Skip to the documentation

Webhook deliveries

The signed callbacks your runs asked for: where each stands, and sending one again.

List callbacks

GET/api/v1/webhook-deliveries

The signed callbacks your runs asked for, newest first: where each stands, how many attempts it took, and what your server answered last. Narrow to one run with ?executionId= or one match with ?matchId=.

A callback is written when a run that named a callbackUrl ends, and sent within about a minute. See Get told when a match finishes.

An API key carrying the scope named here, or a signed-in session.

Scope
search:read
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Parameters

NameInTypeRequiredDescription
executionIdQuerystring (uuid)OptionalOnly the callback for this run.
matchIdQuerystring (uuid)OptionalOnly the callback for this match.
limitQueryintegerOptionalHow many to return: 1 to 50, 20 when absent. A number outside that range is clamped; text is ignored.
cursorQuerystringOptionalWhere the last page ended: the cursor inside the previous page's links.next. Pass links as given; a cursor you edit is refused.

Examples

curl "https://liviamatch.com/api/v1/webhook-deliveries?executionId=0d9e7c1a-52b8-4f3a-8e6d-1c7a9b2f4e83&matchId=1e8b4c27-5a93-4d60-b2f7-9c0d3a6e8f15" \
  -H "Authorization: Bearer $LIVIA_API_KEY"

Responses

200

One page of callbacks.

One delivered, one retrying
{
  "data": [
    {
      "id": "8a3f5d12-6b74-4c90-9e2a-0f8d1c6b3e57",
      "type": "match.completed",
      "status": "pending",
      "url": "https://hooks.example.com/livia",
      "attempts": 2,
      "lastAttempt": {
        "at": "2026-10-12T15:05:41.402Z",
        "statusCode": 503,
        "error": "http-503"
      },
      "nextAttemptAt": "2026-10-12T15:10:41.402Z",
      "deliveredAt": null,
      "occurredAt": "2026-10-12T15:04:05.000Z",
      "createdAt": "2026-10-12T15:04:05.000Z",
      "executionId": "0d9e7c1a-52b8-4f3a-8e6d-1c7a9b2f4e83",
      "matchId": "1e8b4c27-5a93-4d60-b2f7-9c0d3a6e8f15",
      "mode": "live"
    },
    {
      "id": "8a3f5d12-6b74-4c90-9e2a-0f8d1c6b3e57",
      "type": "match.completed",
      "status": "delivered",
      "url": "https://hooks.example.com/livia",
      "attempts": 1,
      "lastAttempt": {
        "at": "2026-10-12T15:04:41.118Z",
        "statusCode": 204,
        "error": null
      },
      "nextAttemptAt": null,
      "deliveredAt": "2026-10-12T15:04:41.118Z",
      "occurredAt": "2026-10-12T15:04:05.000Z",
      "createdAt": "2026-10-12T15:04:05.000Z",
      "executionId": "0d9e7c1a-52b8-4f3a-8e6d-1c7a9b2f4e83",
      "matchId": "1e8b4c27-5a93-4d60-b2f7-9c0d3a6e8f15",
      "mode": "live"
    }
  ],
  "links": {
    "next": null
  }
}
Fields (19)
FieldTypeDescription
dataobject[]
data[].idstring (uuid)The delivery's id: the webhook-id header and the callback body's id, the same on every retry and redelivery.
data[].type"run.completed" | "run.failed" | "run.canceled" | "match.completed" | "match.failed" | "match.canceled"The event it announces.
data[].status"pending" | "sending" | "delivered" | "stopped" | "dead"pending (due at nextAttemptAt), sending, delivered, stopped (410, or the key can no longer sign) or dead (every attempt failed).
data[].urlstringWhere it is sent: the callbackUrl the run named.
data[].attemptsintegerAttempts made since it was written or last redelivered.at least 0
data[].lastAttemptobject | nullThe latest attempt; null before the first.
data[].lastAttempt.atstring (date-time)
data[].lastAttempt.statusCodeinteger | nullWhat the receiver answered; null when it never answered.
data[].lastAttempt.errorstring | nullWhy it did not deliver, as a code: http-500, timeout, refused-address, dns-failed, connect-failed, tls-failed, key-not-live, no-signing-secret. Null when it delivered.
data[].nextAttemptAtstring (date-time) | nullWhen the next attempt is due; null unless pending.
data[].deliveredAtstring (date-time) | null
data[].occurredAtstring (date-time)When the run or match ended.
data[].createdAtstring (date-time)
data[].executionIdstring (uuid) | nullThe run it is about; null for a data set match, which has none.
data[].matchIdstring (uuid) | nullThe match it is about; null for a headless run.
data[].mode"live" | "mock" | nulllive when the last attempt was sent, mock when a stand-in answered it on a non-production tier; null before any attempt.
linksobject
links.nextstring | nullThe URL of the next page, or null when this is the last. Follow it as given.

