Webhooks — events & delivery
Webhooks are the recommended way to keep your system in sync with Atlast. Instead of polling, Atlast pushes a small notification to your server the moment a job changes, and you re-fetch that job from the API for its full detail. You configure one webhook endpoint per organisation in the Atlast Portal (Settings → Integrations → Webhook).
Events
Section titled “Events”| Event | Fires when… |
|---|---|
job.published | A job becomes publicly visible. |
job.updated | A published job’s content changes. |
job.unpublished | A published job is taken down (but not deleted). |
job.deleted | A job is permanently removed. |
The payload is intentionally thin
Section titled “The payload is intentionally thin”Webhook payloads carry identifiers, not full job content. They tell you what changed and where to fetch the current state — they are not a snapshot of the job:
{ "id": "evt_9f8e7d6c5b4a3210", "event": "job.updated", "occurredAt": "2026-06-09T12:34:56.000Z", "data": { "jobId": "job-550e8400-e29b-41d4-a716-446655440000", "publicId": "abc123def456", "jobUrl": "https://acme.careers.atlasthq.com/jobs/abc123def456", "applyUrl": "https://acme.careers.atlasthq.com/jobs/abc123def456/apply", "apiUrl": "https://api.atlasthq.com/api/public/v1/jobs/abc123def456" }}| Field | Description |
|---|---|
id | Unique event ID. Use this to de-duplicate (see below). |
event | One of the four event types above. |
occurredAt | ISO-8601 timestamp of when the change happened. |
data.jobId | Internal job ID. |
data.publicId | Public identifier — use it with the Jobs API. |
data.jobUrl / data.applyUrl | Public careers URLs (may be null). |
data.apiUrl | The exact Jobs API URL to fetch this job’s full detail. |
The re-fetch pattern
Section titled “The re-fetch pattern”Because the payload is thin, the correct way to handle most events is:
- Receive the webhook and verify its signature.
GETthedata.apiUrl(or…/jobs/{publicId}) to load the full, current job detail.- Upsert that into your system.
This keeps your data correct even if events arrive out of order or are redelivered — you always reconcile against the live API, which is the source of truth.
For job.deleted and job.unpublished, you don’t need to re-fetch — the job is
gone or no longer public (GET …/jobs/{publicId} returns 404). Remove or hide
it on your side.
Delivery headers
Section titled “Delivery headers”Every delivery includes these headers:
| Header | Purpose |
|---|---|
X-Atlast-Signature | HMAC-SHA256 of the raw body — verify this. |
X-Atlast-Timestamp | ISO-8601 time the event occurred. |
X-Atlast-Event | The event type (e.g. job.updated). |
X-Atlast-Delivery-Id | Equals the payload id — the de-duplication key. |
Delivery semantics
Section titled “Delivery semantics”- At-least-once. A delivery may arrive more than once. De-duplicate on
the event
id(X-Atlast-Delivery-Id): record IDs you’ve processed and skip repeats. - Retries. If your endpoint doesn’t return a
2xx, Atlast retries with backoff. Return2xxonly after you’ve safely accepted the event (queued or stored it). - Ordering is not guaranteed. Events can arrive out of order. The re-fetch pattern makes this a non-issue — reconcile against the live API rather than trusting event order.
- HTTPS only. Webhook endpoints must be public HTTPS URLs.
Responding correctly
Section titled “Responding correctly”HTTP/1.1 200 OKRespond 2xx quickly (within a few seconds). Do slow work (re-fetching,
database writes) asynchronously — accept the event, enqueue it, return
200, then process. A slow handler looks like a failure and triggers retries.