OdyhookSign in

API reference

REST API for managing webhook sources, destinations, routes, and events in Odyhook. All endpoints require a bearer token issued from Settings → API Tokens.

Base URL: https://odyhook.dev · Spec: /openapi.json (OpenAPI 3.1.0)

Every request authenticates with a bearer token (ody_…) minted at Settings → API Tokens. This page is generated from the OpenAPI spec, so it always matches the live contract. For /api/v1/events/search and /api/v1/fixtures, see the REST API overview.

Sources

GET /api/v1/sources

List sources

Returns a paginated list of webhook sources belonging to the authenticated user.

ParameterInTypeRequiredDescription
limitqueryintegernoMaximum number of items to return (1–100, default 25).
cursorquerystringnoOpaque pagination cursor. Use the nextCursor value from a previous response.
ResponseDescriptionBody
200Paginated list of sources.
401Missing or invalid API token.Error
429Too many requests.Error
curl -X GET https://odyhook.dev/api/v1/sources \
  -H "Authorization: Bearer ody_…"

POST /api/v1/sources

Create a source

Creates a new webhook source. A unique ingest slug is generated automatically.

Request body: SourceCreate

ResponseDescriptionBody
201Source created.Source
400Request body failed schema validation.Error
401Missing or invalid API token.Error
429Too many requests.Error
curl -X POST https://odyhook.dev/api/v1/sources \
  -H "Authorization: Bearer ody_…" \
  -H "Content-Type: application/json" \
  -d '{ … }'  # SourceCreate

GET /api/v1/sources/{id}

Get a source

Retrieves a single source by ID.

ParameterInTypeRequiredDescription
idpathstringyesResource identifier.
ResponseDescriptionBody
200Source found.Source
401Missing or invalid API token.Error
404Resource not found or does not belong to the authenticated user.Error
429Too many requests.Error
curl -X GET https://odyhook.dev/api/v1/sources/{id} \
  -H "Authorization: Bearer ody_…"

PATCH /api/v1/sources/{id}

Update a source

Partially updates a source. Only supplied fields are changed.

ParameterInTypeRequiredDescription
idpathstringyesResource identifier.

Request body: SourceUpdate

ResponseDescriptionBody
200Source updated.Source
400Request body failed schema validation.Error
401Missing or invalid API token.Error
404Resource not found or does not belong to the authenticated user.Error
429Too many requests.Error
curl -X PATCH https://odyhook.dev/api/v1/sources/{id} \
  -H "Authorization: Bearer ody_…" \
  -H "Content-Type: application/json" \
  -d '{ … }'  # SourceUpdate

DELETE /api/v1/sources/{id}

Delete a source

Permanently deletes a source. Associated routes and their event history are also removed.

ParameterInTypeRequiredDescription
idpathstringyesResource identifier.
ResponseDescriptionBody
204Resource deleted successfully. No response body.
401Missing or invalid API token.Error
404Resource not found or does not belong to the authenticated user.Error
429Too many requests.Error
curl -X DELETE https://odyhook.dev/api/v1/sources/{id} \
  -H "Authorization: Bearer ody_…"

Destinations

GET /api/v1/destinations

List destinations

Returns a paginated list of webhook destinations belonging to the authenticated user.

ParameterInTypeRequiredDescription
limitqueryintegernoMaximum number of items to return (1–100, default 25).
cursorquerystringnoOpaque pagination cursor. Use the nextCursor value from a previous response.
ResponseDescriptionBody
200Paginated list of destinations.
401Missing or invalid API token.Error
429Too many requests.Error
curl -X GET https://odyhook.dev/api/v1/destinations \
  -H "Authorization: Bearer ody_…"

POST /api/v1/destinations

Create a destination

Creates a new webhook destination. The URL is checked against SSRF protection rules; private/internal IP ranges are rejected.

Request body: DestinationCreate

