Catch API Reference

All endpoints require a Bearer token unless noted. See Authentication.

See Rate Limits for per-minute limits and panic mode.

Bucket endpoints

POST /v1/catch/buckets

Create a webhook bucket.

ParameterTypeRequiredDescription
target_urlstringYesHTTPS URL to forward webhooks to
providerstringNostripe, github, shopify, or svix
signing_secretstringNoProvider’s webhook signing secret
curl -X POST "https://api.solenoid.systems/v1/catch/buckets" \
  -H "Authorization: Bearer sm_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"target_url": "https://your-app.com/webhooks", "provider": "stripe"}'

201 Created. Returns the new bucket with state: "paused". Bucket IDs use adjective-noun-number format.

Bucket limits by tier: Free (1), Starter (5), Pro (25), Scale (100).

GET /v1/catch/buckets

List all buckets for the authenticated user.

curl "https://api.solenoid.systems/v1/catch/buckets" \
  -H "Authorization: Bearer sm_your_api_key_here"

GET /v1/catch/buckets/:bucket_id

Get a single bucket.

curl "https://api.solenoid.systems/v1/catch/buckets/brave-elephant-42" \
  -H "Authorization: Bearer sm_your_api_key_here"

PATCH /v1/catch/buckets/:bucket_id

Update bucket configuration. All fields optional.

ParameterTypeDescription
statestringlive or paused
target_urlstringNew forwarding URL
signing_secretstringNew signing secret
curl -X PATCH "https://api.solenoid.systems/v1/catch/buckets/brave-elephant-42" \
  -H "Authorization: Bearer sm_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"state": "live"}'

DELETE /v1/catch/buckets/:bucket_id

Delete a bucket and all stored events. Returns 204 No Content.

curl -X DELETE "https://api.solenoid.systems/v1/catch/buckets/brave-elephant-42" \
  -H "Authorization: Bearer sm_your_api_key_here"

Ingestion endpoint

POST /v1/catch/:bucket_id

Auth: None. This endpoint is public so webhook providers can send to it directly.

Accepts any JSON payload. Always returns 200 OK to prevent sender retries.

Provider is auto-detected from signature headers:

ProviderHeader
Stripestripe-signature
GitHubx-hub-signature-256
Shopifyx-shopify-hmac-sha256
Svixsvix-signature, svix-id, svix-timestamp

Response fields:

  • verificationvalid, invalid, or none
  • Invalid signatures are stored but marked invalid
  • Rate-limited requests return 200 with status: "rate_limited"
  • Panic mode (5x limit exceeded) returns 200 with status: "panic_mode" for 10 minutes

Event endpoints

GET /v1/catch/:bucket_id/events

List events in a bucket.

Query paramTypeDescription
limitnumberMax events (default 20, max 100)
cursorstringPagination cursor
providerstringFilter by provider
statusstringpending, delivered, or failed
curl "https://api.solenoid.systems/v1/catch/brave-elephant-42/events?limit=10" \
  -H "Authorization: Bearer sm_your_api_key_here"

Pass cursor from the response to fetch the next page. null means no more results.

GET /v1/catch/:bucket_id/events/:event_id

Get a single event including full payload and headers.

curl "https://api.solenoid.systems/v1/catch/brave-elephant-42/events/01HX1234567890ABCDEF" \
  -H "Authorization: Bearer sm_your_api_key_here"

POST /v1/catch/:bucket_id/events/:event_id/replay

Replay a single event to the bucket’s target_url. Bucket must be in live state.

curl -X POST "https://api.solenoid.systems/v1/catch/brave-elephant-42/events/01HX1234567890ABCDEF/replay" \
  -H "Authorization: Bearer sm_your_api_key_here"

Returns status: "replayed" on success or status: "failed" with the target’s HTTP status code.

DELETE /v1/catch/:bucket_id/events

Bulk delete events.

Query paramTypeDescription
beforestringDelete events before this ISO 8601 timestamp
curl -X DELETE "https://api.solenoid.systems/v1/catch/brave-elephant-42/events?before=2026-02-01T00:00:00Z" \
  -H "Authorization: Bearer sm_your_api_key_here"

Returns {"deleted_count": 42}.

Replay signatures

When Catch replays events to your target_url, it adds these headers:

  • X-Solenoid-Signaturet=<timestamp>,v1=<hmac>
  • X-Solenoid-Event-Id — original event ID
  • X-Solenoid-Timestamp — original event timestamp

Verify with HMAC-SHA256 over {timestamp}.{payload}:

const crypto = require('crypto')

function verifyReplaySignature(payload, signature, secret) {
  const [tPart, v1Part] = signature.split(',')
  const timestamp = tPart.split('=')[1]
  const expected = v1Part.split('=')[1]
  const computed = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${payload}`)
    .digest('hex')
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(computed))
}

Retention and limits

See Pricing for tier details.

TierRetentionMax events per bucket
Free24 hours100
Starter3 days1,000
Pro30 days10,000
Scale90 days100,000

Oldest events are deleted when the per-bucket limit is exceeded.

Metering

OperationCost
Webhook ingestion1 credit
Successful replay1 credit
Failed replayFree
List/get events1 credit
Bucket managementFree

See Pricing for monthly allocations.