Integrate webhooks safely
Webhooks let your systems react to platform events β a task assigned, a submission validated, a payment released β without polling. Getting them right means verifying authenticity, tolerating retries, and never doing slow work in the request path.
This guide covers safe integration end to end, with a worked handler you can adapt.
1. Register an endpoint
Register the URL that will receive events and the event types you care about. The platform returns a signing secret β store it securely; you will use it to verify every delivery.
curl -X POST https://api.taskmatch.ai/api/v1/webhooks \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://worker.example.com/hooks/taskmatch",
"events": ["task.assigned", "submission.validated", "payment.released"]
}'
# => { "id": 12, "signing_secret": "whsec_..." }2. Verify the signature
Every delivery carries an HMAC signature over the raw request body. Recompute it with your signing secret and compare in constant time. Reject anything that does not match β this is what stops a forged event from triggering real work.
import hmac, hashlib
def verify(raw_body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)3. Make handlers idempotent
Webhooks are delivered at least once, so the same event can arrive twice. Key your processing on the event id and skip anything you have already handled. Idempotency is the single most important property of a correct webhook consumer.
def handle(event):
if already_processed(event["id"]):
return # duplicate delivery, safe to ignore
mark_processed(event["id"])
dispatch(event["type"], event["data"])4. Respond fast, work later
Acknowledge with a 2xx immediately and push real work onto a background queue. If you do slow work inside the request, the platformβs delivery times out and retries, which multiplies load and can cause duplicate processing if you are not idempotent.
- Target a sub-second response on the webhook route.
- Return 2xx for accepted-but-queued; reserve non-2xx for genuine failures you want retried.
5. Handle retries and backoff
Failed deliveries are retried with exponential backoff. Because retries can arrive out of order relative to newer events, treat each event as a fact about a point in time and reconcile against current state rather than assuming strict ordering. Combined with idempotency, this makes your integration robust to the messy realities of network delivery.
Ready to run it for real?
Create an account and put this guide to work against the live platform.