Overview
Webhooks allow you to receive real-time HTTP notifications when events occur in your Enterprise API v2 account. Configure a webhook endpoint to be notified when retrieval requests have a public status update, need action from your firm, or have new records or invoices.Webhook Events
Subscribe to any combination of these event types:
When creating or updating a webhook, provide at least one event in
events. See
Retrieval Request Events for details of the retrieval
events.
Creating a Webhook
Register a webhook endpoint with the events you want to receive:name is at most 100 characters, description at most 500 and url at most 2048.
An organization can register up to 20 webhooks; creating a 21st returns 409 limit_exceeded
(delete or reuse an existing webhook instead). Values over a limit return 400 invalid_request.
Webhook Payload
All webhook deliveries use HTTP POST with a JSON body in this envelope. The shape ofdata depends on type:
Payload Fields
The
data fields for each event type are listed under Retrieval Request Events.
Delivery Headers
Retrieval Request Events
Retrieval webhooks identify the request and the type of update. Fetch the request for its current status, action request, and document metadata; use the document download endpoint for record and invoice file URLs. The envelope isid, type, created_at, and data. Every retrieval event includes data.retrieval_request_id, data.case_id (nullable), and data.public_updated_at, the version of public state that triggered the event. The id is opaque; use it to deduplicate deliveries.
To subscribe to retrieval events, use an API key with webhooks:write and
retrievals:read.
retrieval_request.status_changed
Fires when the public status or timeline changes, including a new visible update
within the same stage, a correction to an existing visible update, and a return
to a previously visited stage.
retrieval_request.action_required
Fires when a client action request is opened or reopened. Fetch GET /v2/retrieval-requests/{id} and read pending_action_request for the current message and any attachment.
retrieval_request.documents_available
Fires when records are released or a provider invoice becomes downloadable. document_ids use
the same IDs as GET /v2/retrieval-requests/{id}/documents.
An invoice event also contains invoice_ids with the same ID in both arrays. Fetch document metadata through the API, then request a download URL from the
document download endpoint.
Event IDs and reconciliation
Deduplicate deliveries by eventid. Retries use the same ID; a later occurrence, such as reopening an action request, has a new ID.
When an event arrives, fetch the identified request and compare its public_updated_at with your cached version. Events may arrive out of order, so the fetched request gives you the current state.
Use incremental polling to keep all requests current, including completed and cancelled ones. Save the final page’s next_public_updated_since as your polling checkpoint, and choose an interval that fits your integration.
Fetch GET /v2/retrieval-requests/{id} when you need current costs.
Signature Verification
Every webhook delivery includes the recommended timestampedX-Tavrn-Signature-V1 signature and the X-Tavrn-Timestamp header. Verify the v1 signature against the raw request body and reject timestamps more than five minutes from your current time. The timestamp limits replay attacks.
The v1 signature is the hex HMAC-SHA256 of <timestamp>.<raw body>, sent as X-Tavrn-Signature-V1: v1=<hex>. The timestamp is Unix time in seconds (for example, 1767225600). Compare signatures in constant time.
X-Tavrn-Signature signs only the raw body and has no timestamp. Use the v1
signature for verification.
Node.js Example
Python Example
enqueueEventOnce or enqueue_event_once in your application so it stores an event once by id. Process the saved event in a background worker.
For Express, register the raw-body webhook route before any JSON body parser middleware so signature verification receives the original bytes.
Best Practices
Respond Quickly
Verify the signature and save the event durably before returning a 2xx response within 5 seconds. Do longer work, such as fetching a request or downloading a file, in a background worker. If the event cannot be saved, return a non-2xx response so Tavrn retries it.Idempotent Processing
Events may be delivered more than once. A retried delivery has the sameid as the original. Store processed IDs in a persistent queue or database so deduplication survives restarts, and make the background work safe to retry.
Handle All Event Types
Handle unknown event types gracefully in your background worker:Retries and Automatic Disabling
A delivery succeeds when your endpoint returns a 2xx status within 5 seconds. Any other status, a timeout, or a connection error counts as a failed attempt. Tavrn does not follow redirects, so a 3xx response is a failed attempt too: your webhook URL must answer directly. Tavrn makes up to 5 attempts per event, retrying 1 minute, 5 minutes, 30 minutes, and 2 hours after successive failures. Every attempt carries the same event body andid; the timestamp and v1 signature are generated for each attempt.
If all attempts for an event fail, the webhook’s consecutive_failures increases by one; any successful delivery resets it to 0. When consecutive_failures reaches 5, Tavrn disables the webhook: is_enabled becomes false and auto_disabled_at records when. Disabled webhooks receive no events, and events that occur while a webhook is disabled are not delivered later.
To recover, fix your endpoint, confirm it with a test event, then re-enable the webhook with PATCH /v2/webhooks/{id} and {"is_enabled": true}. Re-enabling resets consecutive_failures to 0 and clears auto_disabled_at. For retrieval requests, use your reconciliation poll to catch up on anything missed.
Monitor Webhook Health
Regularly check your webhook status:consecutive_failures> 0 (investigate delivery issues)is_enabled: false(webhook is disabled)auto_disabled_atset (Tavrn disabled the webhook after 5 consecutive failed deliveries)last_failure_at/last_success_at(delivery timestamps)last_failure(most recent failed attempt:at,status_code,error,event_type)
status_code is null when your endpoint did not respond. error describes the
failure. last_failure excludes test events.
Managing Webhooks
List Webhooks
Update Webhook
is_enabled to true on a disabled webhook resets consecutive_failures to 0 and clears auto_disabled_at.
Disable Webhook
Delete Webhook
Testing Webhooks
Send a Test Event
Send a test event to check that your endpoint is reachable and verifies signatures:success:
status_code is null when no response was received. error is null on
success and describes the failure otherwise. Your endpoint’s response body is
never returned.
The endpoint requires the webhooks:write scope and works on disabled webhooks.
Tests do not change consecutive_failures, last_failure_at, last_success_at,
or last_failure. Failed tests are not retried. You can send one test per webhook
every 10 seconds; sooner requests return 429 rate_limited with a Retry-After
header.
Your endpoint receives a webhook.test event, signed and delivered with the same headers as real events (X-Webhook-Event-Type: webhook.test):
webhook.test cannot be added to events. Return a 2xx response and take no other action.
Local Development
For local development, use a tool like ngrok to expose your local server:Security Considerations
- Verify signatures - Check
X-Tavrn-Signature-V1against the raw body before processing a delivery - Use HTTPS - Keep delivery encrypted. URLs must be publicly reachable and cannot resolve to a private address
- Rotate secrets - If a secret is compromised, delete and recreate the webhook
- Rate limiting - Protect your endpoint from abuse
- Logging - Log event IDs and delivery outcomes without logging patient details, secrets, or signed download URLs