Webhooks guide
Outbound webhooks let RolesAPI notify your server the moment an async job finishes, instead of you polling for status. Register an endpoint once and every job’s completion event is delivered to it, signed so you can verify it came from us.
How do I create a webhook?
curl -X POST "https://api.rolesapi.com/v1/webhooks" \ -H "Authorization: Bearer rk_live_your_key" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/hooks/rolesapi", "events": ["job.succeeded", "job.failed"] }'{ "data": { "id": "wh_01habc", "url": "https://example.com/hooks/rolesapi", "events": ["job.succeeded", "job.failed"], "secret": "whsec_9f2c4e6a8b0d1f3a5c7e9b2d4f6a8c0e", "active": true, "created_at": "2026-07-01T09:15:00Z" }, "request_id": "req_0b3d55e7"}The secret is shown once, in this response only. Store it immediately — later reads of the webhook return the object without the secret. If you lose it, delete the webhook and create a new one.
There are four supported events: job.succeeded, job.failed, job.timed_out, and job.aborted. A webhook receives every matching event for jobs on your account.
What does a delivery look like?
RolesAPI POSTs JSON to your URL:
{ "event": "job.succeeded", "delivered_at": "2026-07-01T09:32:41Z", "data": { "job": { "id": "5f0f6c2e-4b3a-4e9c-9c74-31d1f2a30c11", "type": "batch_detail", "status": "succeeded", "result_count": 120, "created_at": "2026-07-01T09:30:02Z", "started_at": "2026-07-01T09:30:03Z", "completed_at": "2026-07-01T09:32:41Z" } }}The payload carries the job, not the roles — fetch results from GET /v1/jobs/{id}/results with your API key, in any output format.
How do I verify the signature?
Every delivery includes the header:
x-rolesapi-signature: t=1751362361,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bdtis the Unix timestamp when the delivery was signed.v1isHMAC-SHA256(secret, "<t>.<raw body>")in hex — the timestamp, a period, and the exact raw request body.
Verification steps:
- Read the raw request body as bytes, before any JSON parsing or re-serialization.
- Parse
tandv1out of the header. - Reject if
|now - t| > 300seconds — this bounds replay of captured deliveries. - Compute
HMAC-SHA256(secret, t + "." + raw_body)and compare withv1using a timing-safe comparison. - Only then act on the payload.
Runnable Node and Python verifiers are in Verify a webhook signature.
What if my endpoint is down?
Respond with a 2xx within a few seconds to acknowledge a delivery. Non-2xx responses and timeouts are retried with increasing delay. Every attempt is recorded — inspect them at any time:
curl "https://api.rolesapi.com/v1/webhooks/wh_01habc/deliveries" \ -H "Authorization: Bearer rk_live_your_key"Each delivery record includes the event, attempt number, response status, and timestamp — see the Webhooks reference. Because retries can produce duplicate deliveries, make your handler idempotent: key on the job id and ignore events you have already processed.
How should I handle the secret?
- Store it in a secrets manager or environment variable, never in code or logs.
- Use a distinct endpoint (and therefore secret) per environment.
- To rotate: create a new webhook, verify deliveries arrive, then
DELETE /v1/webhooks/{id}on the old one.