Errors

StatusCodeWhen
400invalidexecutionId or matchId is not a UUID.
400invalid-cursorThe cursor is not one a page linked to.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal

Send a callback again

POST/api/v1/webhook-deliveries/{deliveryId}/redeliver

Sends a delivered, stopped or dead callback again, under the same webhook-id and the same body, with a fresh retry ladder. The next sweep sends it, within about a minute. Dedupe on webhook-id and a redelivery of something you already handled is a no-op on your side.

An API key carrying the scope named here, or a signed-in session.

Scope
search:run
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Parameters

NameInTypeRequiredDescription
deliveryIdPathstring (uuid)RequiredThe delivery's id: the webhook-id its callback carried.

Examples

curl -X POST "https://liviamatch.com/api/v1/webhook-deliveries/8a3f5d12-6b74-4c90-9e2a-0f8d1c6b3e57/redeliver" \
  -H "Authorization: Bearer $LIVIA_API_KEY"

Responses

202

The callback is pending again.

Pending again
{
  "data": {
    "id": "8a3f5d12-6b74-4c90-9e2a-0f8d1c6b3e57",
    "type": "match.completed",
    "status": "pending",
    "url": "https://hooks.example.com/livia",
    "attempts": 0,
    "lastAttempt": {
      "at": "2026-10-12T15:04:41.118Z",
      "statusCode": 204,
      "error": null
    },
    "nextAttemptAt": "2026-10-12T16:00:00.000Z",
    "deliveredAt": "2026-10-12T15:04:41.118Z",
    "occurredAt": "2026-10-12T15:04:05.000Z",
    "createdAt": "2026-10-12T15:04:05.000Z",
    "executionId": "0d9e7c1a-52b8-4f3a-8e6d-1c7a9b2f4e83",
    "matchId": "1e8b4c27-5a93-4d60-b2f7-9c0d3a6e8f15",
    "mode": "live"
  }
}
Fields (17)
FieldTypeDescription
dataobject
data.idstring (uuid)The delivery's id: the webhook-id header and the callback body's id, the same on every retry and redelivery.
data.type"run.completed" | "run.failed" | "run.canceled" | "match.completed" | "match.failed" | "match.canceled"The event it announces.
data.status"pending" | "sending" | "delivered" | "stopped" | "dead"pending (due at nextAttemptAt), sending, delivered, stopped (410, or the key can no longer sign) or dead (every attempt failed).
data.urlstringWhere it is sent: the callbackUrl the run named.
data.attemptsintegerAttempts made since it was written or last redelivered.at least 0
data.lastAttemptobject | nullThe latest attempt; null before the first.
data.lastAttempt.atstring (date-time)
data.lastAttempt.statusCodeinteger | nullWhat the receiver answered; null when it never answered.
data.lastAttempt.errorstring | nullWhy it did not deliver, as a code: http-500, timeout, refused-address, dns-failed, connect-failed, tls-failed, key-not-live, no-signing-secret. Null when it delivered.
data.nextAttemptAtstring (date-time) | nullWhen the next attempt is due; null unless pending.
data.deliveredAtstring (date-time) | null
data.occurredAtstring (date-time)When the run or match ended.
data.createdAtstring (date-time)
data.executionIdstring (uuid) | nullThe run it is about; null for a data set match, which has none.
data.matchIdstring (uuid) | nullThe match it is about; null for a headless run.
data.mode"live" | "mock" | nulllive when the last attempt was sent, mock when a stand-in answered it on a non-production tier; null before any attempt.

Errors

StatusCodeWhen
404not-foundNo such callback in your workspace.
409delivery-in-flightThe callback is still pending or sending.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal