Navigation

API Reference

CatchHook provides a REST API for programmatic access to endpoints, ingress events, and tunnel connections.

Base URL: https://catchhook.app/api/v1

Authentication

All API requests require a Bearer token in the Authorization header:

Authorization: Bearer <your-api-token>

Create API tokens in Account Settings. Tokens have two dimensions of access control:

Token level

Level Access Created from
Account All workspaces and resources in the account Account Settings
Workspace Only the specific workspace's resources Workspace management page

CLI tokens (created during catchhook login) are always account-scoped.

Permission scopes

Scope Access
read List and view endpoints, events, forwarding targets, and activity
write Create, update, delete resources; replay events
tunnel Connect to tunnel WebSocket and report deliveries

Endpoints

Verify authentication

GET /api/v1/auth/verify

Returns the current user and account information. Useful for verifying your token is valid.

Response:

{
  "user": { "id": 1, "email": "you@example.com" },
  "account": { "id": 1, "name": "Acme Corp" }
}

List endpoints

GET /api/v1/endpoints

Returns all endpoints accessible to the authenticated user, including both webhook and email endpoints.

Response:

{
  "data": [
    {
      "id": "ep_abc123",
      "name": "GitHub Webhooks",
      "kind": "webhook",
      "custom_id": null,
      "provider": "github",
      "provider_config": {},
      "webhook_url": "https://listen.catchhook.app/hooks/ep_abc123",
      "email_address": null,
      "tunnel_active": false,
      "created_at": "2026-05-01T12:00:00Z",
      "updated_at": "2026-05-01T12:00:00Z"
    },
    {
      "id": "ep_def456",
      "name": "Transactional Emails",
      "kind": "email",
      "custom_id": null,
      "provider": null,
      "provider_config": {},
      "webhook_url": null,
      "email_address": "billing@in.catchhook.app",
      "tunnel_active": false,
      "created_at": "2026-05-01T12:00:00Z",
      "updated_at": "2026-05-01T12:00:00Z"
    }
  ]
}

Create an endpoint

POST /api/v1/endpoints

Body (webhook endpoint):

{
  "endpoint": {
    "name": "My Endpoint",
    "kind": "webhook",
    "provider": "github"
  }
}

Body (email endpoint):

{
  "endpoint": {
    "name": "Transactional Emails",
    "kind": "email",
    "email_local_part": "billing"
  }
}
Parameter Description
name Human-readable label (required)
kind Endpoint type: webhook (default) or email
provider Webhook only. One of github, stripe, shopify, or twilio. Stores the intended webhook source for this endpoint. Only CLI preset providers (github, stripe) enable the CLI --provider signature config workflow on free plans; shopify and twilio are detection-only.
email_local_part Email only. The local part of the generated email address (before the @). Must be lowercase alphanumeric with dots, hyphens, or underscores (2–50 characters). If omitted, a random local part is generated.

Provider detection of incoming webhooks happens automatically at ingest for all webhook endpoints, regardless of whether provider is set. Setting provider stores your intended webhook source. For CLI preset providers (github, stripe), it also enables the --provider workflow for automatic signature config creation.

For email endpoints, provider is not applicable — email provider detection happens automatically based on email headers.

Get an endpoint

GET /api/v1/endpoints/:id

Returns details for a single endpoint. The response includes kind, webhook_url (webhook endpoints), and email_address (email endpoints).

List events for an endpoint

GET /api/v1/endpoints/:endpoint_id/requests

Returns ingress events (both webhook requests and email events) received by the specified endpoint. Events are returned in reverse chronological order.

Query parameters:

Parameter Description Default
limit Number of events (1–100) 25
offset Number of events to skip 0

Response:

