WebHRDevelopers
On this page
Early access · v1

Build on WebHR

Post jobs and read hiring data in your WebHR workspace from your own systems: an HRIS, a requisition tool, a job board, or a vendor you choose.

Base URL
https://api.webhr.in/api/v1
Auth
API key → one-hour bearer token
Format
JSON, snake_case, UTC times
Covers today
Jobs, hiring stages, master data

Candidates, applications and webhooks come next.

Getting access

  1. The API is the API Access add-on. Ask your WebHR account manager, or support@webhr.in, to turn it on for your workspace.
  2. A workspace admin opens Settings → Integrations & Security → API Keys and creates a key: a name, the scopes it needs, and optionally the IP addresses it may be used from and an expiry date.
  3. WebHR shows the client_id and client_secret once. Keep the secret in your secrets manager; WebHR stores only a fingerprint and can't show it again. If it's lost, rotate the key.

A key acts with the access of the admin who created it, and stops working if that person is no longer a workspace admin. Before an admin leaves, have another admin create replacement keys.

Quick start

1. Get a token

curl -X POST https://api.webhr.in/api/v1/auth/token \
  -H "Content-Type: application/json" \
  -d "{\"client_id\": \"$WEBHR_CLIENT_ID\", \"client_secret\": \"$WEBHR_CLIENT_SECRET\"}"
Response
{
  "access_token": "eyJhbGciOi…",
  "token_type": "bearer",
  "expires_in": 3600,
  "scopes": ["recruitment.jobs:read"]
}

2. Call the API

curl "https://api.webhr.in/api/v1/recruitment/jobs?status=published" \
  -H "Authorization: Bearer $WEBHR_TOKEN"
Response
{
  "items": [{ "id": 42, "job_code": "JOB-0042", "title": "Welder", "status": "published", … }],
  "total": 1,
  "page": 1,
  "page_size": 25
}

Request builder

Pick an endpoint and fill in its fields to get a command you can run. It's built from the same OpenAPI file as the reference, so it always matches the API.

Nothing is sent from this page, and it never asks for your client secret. Run the command on your server, with a token from POST /auth/token in WEBHR_TOKEN.

Authentication

Scopes

Give each key only what it needs. A call outside the key's scopes answers 403; narrowing a key's scopes in WebHR takes effect on its next call.

ScopeAllows
recruitment.jobs:readList and read jobs; read the hiring stages
recruitment.jobs:createCreate jobs (always as drafts)
recruitment.jobs:updateEdit, publish and close jobs
master_data:readRead departments, designations, legal entities and business units

Paging and syncing

Lists take page (from 1) and page_size (default 25, at most 200), and answer {"items": […], "total": n, "page": 1, "page_size": 25}. Keep asking for the next page while page × page_size < total.

To keep a copy in sync, pass updated_since (an ISO 8601 time) to GET /recruitment/jobs: it returns only jobs changed since then, most recently changed first. Store the time each sync started and use it next time.

Errors

Every error has the same shape. Quote the request_id when you contact support; a 422 also lists each field's problem in errors.

Error
{ "detail": "This key lacks the recruitment.jobs:create scope", "request_id": "5e7250c4-…" }
StatusMeaningWhat to do
401No token, or it's expired, revoked, rotated or not validGet a new token; if that fails, check the key in WebHR
403The key lacks the scope, the add-on is off, or the address isn't on the key's allowlistCheck the key's scopes and IP allowlist
404Not found. Other workspaces' records answer exactly the same way.Check the id
409Conflicts with the current state, such as publishing a job that is already publishedRead the record and decide
422Not valid: an unknown or protected field, a value out of rangeFix the request; don't retry it unchanged
429Over a rate limitWait Retry-After seconds, then retry
5xxOur faultRetry with backoff; send us the request_id if it persists

Rate limits

Retrying safely

Send an Idempotency-Key header (any unique string up to 100 characters, such as a UUID) on every POST. If the network drops and you send the same request with the same key within 24 hours, WebHR answers with the first result instead of acting twice and adds Idempotent-Replayed: true. The same key with a different body answers 422.

Jobs

Careers page

Your public careers page needs no key. These two endpoints answer anyone, so they are limited per visitor address.

CallNotes
GET https://api.webhr.in/api/careers/{workspace}/jobsYour published jobs, as a list. Add page and page_size to page it; the total is in the X-Total-Count header. 120 calls a minute per address.
POST https://api.webhr.in/api/careers/{workspace}/jobs/{job_id}/applyAn application from your site. Send consent: true and the consent_text the applicant agreed to (India's DPDP Act); consent: false is refused. Add a field named contact_me_by_fax_only, hidden with CSS and left empty: bots fill it in and are quietly dropped. 10 applications an hour per address.

Security

Versioning

Version 1 lives at /api/v1. Within it we only add endpoints, fields and values, so write clients that ignore fields they don't know. A change that could break a client gets a new version, /api/v2, with at least 12 months' notice before v1 changes.

Support

Email support@webhr.in with the request_id of the call in question.