Receive job webhooks
Let your application react to job events without constant polling. Treat delivery as at least once and verify each signed message before acting on it.
Provide a public receiver
Crawl and company creation can include a webhook object with a public url and a secret between 16 and 200 characters. Use a dedicated secret for the receiving application and store it with the job's configuration. Do not use your Luni API key as the webhook secret.
Use a public HTTPS receiver in your application. The receiver should accept the event, persist the work to be done and return a 2xx status promptly. Long-running processing should happen after acceptance, so a slow downstream task does not cause unnecessary redelivery.
Verify the signed bytes
The X-Luni-Signature header has the form t=timestamp,v1=hex_signature. Luni signs the timestamp, a dot and the exact raw request body using HMAC-SHA256 with your shared secret. Preserve those raw bytes before parsing JSON; reserializing an object can change the signed representation.
Compare signatures in constant time and apply a timestamp tolerance suited to your receiver. Reject missing, malformed or mismatched signatures. Keep the secret on the server and avoid logging it when investigating a failed verification.
Make duplicate delivery harmless
X-Luni-Event-ID identifies the delivery event. Persist accepted IDs and make handling the same event twice safe. A receiver can return success after an event is already accepted rather than repeating a downstream action.
Delivery is at least once, with bounded retries over a 24-hour window. A non-2xx response or delivery failure can cause another attempt. Do not assume that the arrival order of messages is a complete account of job state.