ResponseDescriptionBody
201Destination created.Destination
400Request body failed schema validation.Error
401Missing or invalid API token.Error
429Too many requests.Error
curl -X POST https://odyhook.dev/api/v1/destinations \
  -H "Authorization: Bearer ody_…" \
  -H "Content-Type: application/json" \
  -d '{ … }'  # DestinationCreate

GET /api/v1/destinations/{id}

Get a destination

Retrieves a single destination by ID.

ParameterInTypeRequiredDescription
idpathstringyesResource identifier.
ResponseDescriptionBody
200Destination found.Destination
401Missing or invalid API token.Error
404Resource not found or does not belong to the authenticated user.Error
429Too many requests.Error
curl -X GET https://odyhook.dev/api/v1/destinations/{id} \
  -H "Authorization: Bearer ody_…"

PATCH /api/v1/destinations/{id}

Update a destination

Partially updates a destination. Only supplied fields are changed. Setting enabled to true also clears the consecutive failure counter.

ParameterInTypeRequiredDescription
idpathstringyesResource identifier.

Request body: DestinationUpdate

ResponseDescriptionBody
200Destination updated.Destination
400Request body failed schema validation.Error
401Missing or invalid API token.Error
404Resource not found or does not belong to the authenticated user.Error
429Too many requests.Error
curl -X PATCH https://odyhook.dev/api/v1/destinations/{id} \
  -H "Authorization: Bearer ody_…" \
  -H "Content-Type: application/json" \
  -d '{ … }'  # DestinationUpdate

DELETE /api/v1/destinations/{id}

Delete a destination

Permanently deletes a destination.

ParameterInTypeRequiredDescription
idpathstringyesResource identifier.
ResponseDescriptionBody
204Resource deleted successfully. No response body.
401Missing or invalid API token.Error
404Resource not found or does not belong to the authenticated user.Error
429Too many requests.Error
curl -X DELETE https://odyhook.dev/api/v1/destinations/{id} \
  -H "Authorization: Bearer ody_…"

Routes

GET /api/v1/routes

List routes

Returns a paginated list of routes belonging to the authenticated user.

ParameterInTypeRequiredDescription
limitqueryintegernoMaximum number of items to return (1–100, default 25).
cursorquerystringnoOpaque pagination cursor. Use the nextCursor value from a previous response.
ResponseDescriptionBody
200Paginated list of routes.
401Missing or invalid API token.Error
429Too many requests.Error
curl -X GET https://odyhook.dev/api/v1/routes \
  -H "Authorization: Bearer ody_…"

POST /api/v1/routes

Create a route

Creates a route linking a source to a destination. Both resources must belong to the authenticated user. Returns 409 if a route between this source and destination already exists.

Request body: RouteCreate

ResponseDescriptionBody
201Route created.Route
400Request body failed schema validation.Error
401Missing or invalid API token.Error
404Resource not found or does not belong to the authenticated user.Error
409A duplicate resource already exists.Error
429Too many requests.Error
curl -X POST https://odyhook.dev/api/v1/routes \
  -H "Authorization: Bearer ody_…" \
  -H "Content-Type: application/json" \
  -d '{ … }'  # RouteCreate

GET /api/v1/routes/{id}

Get a route

Retrieves a single route by ID.

ParameterInTypeRequiredDescription
idpathstringyesResource identifier.
ResponseDescriptionBody
200Route found.Route
401Missing or invalid API token.Error
404Resource not found or does not belong to the authenticated user.Error
429Too many requests.Error
curl -X GET https://odyhook.dev/api/v1/routes/{id} \
  -H "Authorization: Bearer ody_…"

PATCH /api/v1/routes/{id}

Update a route

Partially updates a route. Currently only the enabled flag can be toggled.

ParameterInTypeRequiredDescription
idpathstringyesResource identifier.

Request body: RouteUpdate

ResponseDescriptionBody
200Route updated.Route
400Request body failed schema validation.Error
401Missing or invalid API token.Error
404Resource not found or does not belong to the authenticated user.Error
429Too many requests.Error
curl -X PATCH https://odyhook.dev/api/v1/routes/{id} \
  -H "Authorization: Bearer ody_…" \
  -H "Content-Type: application/json" \
  -d '{ … }'  # RouteUpdate

