Skip to main content
A webhook is an HTTP 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:
  1. Register a webhook with signing turned on.
  2. Read the payload you receive: headers and fields.
  3. Verify the signature: with the SDK helper, or in a few lines of your own, plus full receiver examples.
  4. Track deliveries and retries: states, idempotency, and the delivery history.
  5. Manage the signing secret: generate, supply, disable, and rotate without a gap.
  6. 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.

What each property means

Signing is optional but strongly recommended: without it, your endpoint cannot tell a real HydraDB delivery from anything else that can reach the URL. Section 3 shows how to verify it. Calling 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.
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.
The management endpoints return the standard v2 { 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 a POST with a JSON body and these headers:
A test delivery is synthetic: nothing was ingested, so there is no database name to report, and every scope field, including 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.
Route and filter on 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 carries X-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.
The official SDKs include a verifier:
Otherwise, implement it directly. Both versions use a constant-time comparison, which matters: a naive == leaks timing information that can be used to forge a signature byte by byte.
If the signing secret is missing from your environment, reject the request rather than skipping verification. Return a 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.

4. Track deliveries and retries

When an item reaches a terminal state, HydraDB creates a delivery record, sends the POST, 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. If a worker shuts down during delivery, the sweep process recovers the event later. Test deliveries do not appear in the history. Because of retries, your receiver should be idempotent:
  • Store delivery_id.
  • If the same delivery_id arrives again, return 2xx without repeating side effects.
The history uses 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.
Only 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.
Disabling removes the stored secret, and deliveries stop carrying X-HydraDB-Signature.
Rotating takes effect immediately, with no overlap period. Deliveries in flight during a rotation are signed with the new secret, so a receiver that only knows the old one will reject them. Rotate without downtime shows how to avoid the gap.

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.
1

Choose the new secret yourself

Generate a high-entropy value with your own tooling, for example 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.
2

Teach your receiver both secrets

Deploy your receiver so it accepts either the current secret or the new one, reading both from your environment. At this point nothing has changed on the HydraDB side, so every delivery still verifies against the old secret.
3

Rotate in HydraDB, supplying that secret

In the dashboard, open Rotate, tick I’ll use my own secret, and paste the value. Over the API, call POST /webhooks/indexing/signing-secret with a signing_secret body. Deliveries switch to the new secret immediately, and your receiver already accepts it.
4

Retire the old secret

Once you have confirmed deliveries are verifying against the new secret, remove the old one from your receiver and redeploy. You are back to a single active secret.

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-Signature using 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 2xx only after you accept the event.
  • Deduplicate using delivery_id.
  • Keep the endpoint fast. Put slow work in a queue or background job.

Common issues

  • 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