Skip to main content

Overview

Webhooks let you receive real-time notifications when asset processing finishes. Instead of polling the submission status endpoint, your system is notified via HTTPS POST as soon as an event occurs.

How webhooks work

1

Create a subscription

Register an HTTPS endpoint URL and the event types you want to receive. The API returns a signing secret.
2

Receive deliveries

When an asset finishes processing, the API sends a signed POST to your endpoint.
3

Verify and acknowledge

Verify the signature, respond quickly with a 2xx, and process asynchronously.
4

Fetch detail

The payload does not embed results. Fetch the asset detail, issues, or topics from the REST API.

Event types

Only two event types exist.

Creating a webhook subscription

POST /api/webhooks/subscriptions The request uses endpointUrl (HTTPS required), eventTypes, and an optional description.
Response 201 Created. The secret is returned only on create:
Save the secret immediately — it is never returned again after create. You use it to verify webhook signatures.
A 422 is returned for a non-HTTPS URL or when the workspace reaches its subscription limit.

Webhook delivery payload

When an event occurs, the API sends a Standard Webhooks envelope to your endpoint. The outer fields are id, type, timestamp, and data. The data object is snake_case.
data.external_reference echoes verbatim the structured reference you supplied when creating the submission. It is present only when the submission was created with an externalReference (otherwise the key is omitted), and lets an integration correlate the completion back to the originating work item without keeping its own mapping. The same optional field appears on asset.processing.failed deliveries. A failure delivery uses the same envelope with data.status set to "failed", an added data.error_message, and data.is_retryable (whether the asset can be retried):
The payload does not embed results. To get issues, topics, or full asset detail, fetch them from the REST API: GET /api/submissions/{submission_id}/assets/{asset_id}, its /issues, or its /topics. See Assets.

Verifying webhook signatures

Deliveries are signed using the Standard Webhooks format. Always verify the signature using your subscription secret. After verification, read the event type from event["type"].

Handling webhooks

Your endpoint should:
  1. Verify the signature (see above).
  2. Respond quickly — return a 2xx immediately, then process in the background.
  3. Process idempotently — handle the same event id being delivered more than once.
  4. Fetch detail — load issues or topics from the REST API as needed.

Delivery and retries

Webhook delivery is handled by a delivery provider. If your endpoint returns a non-2xx status, the delivery is retried automatically. Review attempt history through the deliveries endpoint or in the control plane rather than relying on a fixed retry schedule. GET /api/webhooks/subscriptions/{subscription_id}/deliveries Query parameters: status (optional filter) and limit (1–200, default 50).

Testing webhooks

Using ngrok

For local testing, expose your local server publicly:
This gives you a public HTTPS URL like https://abc123.ngrok.io. Create a subscription pointing to it.

Managing subscriptions

List subscriptions

GET /api/webhooks/subscriptions Returns a paginated envelope. The secret is never included after create.
Query parameters: page (≥1), pageSize (1–100), sortBy (endpoint_url | created_at | updated_at), sortOrder (asc | desc), enabled (bool), and search.

Get a subscription

GET /api/webhooks/subscriptions/{subscription_id} Returns a single subscription (without secret).

Update a subscription

PATCH /api/webhooks/subscriptions/{subscription_id} Only enabling or disabling is supported:

Delete a subscription

DELETE /api/webhooks/subscriptions/{subscription_id} Returns 204 No Content.

Webhook best practices

  • Verify signatures — always validate the signature using your subscription secret.
  • Respond quickly — return a 2xx promptly and process asynchronously.
  • Process idempotently — handle duplicate event IDs gracefully.
  • Fetch detail on demand — the payload does not embed results; load them from the REST API.
  • Store the secret securely — keep it in environment variables or a secret manager.