DELETE /api/v1/routes/{id}

Delete a route

Permanently deletes a route.

ParameterInTypeRequiredDescription
idpathstringyesResource identifier.
ResponseDescriptionBody
204Resource deleted successfully. No response body.
401Missing or invalid API token.Error
404Resource not found or does not belong to the authenticated user.Error
429Too many requests.Error
curl -X DELETE https://odyhook.dev/api/v1/routes/{id} \
  -H "Authorization: Bearer ody_…"

Events

GET /api/v1/events

List events

Returns a paginated list of webhook events received by all sources belonging to the authenticated user, ordered newest first.

ParameterInTypeRequiredDescription
limitqueryintegernoMaximum number of items to return (1–100, default 25).
cursorquerystringnoOpaque pagination cursor. Use the nextCursor value from a previous response.
ResponseDescriptionBody
200Paginated list of events.
401Missing or invalid API token.Error
429Too many requests.Error
curl -X GET https://odyhook.dev/api/v1/events \
  -H "Authorization: Bearer ody_…"

GET /api/v1/events/{id}

Get an event

Retrieves a single event including its raw body and all delivery records.

ParameterInTypeRequiredDescription
idpathstringyesResource identifier.
ResponseDescriptionBody
200Event found.EventDetail
401Missing or invalid API token.Error
404Resource not found or does not belong to the authenticated user.Error
429Too many requests.Error
curl -X GET https://odyhook.dev/api/v1/events/{id} \
  -H "Authorization: Bearer ody_…"

Schemas

Error

FieldTypeRequiredDescription
errorobjectyes

Source

A webhook source — an ingest endpoint Odyhook listens on.

FieldTypeRequiredDescription
id (read-only)stringyesUnique identifier (CUID).
namestringyesDisplay name for the source.
slug (read-only)stringyesURL slug used in the ingest endpoint path.
verifyStyle"stripe" | "github" | "generic-sha256" | nullyesHMAC verification style. null means no signature verification.
hasSigningSecret (read-only)booleanyesWhether a signing secret is configured. The secret itself is never returned.
rateLimitPerSecinteger | nullyesPer-second rate limit override. null means the global default applies.
rateLimitBurstinteger | nullyesBurst allowance override. null means the global default applies.
retentionDaysinteger | nullyesDays events are retained before the daily purge deletes them. null means keep indefinitely.
createdAt (read-only)string (date-time)yesISO 8601 creation timestamp.

SourceCreate

FieldTypeRequiredDescription
namestringyesDisplay name for the source.
verifyStyle"none" | "stripe" | "github" | "generic-sha256"noHMAC verification style. Defaults to none (no verification).
signingSecretstringnoSigning secret for HMAC verification. Required when verifyStyle is not none. Never returned in responses.
retentionDaysinteger | nullnoDays events are retained before purge. Defaults to 90; set to null to keep indefinitely.

SourceUpdate

FieldTypeRequiredDescription
namestringnoUpdated display name.
verifyStyle"none" | "stripe" | "github" | "generic-sha256"noUpdated HMAC verification style.
signingSecretstringnoNew signing secret. Required when changing verifyStyle to a non-none value and no secret is already stored. Never returned in responses.
rateLimitPerSecinteger | nullnoPer-second rate limit override. Set to null to revert to the global default.
rateLimitBurstinteger | nullnoBurst allowance override. Set to null to revert to the global default.
retentionDaysinteger | nullnoDays events are retained before purge. Set to null to keep indefinitely.

Destination

A downstream URL that Odyhook delivers webhook payloads to.

