Write a webhook
See Webhooks for the full field reference and delivery model this guide only walks through the common path of.
1. Create the config file
Section titled “1. Create the config file”Targets live in a YAML file, not a database table — this can hold real bearer tokens and HMAC secrets, so it belongs in a file kept out of git, not a row a superuser edits at runtime:
cp api/webhooks.example.yaml webhooks.yaml2. Add a target
Section titled “2. Add a target”Edit webhooks.yaml with the one endpoint you want to notify first. This
example fires on indexing or upload, only for the invoices bucket:
targets: - name: my-first-target url: https://example.com/hooks/atlas events: [INDEX, UPLOAD] bucket: invoices secret: a-shared-secret-only-this-target-and-atlas-know body: bucket: ${bucket} path: ${path} object_id: ${object_id}Omit events to fire on every action, and bucket to fire for every
bucket. secret is optional but recommended — it’s what lets the receiver
verify a delivery actually came from Atlas (step 4).
3. Point Atlas at the file and restart
Section titled “3. Point Atlas at the file and restart”ATLAS_WEBHOOKS_CONFIG_PATH=./webhooks.yamlThis is read once at process start — restart the API after editing either the path or the YAML file itself.
4. Verify a delivery
Section titled “4. Verify a delivery”Trigger the action you configured (declare a document, upload a file,
…) and check your endpoint received a signed POST:
POST /hooks/atlas HTTP/1.1Content-Type: application/jsonX-Atlas-Signature: sha256=5f1c2e...a91b
{"bucket": "invoices", "path": "2024/invoice_042.pdf", "object_id": "0198e2b4-..."}On the receiving end, confirm the signature before trusting the payload:
import hashlibimport hmac
def verify(secret: str, signature_header: str, raw_body: bytes) -> bool: algo, _, signature = signature_header.partition("=") expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest() return algo == "sha256" and hmac.compare_digest(expected, signature)5. Add more targets, or more ${variable} substitution
Section titled “5. Add more targets, or more ${variable} substitution”Every string in url, headers, and body — at any nesting depth —
supports the same substitution. The full variable list
(${event_id}, ${actor}, ${state}, ${context_json}, …) and every
optional field (method, headers, skip_tls_verification, …) are in
Webhooks.