Webhooks
11 operations in the Tolvi API, version 1. Paths are relative to https://api.tolvi.co.uk. Every amount is integer pence.
List the webhook event types
GET/api/v1/webhooks/event-types
- Scopes
webhooks:manage- Role
- Firm admin
The event catalogue you can subscribe to.
Responses
200 OK, application/json
Body: array of WebhookEventTypeInfo.
| Field | Type | Description |
|---|---|---|
[].typerequired | string (WebhookEventType) | One of: |
[].descriptionrequired | string |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
List webhook subscriptions
GET/api/v1/webhooks
- Scopes
webhooks:manage- Role
- Firm admin
Responses
200 OK, application/json
Body: array of WebhookSubscription.
| Field | Type | Description |
|---|---|---|
[].idrequired | string (uuid) | |
[].urlrequired | string (uri) | example "https://hooks.example.co.uk/tolvi" |
[].descriptionrequired | stringnullable | |
[].eventTypesrequired | array of WebhookEventType | One of: at least 1 items |
[].statusrequired | string (WebhookSubscriptionStatus) | One of: |
[].disabledReasonrequired | stringnullable | Why it was disabled: by hand, or automatically after repeated failed deliveries. |
[].disabledAtrequired | string (date-time)nullable | |
[].consecutiveFailuresrequired | integer | Failed attempts in a row. Reaching the limit disables the subscription and tells the firm’s admins. at least 0 |
[].secretPrefixrequired | string | First characters of the signing secret. example "whsec_AbC1" |
[].createdByrequired | string (uuid)nullable | |
[].createdAtrequired | string (date-time) | |
[].updatedAtrequired | string (date-time) |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Create a webhook subscription
POST/api/v1/webhooks
- Scopes
webhooks:manage- Role
- Firm admin
Returns the signing secret once. Each delivery is a POST with a JSON body and a Tolvi-Signature: t=<unix seconds>,v1=<hex> header, where v1 is HMAC-SHA256 of <t>.<raw body> keyed with the subscription’s secret. Reject a delivery whose signature does not match or whose t is more than 5 minutes from now, and de-duplicate on Tolvi-Event-Id. Answer 2xx within 10 seconds; anything else is retried with exponential backoff (30 s doubling to 6 h, 12 attempts). After 20 failed attempts in a row the subscription is disabled and the firm’s admins are told.
Request body
Required. application/json: object (CreateWebhookSubscription).
| Field | Type | Description |
|---|---|---|
urlrequired | string (uri) | An https URL on a public host. Private, loopback and link-local addresses are refused. up to 2048 characters |
eventTypesrequired | array of WebhookEventType | One of: at least 1 items |
description | stringnullable | up to 200 characters |
Responses
201 Created, application/json
Body: object (CreatedWebhookSubscription).
The signing secret is shown only once. Use it to verify the Tolvi-Signature header.
| Field | Type | Description |
|---|---|---|
subscriptionrequired | object (WebhookSubscription) | |
subscription.idrequired | string (uuid) | |
subscription.urlrequired | string (uri) | example "https://hooks.example.co.uk/tolvi" |
subscription.descriptionrequired | stringnullable | |
subscription.eventTypesrequired | array of WebhookEventType | One of: at least 1 items |
subscription.statusrequired | string (WebhookSubscriptionStatus) | One of: |
subscription.disabledReasonrequired | stringnullable | Why it was disabled: by hand, or automatically after repeated failed deliveries. |
subscription.disabledAtrequired | string (date-time)nullable | |
subscription.consecutiveFailuresrequired | integer | Failed attempts in a row. Reaching the limit disables the subscription and tells the firm’s admins. at least 0 |
subscription.secretPrefixrequired | string | First characters of the signing secret. example "whsec_AbC1" |
subscription.createdByrequired | string (uuid)nullable | |
subscription.createdAtrequired | string (date-time) | |
subscription.updatedAtrequired | string (date-time) | |
secretrequired | string | example "whsec_…" |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Get a webhook subscription
GET/api/v1/webhooks/{id}
- Scopes
webhooks:manage- Role
- Firm admin
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | Webhook subscription id. |
Responses
200 OK, application/json
Body: object (WebhookSubscription).
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | |
urlrequired | string (uri) | example "https://hooks.example.co.uk/tolvi" |
descriptionrequired | stringnullable | |
eventTypesrequired | array of WebhookEventType | One of: at least 1 items |
statusrequired | string (WebhookSubscriptionStatus) | One of: |
disabledReasonrequired | stringnullable | Why it was disabled: by hand, or automatically after repeated failed deliveries. |
disabledAtrequired | string (date-time)nullable | |
consecutiveFailuresrequired | integer | Failed attempts in a row. Reaching the limit disables the subscription and tells the firm’s admins. at least 0 |
secretPrefixrequired | string | First characters of the signing secret. example "whsec_AbC1" |
createdByrequired | string (uuid)nullable | |
createdAtrequired | string (date-time) | |
updatedAtrequired | string (date-time) |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Update a webhook subscription
PATCH/api/v1/webhooks/{id}
- Scopes
webhooks:manage- Role
- Firm admin
Change the URL, event types or description, or disable it. Setting status to active re-enables a disabled subscription and resets its failure count.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | Webhook subscription id. |
Request body
Required. application/json: object (UpdateWebhookSubscription).
| Field | Type | Description |
|---|---|---|
url | string (uri) | up to 2048 characters |
eventTypes | array of WebhookEventType | One of: at least 1 items |
description | stringnullable | up to 200 characters |
status | string (WebhookSubscriptionStatus) |
One of: |
Responses
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Delete a webhook subscription
DELETE/api/v1/webhooks/{id}
- Scopes
webhooks:manage- Role
- Firm admin
Deletes it with its delivery log. Pending deliveries are not sent.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | Webhook subscription id. |
Responses
204 No content
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Send a test event to an endpoint
POST/api/v1/webhooks/test
- Scopes
webhooks:manage- Role
- Firm admin
Before subscribing: checks the URL as a subscription would (https, public addresses only) and POSTs one ping event to it, then says what came back. The test is signed with a one-off key, so your endpoint can’t verify its signature; it only needs to answer 2xx within 10 seconds. Nothing is stored or retried.
Request body
Required. application/json: object (TestWebhookEndpoint).
| Field | Type | Description |
|---|---|---|
urlrequired | string (uri) | An https URL on a public host, checked exactly as a subscription’s is. up to 2048 characters |
Responses
200 OK, application/json
Body: object (WebhookEndpointTest).
What happened when Tolvi sent a test event (type ping) to an endpoint. Nothing is stored.
| Field | Type | Description |
|---|---|---|
okrequired | boolean | The endpoint answered 2xx within 10 seconds. |
statusrequired | integernullable | The HTTP status it answered with; null when nothing came back. |
errorrequired | stringnullable | Why it failed, in words: a refused address, a timeout, no answer. |
durationMsrequired | integer | How long it took, in milliseconds. |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Rotate the signing secret
POST/api/v1/webhooks/{id}/rotate-secret
- Scopes
webhooks:manage- Role
- Firm admin
Returns the new secret once. The old one stops working at once, including for retries already scheduled.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | Webhook subscription id. |
Responses
200 OK, application/json
Body: object (CreatedWebhookSubscription).
The signing secret is shown only once. Use it to verify the Tolvi-Signature header.
The fields are as shown above.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
List a subscription’s deliveries, newest first
GET/api/v1/webhooks/{id}/deliveries
- Scopes
webhooks:manage- Role
- Firm admin
The delivery log: status, attempts and the last response code.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | Webhook subscription id. |
limit | query | integer | |
cursor | query | string | |
status | query | string (WebhookDeliveryStatus) | One of: |
Responses
200 OK, application/json
Body: object (WebhookDeliveryPage).
| Field | Type | Description |
|---|---|---|
rowsrequired | array of WebhookDelivery | |
rows[].idrequired | string (uuid) | Sent as Tolvi-Delivery-Id. |
rows[].subscriptionIdrequired | string (uuid) | |
rows[].eventIdrequired | string (uuid) | Sent as Tolvi-Event-Id and as |
rows[].eventTyperequired | string (WebhookEventType) | One of: |
rows[].statusrequired | string (WebhookDeliveryStatus) | One of: |
rows[].attemptsrequired | integer | at least 0 |
rows[].nextAttemptAtrequired | string (date-time)nullable | When the next attempt is due (pending deliveries only). |
rows[].lastAttemptAtrequired | string (date-time)nullable | |
rows[].responseStatusrequired | integernullable | |
rows[].errorrequired | stringnullable | |
rows[].replayOfrequired | string (uuid)nullable | The delivery this one replays. |
rows[].createdAtrequired | string (date-time) | |
nextCursorrequired | stringnullable | Opaque cursor for the next page (pass as |
pageSizerequired | integer | The page size that was used. 1 to 100 |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Get a delivery with its payload and every attempt
GET/api/v1/webhooks/{id}/deliveries/{deliveryId}
- Scopes
webhooks:manage- Role
- Firm admin
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | Webhook subscription id. |
deliveryIdrequired | path | string (uuid) | Delivery id. |
Responses
200 OK, application/json
Body: object (WebhookDeliveryDetail).
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | Sent as Tolvi-Delivery-Id. |
subscriptionIdrequired | string (uuid) | |
eventIdrequired | string (uuid) | Sent as Tolvi-Event-Id and as |
eventTyperequired | string (WebhookEventType) | One of: |
statusrequired | string (WebhookDeliveryStatus) | One of: |
attemptsrequired | integer | at least 0 |
nextAttemptAtrequired | string (date-time)nullable | When the next attempt is due (pending deliveries only). |
lastAttemptAtrequired | string (date-time)nullable | |
responseStatusrequired | integernullable | |
errorrequired | stringnullable | |
replayOfrequired | string (uuid)nullable | The delivery this one replays. |
createdAtrequired | string (date-time) | |
payloadrequired | string | The exact JSON body that is signed and sent. |
attemptLogrequired | array of WebhookDeliveryAttempt | |
attemptLog[].attemptrequired | integer | at least 1 |
attemptLog[].atrequired | string (date-time) | |
attemptLog[].responseStatusrequired | integernullable | HTTP status, or null when no response came back. |
attemptLog[].responseBodyrequired | stringnullable | First 1 KB of the response body. |
attemptLog[].errorrequired | stringnullable | Network error, timeout or refused address. |
attemptLog[].durationMsrequired | integer | at least 0 |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Replay a delivery
POST/api/v1/webhooks/{id}/deliveries/{deliveryId}/replay
- Scopes
webhooks:manage- Role
- Firm admin
- Retries
- Send an
Idempotency-Keyto make retries safe.
Queues the same event again as a new delivery, sent within seconds. The event id is unchanged, so receivers that de-duplicate on it ignore a copy they already processed.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | Webhook subscription id. |
deliveryIdrequired | path | string (uuid) | Delivery id. |
Idempotency-Key | header | string | A unique key (1-255 visible characters) to make retries safe. Replayed for 24 hours. 1 to 255 characters |
Responses
202 Accepted, application/json
Body: object (WebhookDelivery).
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | Sent as Tolvi-Delivery-Id. |
subscriptionIdrequired | string (uuid) | |
eventIdrequired | string (uuid) | Sent as Tolvi-Event-Id and as |
eventTyperequired | string (WebhookEventType) | One of: |
statusrequired | string (WebhookDeliveryStatus) | One of: |
attemptsrequired | integer | at least 0 |
nextAttemptAtrequired | string (date-time)nullable | When the next attempt is due (pending deliveries only). |
lastAttemptAtrequired | string (date-time)nullable | |
responseStatusrequired | integernullable | |
errorrequired | stringnullable | |
replayOfrequired | string (uuid)nullable | The delivery this one replays. |
createdAtrequired | string (date-time) |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 409 Conflict, 422 Unprocessable content, 429 Too many requests, as problem details (application/problem+json).