When to Use Webhooks
Any job can be polled, so webhooks matter where polling works poorly: poll frequently and most requests returnprocessing, poll slowly and finished results sit unclaimed. One push per job replaces that loop. This is most valuable when many jobs run at once, when a finished parse should immediately trigger the next pipeline stage, and when failures should raise an alert rather than wait to be noticed.
Webhook Events
Theparse and extract events fire when a run reaches its final state. When the result is fetchable from the API, the event includes a result_url. See Event Payload for the variants. Synchronous Parse and Extract requests also fire events, but never include a result_url, because the result was already returned in the API response.
How Long Results Are Available
Job results are available for 24 hours after the job completes. If your organization uses Zero Data Retention (ZDR), a result is also deleted as soon as you fetch it, so theresult_url works once.
If your pipeline may act on events late (for example, working through a backlog after downtime), fetch results promptly on receipt, or create jobs with output_save_url so the output is delivered to your own storage as soon as the job finishes. See Events for Saved Output.
Set Up a Webhook Endpoint
Create an endpoint on your side first: an HTTPS URL that accepts POST requests and returns a2xx status code. The URL must be publicly reachable. For local development, use a tunnel such as ngrok.
Then register the endpoint. Registration happens in the Playground only, because there is no API for managing endpoints:
- Go to Playground > Settings > Webhooks. Endpoints belong to the workspace you create them in: your organization or your personal account.
- Click Add Endpoint.
- Enter the Endpoint URL.
- (Optional) Enter a Description so your team knows what the endpoint is for.
- Select the events to subscribe to. If you select none, the endpoint receives all events.
- Click Create endpoint.
- Copy the signing secret and store it securely, such as in a secret manager. The secret is shown only once. You use it to verify event signatures.
- Click Send test event to confirm your endpoint receives and verifies a signed event. See Test Events.
Event Payload
The event body is compact JSON that identifies the job and, when the result is fetchable from the API, carries a URL for it. It never contains document content, which keeps sensitive data out of the systems around your webhooks, such as request logs and log aggregators.parse.succeeded
Events for Failed Runs
Failed job events carry only the job ID and status. Fetch the job to get the error details. For a failed synchronous request, the error was already returned in the API response.parse.failed
Events for Saved Output
If you created the job withoutput_save_url, the event adds a delivery receipt confirming that the result was written to your URL, with the status code your storage returned. See Save Parsed Output to a URL and Save Extraction Output to a URL.
extract.succeeded with saved output
output_save_url. The event then has no result_url, and result_retained is false. The delivery receipt is your confirmation that the job finished and where the output went. See Result Retention.
extract.succeeded with ZDR
Test Events
Clicking Send test event on an endpoint sends awebhook.test event to that endpoint only. The event is signed like any real event, so it exercises your signature verification end to end. The job_id is synthetic (prefixed test-), there is never a result_url, and the send gets one attempt with no retries.
webhook.test
Verify Event Signatures
Every event is signed following the Standard Webhooks specification, so you can confirm that an event is authentic and wasn’t altered in transit. Verify the signature before acting on any event. Each delivery includes three headers:
Use a Standard Webhooks library instead of comparing hashes yourself: the libraries compare in constant time and reject stale timestamps, which blocks replay attacks. Verify with the endpoint’s own signing secret, and pass the raw request body exactly as received. Re-serialized JSON changes the bytes and fails verification.
Delivery and Retries
Your endpoint has 15 seconds to respond. Return a2xx status code as soon as you have recorded the event, and do any heavy processing afterward. Any 2xx counts as delivered. Any other response, or a timeout, counts as a failed attempt.
Failed deliveries are retried with increasing delays, from 30 seconds up to 2 hours between attempts: up to 14 attempts over roughly 12 hours. Retries reuse the same webhook-id, so deduplicating by that header makes a redelivered event harmless.
Every delivery attempt is recorded in the endpoint’s delivery log in Playground > Settings > Webhooks, including the response status and body (truncated to 4 KB).
Responding 410 Gone permanently cancels the remaining retries for that event. It does not unsubscribe the endpoint, and future events are still delivered. To stop all deliveries, disable or delete the endpoint in Playground > Settings > Webhooks.
Troubleshoot Webhooks
Use this section to troubleshoot issues with webhook endpoints and event deliveries.Signature Verification Fails
Verification fails when the secret, the body, or the timestamp doesn’t match what was signed. Check the three requirements in Verify Event Signatures: the endpoint’s own secret, the raw body bytes (web frameworks often parse and re-serialize JSON automatically), and an accurate server clock. To reproduce a delivery locally, use Copy as curl on the delivery in the delivery log. If you lost the endpoint’s secret, delete the endpoint and create it again to get a new one.Endpoint Stopped Receiving Events
Check the endpoint in Playground > Settings > Webhooks: deliveries stop when the endpoint is disabled or deleted, or when its event subscriptions change. Review the delivery log to see what was sent and what your endpoint returned. After fixing the receiver, click Send test event to confirm deliveries reach it.Missed or Duplicate Events
If your receiver was down for longer than the retry window (roughly 12 hours), the missed deliveries are not resent. To recover, call List Parse Jobs to find parse jobs you haven’t processed, and fetch each one. Extract Jobs has no list endpoint, so keep thejob_id from each create response on your side. Duplicates are expected with webhooks in general. Deduplicate by webhook-id.
Fetching the Result Returns an Error
Aresult_url fetch returns status 410 with the error code result_expired when the result is no longer available. See How Long Results Are Available.