{
  "data": [
    {
      "id": "req_abc123",
      "type": "webhook",
      "method": "POST",
      "path": "/hooks/checkout",
      "status": 200,
      "content_type": "application/json",
      "ip_address": "1.2.3.4",
      "size": 1024,
      "requested_at": "2026-05-01T12:00:00Z",
      "detected_provider": "stripe",
      "provider_event_data": { "event_type": "invoice.paid" }
    },
    {
      "id": "eml_def456",
      "type": "email",
      "method": "EMAIL",
      "path": "billing@in.catchhook.app",
      "status": null,
      "content_type": null,
      "ip_address": null,
      "size": 4096,
      "requested_at": "2026-05-01T11:30:00Z",
      "from": "sender@example.com",
      "to": "billing@in.catchhook.app",
      "subject": "Order Confirmation",
      "detected_provider": "sendgrid",
      "authentication": { "spf": "PASS", "dkim": "PASS", "dmarc": "PASS" }
    }
  ],
  "meta": {
    "total": 42,
    "limit": 25,
    "offset": 0
  }
}

Get a single event

GET /api/v1/endpoints/:endpoint_id/requests/:id

Returns full details for a single event, including the complete body. For email events, the full response includes text_body, html_body, email_headers, attachment_metadata, and authentication_results.

Delete an event

DELETE /api/v1/endpoints/:endpoint_id/requests/:id

Scope required: write

Permanently deletes a single ingress event.

Delete events in bulk

DELETE /api/v1/endpoints/:endpoint_id/requests/destroy_all

Scope required: write

Deletes all events for the endpoint. Optional query parameters:

Parameter Description
before Delete events received before this ISO 8601 timestamp
after Delete events received after this ISO 8601 timestamp

Replay an event

POST /api/v1/endpoints/:endpoint_id/requests/:id/replay

Scope required: write

Re-sends an event to a target URL.

For webhook events, the API currently supports exact replay only — the original method, headers, and body are forwarded as-is with optional identity and signature handling. Request modification parameters (body editing, header/query overrides) are available in the web UI and will be added to the API in a future release.

For email events, the replay sends the normalized JSON payload as a POST request to the target URL.

Body:

{
  "target_url": "https://your-app.com/webhooks",
  "identity_mode": "original",
  "signature_mode": "strip"
}
Parameter Options Default Description
target_url Any valid URL (required) Destination for the replayed event
identity_mode original, regenerate original regenerate appends unique suffixes to ID fields (JSON bodies only, requires payment method). Webhook events only.
signature_mode strip, resign strip resign computes a fresh signature using the endpoint's signing secret (requires payment method and a supported signature config). Webhook events only.

CatchHook adds replay metadata headers to every outbound request: X-Catchhook-Replay, X-Catchhook-Original-Request, and X-Catchhook-Replay-Time.

Delete an endpoint

DELETE /api/v1/endpoints/:id

Scope required: write

Permanently deletes an endpoint and all its events.

Signature Configs

Create a signature config

POST /api/v1/endpoints/:endpoint_id/signature_configs

Scope required: write

Creates a signature verification config for a webhook endpoint. On Pro/Business plans, any provider is allowed. On free plans, this is restricted to provider-mode endpoints where the sig config provider matches the endpoint's provider.

Not applicable to email endpoints — email authentication (SPF, DKIM, DMARC) is handled at the transport level by AWS SES.

Body:

{
  "signature_config": {
    "provider": "github",
    "secret": "whsec_your_secret_here",
    "enabled": true
  }
}
Parameter Description
provider github, stripe, shopify, twilio, or generic_hmac
secret The webhook signing secret
enabled Whether verification is active (default true)

Conflict handling: If a config for the same provider already exists, the API returns 409 Conflict. Pass ?force=true to overwrite the existing config.

Response (201):

{
  "data": {
    "id": 1,
    "provider": "github",
    "enabled": true
  }
}

Forwarding Targets

List forwarding targets

GET /api/v1/endpoints/:endpoint_id/forwarding_targets

Returns all forwarding targets for the specified endpoint. Works for both webhook and email endpoints.

