Compute
Receive webhooks safely
Verify the signature, the timestamp and the event identity on the raw bytes before you parse them, acknowledge safely, then fetch canonical state from the API.
Before you start
You need an endpoint you control, a registered webhook, and somewhere durable to record what you have already seen.
You also need a way to call the Work API from the same service. A webhook receiver that cannot ask a follow-up question is only half an integration.
Verify on the raw bytes, before parsing
Capture the exact bytes of the request body before any framework touches them. Then verify three things, in this order.
- The signature, computed over those raw bytes. Not over a re-serialized object, which will differ by whitespace or key order.
- The timestamp, against a bounded tolerance you choose. An old delivery replayed at you is the attack this stops.
- The event identity, so you know which event this claims to be.
Only after all three pass may you parse the body. Parsing first is the mistake, because a parser is code you have run on an unverified payload.
Compare signatures with a constant-time comparison. Reject anything that fails, and do not tell the caller which check failed.
Acknowledge safely, then ask
Record the event identity durably and return your acknowledgement quickly. Do the real work afterwards, outside the request.
Your acknowledgement means "received", not "processed". Treating it as a completion promise is how a slow handler turns into a redelivery storm.
Then fetch canonical state from the API using the identifiers in the event. The payload tells you something changed; the API tells you what is true now.
Never treat the payload as the truth
A webhook body is a notification. It was accurate when it was sent, and it may not be accurate when you read it.
So make the decision from a fresh read, not from the fields in the body. Read the job status, the delivery state or the result manifest as needed.
This matters most for terminal states. A part file existing does not mean a bundle is complete, and only result-manifest.json marks a complete bundle. See what a stalled job looks like when a fresh read disagrees with the event you received.
Handle duplicates and out-of-order delivery
Delivery is at-least-once, and ordering is not promised. Both are normal, and both are simple to handle.
- Duplicate. Look up the event identity first. If you have seen it, acknowledge and stop.
- Out of order. Compare the version on the record, not the arrival time. Never let a lower version overwrite a higher one.
- Late. A stale event about a finished job is history. Record it and move on.
- Missing. Do not build a system that depends on a delivery arriving. Poll status for anything you cannot afford to miss.
Store the event identity and the version together. That pair answers both questions with one lookup.
Confirm success
Send yourself a redelivery of an event you have already handled. A correct receiver acknowledges it and does no further work.
Then check the record it wrote. The version should be unchanged, and no duplicate downstream action should exist.
Finally, tamper with a signature in a test request. Your endpoint should reject it without parsing the body.
When something looks wrong
Read your own rejection counts before opening a support request. Most webhook problems are visible from the receiver's side.
- Signature failures across every delivery usually mean the body was modified in transit by a proxy or a middleware.
- Timestamp failures usually mean clock drift on your host.
- Repeated redelivery of the same event usually means your acknowledgement is too slow or is only sent after processing.
When you do contact support, quote the event identity and the receipt reference. Never send the payload, a signature or a key.