FieldTypeRequiredDescription
id (read-only)stringyesUnique identifier (CUID).
namestringyesDisplay name for the destination.
urlstring (uri)yesHTTPS URL Odyhook POSTs to.
timeoutMsintegeryesRequest timeout in milliseconds.
enabledbooleanyesWhether this destination is active. Odyhook auto-disables after consecutive failures.
hasHeaders (read-only)booleanyesWhether custom outbound headers are configured. Header values are never returned.
hasOutboundSecret (read-only)booleanyesWhether an outbound signing secret is configured. The secret itself is never returned.
consecutiveFailures (read-only)integeryesNumber of consecutive delivery failures. Reset to 0 when the destination is re-enabled.
autoDisabledAt (read-only)string | null (date-time)yesISO 8601 timestamp when the destination was auto-disabled due to repeated failures, or null.
createdAt (read-only)string (date-time)yesISO 8601 creation timestamp.

DestinationCreate

FieldTypeRequiredDescription
namestringyesDisplay name for the destination.
urlstring (uri)yesHTTPS URL to deliver webhooks to. Private/internal IP ranges are rejected (SSRF protection).
timeoutMsintegernoRequest timeout in milliseconds.
headersstringnoCustom outbound HTTP headers, one per line in 'Name: Value' format. Never returned in responses.
outboundSecretstringnoSecret used to sign outbound payloads (HMAC-SHA256 in X-Odyhook-Signature header). Never returned in responses.

DestinationUpdate

FieldTypeRequiredDescription
namestringnoUpdated display name.
urlstring (uri)noUpdated delivery URL. Private/internal IP ranges are rejected.
timeoutMsintegernoUpdated timeout in milliseconds.
headersstringnoReplacement custom outbound headers ('Name: Value' per line). Pass an empty string to clear. Never returned in responses.
outboundSecretstringnoReplacement outbound signing secret. Pass an empty string to clear. Never returned in responses.
enabledbooleannoRe-enable or disable the destination. Setting to true also resets consecutiveFailures to 0.

Route

A link between a source and a destination — determines which sources fan out to which destinations.

FieldTypeRequiredDescription
id (read-only)stringyesUnique identifier (CUID).
sourceIdstringyesID of the source this route belongs to.
destinationIdstringyesID of the destination this route delivers to.
enabledbooleanyesWhether events on this route are delivered.
hasFilter (read-only)booleanyesWhether a filter expression is configured for this route.
createdAt (read-only)string (date-time)yesISO 8601 creation timestamp.

RouteCreate

FieldTypeRequiredDescription
sourceIdstringyesID of the source to route from. Must belong to the authenticated user.
destinationIdstringyesID of the destination to route to. Must belong to the authenticated user.
enabledbooleannoWhether to enable delivery immediately.

RouteUpdate

FieldTypeRequiredDescription
enabledbooleannoEnable or disable delivery on this route.

Event

A webhook event received by an ingest endpoint.

FieldTypeRequiredDescription
id (read-only)stringyesUnique identifier (CUID).
sourceId (read-only)stringyesID of the source that received this event.
method (read-only)stringyesHTTP method of the inbound request (e.g. POST).
receivedAt (read-only)string (date-time)yesISO 8601 timestamp when the event was received.
remoteIp (read-only)string | nullyesIP address of the sender, or null if unavailable.
idempotencyKey (read-only)string | nullyesIdempotency key from the inbound request, or null.

Delivery

A single delivery attempt record for one route on one event.

FieldTypeRequiredDescription
id (read-only)stringyesUnique identifier (CUID).
destinationId (read-only)stringyesID of the destination this delivery targets.
status (read-only)stringyesDelivery status (e.g. pending, success, failed, exhausted).
attemptCount (read-only)integeryesNumber of delivery attempts made so far.
responseCode (read-only)integer | nullyesHTTP status code returned by the destination on the last attempt, or null.
lastError (read-only)string | nullyesError message from the last failed attempt, or null.
deliveredAt (read-only)string | null (date-time)yesISO 8601 timestamp of successful delivery, or null.
createdAt (read-only)string (date-time)yesISO 8601 timestamp when this delivery record was created.

EventDetail

FieldTypeRequiredDescription