POST that HydraDB sends to your endpoint when an ingested document, memory, or app source finishes indexing: completed or errored. Use it to mark a document as ready in your own database, tell a user their upload finished, kick off a downstream job, or catch indexing failures without polling. You register one endpoint per organization with POST /webhooks/indexing.
For progress before then, poll GET /context/status.
In this guide:
- Register a webhook with signing turned on.
- Read the payload you receive: headers and fields.
- Verify the signature: with the SDK helper, or in a few lines of your own, plus full receiver examples.
- Track deliveries and retries: states, idempotency, and the delivery history.
- Manage the signing secret: generate, supply, disable, and rotate without a gap.
- Security checklist, common issues, and related pages.
1. Register a webhook
This request registers your endpoint for the one supported event,indexing.status_changed, and asks HydraDB to generate a signing secret in the same call. The secret is returned once and cannot be read again; copy it into your receiver’s secret store right away.
Register a webhook with signing: Python, TypeScript, or cURL
Register a webhook with signing: Python, TypeScript, or cURL
What each property means
POST /webhooks/indexing again replaces the registration. Omitting signing_secret then preserves the secret you already have; changing the URL or the event list never changes signing. To turn signing off, call DELETE /webhooks/indexing/signing-secret, as in section 5.
The Webhooks page of the dashboard registers too: enter the URL, enable signing, and copy the secret when it is shown. Either way, send a test delivery next to confirm the endpoint is reachable and your verifier works.
Check, replace, test, or delete the registration: cURL
Check, replace, test, or delete the registration: cURL
signing_secret_configured only says whether a secret is set; the secret itself is never returned. Deleting the webhook discards the stored secret along with the registration.{ success, data, error, meta } envelope used by /databases, /context/*, and /query; the examples on this page show only data. The event sent to your webhook URL is not wrapped.
2. Read the payload you receive
Each delivery is aPOST with a JSON body and these headers:
Delivery payloads for completed, errored, and test events: JSON
Delivery payloads for completed, errored, and test events: JSON
database, is set to your organization ID. Match on test: true (or the test_ prefix on delivery_id) to tell it apart from a real delivery.database, not tenant_id; database is the name you sent. New integrations should read database and collection.
3. Verify the signature
When signing is configured, every delivery carriesX-HydraDB-Signature: sha256=<lowercase hex digest>, where the digest is HMAC-SHA256 with your signing secret as the key over the raw request body bytes. Three details decide whether your verifier works:
- The
sha256=prefix is part of the header value, not a separate field. Compare against the whole string. - The digest is lowercase hex, not base64.
- The HMAC is computed over the raw body bytes exactly as received. Parsing the JSON and re-serializing it produces different bytes, so the signature will not match.
Verify with the SDK helper: Python or TypeScript
Verify with the SDK helper: Python or TypeScript
== leaks timing information that can be used to forge a signature byte by byte.
Verify without the SDK: Python or TypeScript
Verify without the SDK: Python or TypeScript
2xx quickly and do slow work after acknowledging the request. These receivers wire the verifier into a handler; both read the raw body before parsing.
Receiver examples: Python (FastAPI) or TypeScript (Express)
Receiver examples: Python (FastAPI) or TypeScript (Express)
4. Track deliveries and retries
When an item reaches a terminal state, HydraDB creates a delivery record, sends thePOST, and marks the record delivered or schedules a retry. Every attempt is recorded, and the history is on the dashboard Webhooks page and over the API.
- Store
delivery_id. - If the same
delivery_idarrives again, return2xxwithout repeating side effects.
List, filter, page, fetch, and retry deliveries: cURL
List, filter, page, fetch, and retry deliveries: cURL
doc_id for the item; the outbound payload uses id. status accepts any of the delivery states above. limit is 1 to 100 (default 20); when next_cursor is not null, pass it back as cursor. <delivery_id> is the value from a payload or from the list.failed and permanently_failed deliveries can be retried by hand; for any other state the call returns queued: false. A retry is signed with your current signing secret, not the one in force when the delivery was first attempted, so after a rotation your receiver must know the new secret.
5. Manage the signing secret
POST /webhooks/indexing/signing-secret enables or rotates signing after registration, and DELETE on the same path disables it. Two ways to set a secret:
- Let HydraDB generate one: send no body. The secret is returned exactly once, in plain text, and takes effect immediately.
- Supply your own: send
signing_secret, at least 16 characters. Use this when you want to deploy the secret to your receiver first and hand it to HydraDB afterwards, so there is no window where deliveries are signed with a secret your endpoint does not yet know.
Generate, supply, or disable the signing secret: cURL
Generate, supply, or disable the signing secret: cURL
X-HydraDB-Signature.Rotate without downtime
HydraDB signs each delivery with one secret, so the overlap has to live in your receiver: deploy it with both secrets before rotating in HydraDB, and supply the new secret yourself so you know it before it takes effect.Choose the new secret yourself
openssl rand -base64 32. Do not use the generate option here: a generated secret is only revealed after it is already in effect, which is the window you are trying to avoid.Teach your receiver both secrets
Rotate in HydraDB, supplying that secret
POST /webhooks/indexing/signing-secret with a signing_secret body. Deliveries switch to the new secret immediately, and your receiver already accepts it.Retire the old secret
A receiver that accepts either secret: Python or TypeScript
A receiver that accepts either secret: Python or TypeScript
Security checklist
- Use HTTPS for your webhook URL.
- Enable signing with a cryptographically random secret, generated by HydraDB or your own tooling.
- Verify
X-HydraDB-Signatureusing the raw request body, with a constant-time comparison. - Fail closed. Reject the request when the secret is missing from your environment, rather than skipping verification.
- Store the secret as a secret. It belongs in your secret manager, not in source control.
- Return
2xxonly after you accept the event. - Deduplicate using
delivery_id. - Keep the endpoint fast. Put slow work in a queue or background job.
Common issues
Related
- Register Webhook: the full request and response reference, with the other webhook endpoints alongside it
- Ingestion Status: poll for progress before an item reaches a terminal state
- Knowledge: ingesting the documents whose indexing these events report on
- SDKs: client setup for the Python and TypeScript examples
