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.

curl -X POST https://api.luni.gg/v1/crawl \
  -H "Authorization: Bearer $LUNI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: example-crawl-c2f6d826452a" \
  -d '{
  "url": "https://example.com",
  "limit": 5,
  "webhook": {
    "url": "https://your-app.example/webhooks/luni",
    "secret": "replace-with-a-long-random-secret"
  }
}'

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.

Retrieve the authoritative result

Use a verified event as a signal to inspect the saved operation or job with your scoped API key. Read the actual status and successful page results before updating a customer-facing state. Polling remains useful as a recovery path when a receiver was unavailable.

A job webhook reports an operation event. It is not a monitoring alert about a change to the source website (monitors send those as monitor.page events), and it does not replace the result's retention window. Store the data your application needs beyond seven days.