Get a forwarding target

GET /api/v1/endpoints/:endpoint_id/forwarding_targets/:id

Create a forwarding target

POST /api/v1/endpoints/:endpoint_id/forwarding_targets

Scope required: write

Body:

{
  "forwarding_target": {
    "name": "Production API",
    "url": "https://api.example.com/webhooks",
    "enabled": true,
    "timeout_seconds": 30,
    "retry_count": 3
  }
}

For email endpoints, forwarding delivers a normalized JSON POST containing the email's from, to, subject, text/HTML bodies, headers, attachments metadata, and authentication results.

Update a forwarding target

PATCH /api/v1/endpoints/:endpoint_id/forwarding_targets/:id

Scope required: write

Delete a forwarding target

DELETE /api/v1/endpoints/:endpoint_id/forwarding_targets/:id

Scope required: write

Events

List recent events

GET /api/v1/events

Scope required: read

Returns recent activity events for the account, including both webhook and email ingress. Useful for building integrations that react to CatchHook activity.

Query parameters:

Parameter Description Default
limit Number of events (1–200) 50
since ISO 8601 timestamp 24 hours ago

Event types:

Type Description
webhook.received A webhook was received at a webhook endpoint
email.received An email was received at an email endpoint
forwarding.failed A forwarding attempt failed
alert.triggered An alert condition was detected

Response:

{
  "data": [
    {
      "type": "webhook.received",
      "occurred_at": "2026-05-01T12:00:00Z",
      "endpoint_id": "ep_abc123",
      "request_id": "req_def456",
      "data": {
        "method": "POST",
        "path": "/hooks/stripe",
        "content_type": "application/json",
        "size": 1024
      }
    },
    {
      "type": "email.received",
      "occurred_at": "2026-05-01T11:30:00Z",
      "endpoint_id": "ep_ghi789",
      "request_id": "eml_jkl012",
      "data": {
        "from": "sender@example.com",
        "to": "billing@in.catchhook.app",
        "subject": "Order Confirmation",
        "size": 4096
      }
    }
  ],
  "meta": { "count": 2 }
}

Tunnel

Connect (authenticated)

POST /api/v1/tunnel/connect

Scope required: tunnel

Body:

{
  "endpoint_id": "ep_abc123"
}

Works for both webhook and email endpoints. Exchanges your API token for a one-time WebSocket ticket (valid for 30 seconds).

Response:

{
  "ticket": "a1b2c3...",
  "expires_in": 30
}

Connect (anonymous / temporary endpoint)

POST /api/v1/tunnel/connect_anonymous

No authentication required. Uses the endpoint's tunnel_key instead.

Body:

{
  "tunnel_key": "tk_xyz789"
}

Response:

{
  "ticket": "a1b2c3...",
  "expires_in": 30,
  "endpoint_id": "ep_abc123"
}

Report delivery

POST /api/v1/tunnel/delivery_reports

Scope required: tunnel

Reports the result of a local tunnel delivery back to CatchHook. Used by the CLI to power tunnel health metrics and alerts.

Body:

{
  "endpoint_id": "ep_abc123",
  "webhook_request_id": "req_def456",
  "target_url": "http://localhost:3000/webhooks",
  "status_code": 200,
  "response_message": "OK",
  "response_time_ms": 42
}

The webhook_request_id field accepts both webhook (req_*) and email (eml_*) event IDs.

Rate limits

API endpoints are rate-limited to prevent abuse:

Endpoint Limit
Tunnel connect (authenticated) 30 requests / 60 seconds
Tunnel connect (anonymous) 10 requests / 60 seconds

When rate-limited, the API returns 429 Too Many Requests with a retry_after field.

Error responses

All errors follow a consistent format:

{
  "error": "not_found"
}

Common status codes:

Code Meaning
401 Invalid or missing API token
403 Token doesn't have the required scope
404 Resource not found
422 Validation error
429 Rate limited