When to use webhooks
Webhooks are better than polling when:- You have many concurrent submissions
- You want real-time notifications
- Your API server resources are limited
- You prefer an event-driven architecture
- Occasional submissions
- Simple scripts and CLIs
- Quick prototypes and testing
Setting up webhooks
Step 1: Prepare your endpoint
Create an HTTPS endpoint that can receive POST requests. The delivered envelope uses Standard Webhooks, so verify the signature with thestandardwebhooks library and your subscription secret. The verified event exposes type (the event type) and data (a snake_case object).
Step 2: Create a subscription
UsePOST /api/webhooks/subscriptions. The request fields are endpointUrl (HTTPS required), eventTypes, and an optional description.
201):
endpointUrl or hitting your workspace subscription limit returns 422.
Step 3: Test your endpoint
Create a submission and watch your endpoint receive events:Webhook events
There are exactly two event types. The delivered envelope hasid, type, timestamp, and a snake_case data object. The payload does not embed results — fetch detail by ID after receiving an event.
asset.processing.completed
Fires when an asset finishes processing successfully.data.external_reference is echoed verbatim from the submission’s externalReference and is present only when it was set at create (the key is omitted otherwise). It also appears on asset.processing.failed deliveries. See Webhooks → delivery payload.
asset.processing.failed
Fires when an asset fails to process. Thedata object adds error_message and is_retryable — when true, the asset can be retried via the retry endpoint; when false, the failure is permanent.
Handling webhooks
Basic handler pattern
Readevent["type"] and the snake_case data fields. Because the payload carries no results, fetch issues or topics by asset ID when you need detail.
.../assets/{asset_id}/topics the same way.
Queue-based processing
For high-volume scenarios, queue webhooks for async processing and respond immediately:Webhook reliability
Signature verification
Always verify webhook signatures with the subscriptionsecret:
Idempotency
Deliveries may arrive more than once. The delivery provider retries failed deliveries, so make your handler idempotent by deduplicating on the eventid:
GET .../subscriptions/{id}/deliveries) or the control plane for attempt history rather than assuming a fixed retry schedule.
Testing webhooks locally
Using ngrok
Expose your local server publicly:https://abc123.ngrok.io. Use it as the endpointUrl in your subscription.
Managing subscriptions
The list endpoint returns a paginated envelope:
{ "items": [...], "page": 1, "pageSize": 10, "total": 3, "totalPages": 1 }. None of these responses include the secret — it is returned only on create.