ATS / HRMS Job Webhook API

Developer Hub · Integration Documentation

API documentation

ATS / HRMS Job Webhook API

A single webhook endpoint that keeps job postings in sync between an external ATS or HRMS and the platform. Whenever a job is created, updated, or closed on your side, send us an event — we validate it, resolve the company record, and write the job through.

POST application/json job.created job.updated job.closed

Before sharing externally: replace every <PLACEHOLDER> in this document — base URL, environment, webhook secret header name, and secret value — with your real integration details. See Integration details.

02 · Authentication

Authentication

Every request is checked by webhook-secret middleware. Send the shared secret in the agreed request header on every call — there is no OAuth flow, no query-string token, and no session.

Required headers
Content-Type: application/json
<WEBHOOK_SECRET_HEADER>: <WEBHOOK_SECRET>

Security note — never place the webhook secret inside the JSON body, and never log it or echo it back in a response.

03 · Base URL & environment

Base URL & environment

All paths in this document are relative to the base URL of the environment you're targeting.

EnvironmentBase URL
StagingPOST <STAGING_BASE_URL>/ats/jobs
ProductionTBD

04 · Endpoint reference

Endpoint reference

POST /ats/jobs
MethodPOST
Endpoint<BASE_URL>/ats/jobs
Content-Typeapplication/json

One endpoint handles all three lifecycle events — the event field in the request body tells the API which operation to run.

05 · Supported events

Supported events

EventPurpose
job.createdCreate a new job. If job_id already exists, the existing job is updated instead.
job.updatedUpdate an existing job. Partial job fields are supported.
job.closedClose an existing job by setting status to false.

06 · Request structure

Request structure

Standard envelope

Every request — regardless of event — uses the same top-level shape.

{
  "event": "job.created",
  "payload": {
    "job": {},
    "company": {}
  }
}
FieldTypeRequiredDescription
eventStringYesOne of job.created, job.updated, job.closed
payloadObjectYesContainer for job and company data
payload.jobObjectYesJob information
payload.companyObjectFor createCompany information; optional for updates

Job object fields

FieldTypeRequired (create)Max lengthDescription
job_idStringYes50Unique external ATS/HRMS job ID
titleStringYes225Job title
descriptionStringYesJob description
cityStringYes50Job location city
stateStringYes50Job location state
statusBoolean *YesJob open / closed state
* Send a JSON boolean when possible. The API also normalizes 0/1 and selected string equivalents — see Job status values.

Company object fields

FieldTypeRequired (create)Max lengthDescription
nameStringYes115Company name
emailStringYes115Company email; used to find an existing company
logoStringYesCompany logo URL or stored value
typeStringYesCompany / industry type
cityStringYes50Company city
stateStringYes50Company state

Company matching — companies are looked up by email. A match updates the existing record; no match creates one.

07 · Event guides

Event guides

Runnable requests for each lifecycle event. Pick a language once — every example on this page switches with you.

job.created

Use this when a new job is created in your ATS/HRMS. All documented job and company fields are required.

Idempotent — if job_id already exists, this updates that job instead of creating a duplicate.

job.updated

job_id is always required. Send only the fields that changed — if company data is included, email is required with it.

Update validation — at least one job field besides job_id, or company data, must be present.

job.closed

Only job_id is required. The API sets status to false automatically.

08 · Job status values

Job status values

InputMeaning
true / 1 / "true" / "1" / "active" / "open"Open / active
false / 0 / "false" / "0" / "inactive" / "closed"Closed / inactive

For third-party integrations, prefer sending native JSON booleans (true / false) whenever possible.

09 · Response reference

Response reference

Success response

{
  "success": true,
  "message": "Webhook processed successfully",
  "data": {
    "event": "job.created",
    "action": "created_job",
    "job_id": "JOB-1001",
    "id": 101,
    "company_id": 25
  }
}

Response action values

ActionMeaning
created_jobNew job created
updated_existing_jobExisting job updated from a repeated job.created event
updated_jobExisting job updated
closed_jobExisting job closed

10 · Validation rules

Validation rules

  • Request body must be a valid JSON object.
  • event is required and must be one of the supported events.
  • Unsupported job or company fields are rejected.
  • All required fields must be present for job.created.
  • job_id is required for job.updated and job.closed.
  • Company email must be a valid address whenever provided.
  • Configured maximum field lengths are enforced.
  • job.updated must include at least one field to change.
  • job.updated and job.closed return "Job not found" when job_id doesn't exist.

11 · Error handling

Error handling

Validation, not-found, duplicate, relationship, and database errors are categorized internally. The API never exposes ORM internals, SQL, stack traces, or secrets in its response.

ScenarioStatusExample message
Invalid / missing field400Invalid webhook payload / field-specific message
Unsupported event400Unsupported webhook event
Job not found404Job not found
Duplicate / unique conflict409Webhook record already exists
Database / internal failure500Failed to process webhook

Implementation note — the current controller returns HTTP 500 for every service error. Before this API is shared externally, the controller should return error.statusCode when available, so integrators can tell validation errors apart from transient server errors.

12 · Retry & duplicate delivery

Retry & duplicate delivery

Network errors and timeouts can cause a retry. Reuse the same job_id across a job's full lifecycle so retries and later events resolve to the same record.

Create: JOB-1001
Update: JOB-1001
Close:  JOB-1001

A repeated job.created delivery with the same job_id updates the existing job — it never creates a duplicate row.

13 · Integration flow

Integration flow

  1. 1

    ATS / HRMS sends

    POST to /ats/jobs

  2. 2

    Verify secret

    Webhook-secret header checked

  3. 3

    Validate

    Event type + payload shape

  4. 4

    Create / find company

    Matched by company email

  5. 5

    Create / update / close job

    Resolved by job_id

  6. 6

    JSON response

    Acknowledged with 2xx

14 · Integration checklist

Integration checklist

  • Use POST for all webhook events.
  • Send Content-Type: application/json.
  • Include the webhook secret header on every request.
  • Use only job.created, job.updated, or job.closed.
  • Use a permanent, unique job_id per job.
  • Reuse that same job_id for create, update, and close.
  • Send every required field for job.created.
  • Send only changed fields for job.updated when appropriate.
  • Send job.closed the moment a job goes inactive.
  • Don't send undocumented fields — they're rejected.
  • Prefer JSON booleans (true/false) for status.
  • Treat any 2xx response as acknowledgement.

15 · Integration details

Integration details to complete before sharing

ItemValue
Staging base URL<STAGING_BASE_URL>
Production base URL<PRODUCTION_BASE_URL>
Webhook endpoint/ats/jobs
Authentication header<WEBHOOK_SECRET_HEADER>
Authentication secretShare securely — do not commit to this document if it will be widely distributed
Technical contact<CONTACT_NAME / EMAIL>

16 · Support

Support

For integration support, payload clarification, staging access, authentication credentials, or production rollout questions, contact the designated development / integration team.