Developers
Careers API
Integrate SohamRecruit with your own website — read published jobs, accept applications, track candidate status, and receive webhook events.
The Careers API is the integration surface for your branded career site. Use it to list open jobs, submit applications straight into your pipeline, show candidates their status, and get notified of events.
It is intentionally narrow — the careers surface only. It cannot read or write your candidates, clients, or pipeline data. (A general Data API is planned separately.)
Most read endpoints need no authentication. The only credential is the Careers API Key, used server-side to submit applications without a reCAPTCHA challenge. Never put it in browser code.
Base URL https://api.sohamrecruit.com
Authentication
Most read endpoints (listing jobs, the feed, candidate status) need no authentication.
The one credential is the Careers API Key. A company admin generates it under Settings → Careers API Key. Send it as the X-Careers-Api-Key header when submitting applications from your server — a valid key that matches the job’s tenant skips the reCAPTCHA challenge. All other validation (consent, required fields, résumé checks) still applies.
The key is a secret: keep it on your server (e.g. a Cloudflare Pages secret) and never ship it in browser code. It grants no data access beyond application submission. The legacy headers X-Career-Site-Key and X-Partner-Apply-Key are still accepted as aliases.
Quickstart
Two common integrations. The first is a public read you can call from the browser; the second must run on your server so the Careers API Key stays secret.
curl "https://api.sohamrecruit.com/api/jobs/public?tenantId=YOUR_TENANT_ID"const res = await fetch(
'https://api.sohamrecruit.com/api/jobs/public?tenantId=YOUR_TENANT_ID'
)
const { jobs } = await res.json()
jobs.forEach((j) => console.log(j.title, j.location, j.currency))curl -X POST \
"https://api.sohamrecruit.com/api/jobs/public/JOB_ID/apply" \
-H "X-Careers-Api-Key: $CAREERS_API_KEY" \
-F "name=Asha Rao" \
-F "email=asha@example.com" \
-F "phone=+919876543210" \
-F "consent=true" \
-F "resume=@/path/to/resume.pdf"// Runs on YOUR backend. The browser posts the form to you;
// you forward it to SohamRecruit with the secret key.
const form = new FormData()
form.set('name', body.name)
form.set('email', body.email)
form.set('phone', body.phone)
form.set('consent', 'true')
if (body.resume) form.set('resume', body.resume, 'resume.pdf')
const res = await fetch(
`https://api.sohamrecruit.com/api/jobs/public/${jobId}/apply`,
{
method: 'POST',
headers: { 'X-Careers-Api-Key': process.env.CAREERS_API_KEY },
body: form,
},
)
const result = await res.json() // { message, statusUrl }Jobs
/api/jobs/publicNoneList a tenant's open, non-expired jobs (newest first).
- Query: tenantId (uuid) — scope to one tenant (the normal case).
- Returns { jobs: PublicJob[] } with a currency per job.
- Safe to call directly from the browser.
/api/jobs/public/{id}NoneGet a single open job by id.
- Returns { job: PublicJob }, or 404 if not found / not open.
/api/jobs/feed/{tenantId}NoneXML job feed in the LinkedIn/Indeed job-wrapping format.
- application/xml response.
- Rate limit: 30 requests / 5 min / IP.
Applications
/api/jobs/public/{id}/applyCareers API Key or reCAPTCHASubmit a candidate application (multipart/form-data).
- Required fields: name, email, phone, consent. Optional: coverLetter, resume (PDF/DOCX ≤10MB), source.
- consent must be 'true' (GDPR).
- With a valid X-Careers-Api-Key, reCAPTCHA is skipped; otherwise a captchaToken is required.
- 201 → { message, statusUrl }. Errors: 400, 404, 409 (already applied), 429.
Candidate status
/api/status/{token}None (token)Sanitized application status for a candidate.
- The token is emailed to the candidate on apply (see statusUrl).
- Returns companyName, jobTitle, appliedAt, and a 4-step status timeline.
- Never exposes recruiter PII, internal notes, or raw stage names.
Webhooks
Register HTTPS endpoints under Settings → Webhooks to receive signed events. Each delivery is a JSON envelope — { event, tenantId, timestamp, data } — with three headers: X-SohamRecruit-Event, X-SohamRecruit-Signature-256, and X-SohamRecruit-Delivery.
Events: candidate.created, candidate.updated, candidate.stage_changed, placement.created, interview.scheduled, application.received.
Verify the signature (HMAC-SHA256 of the raw request body with your endpoint secret) before trusting a payload. Respond with any 2xx to acknowledge; a non-2xx is retried up to 3 times.
import crypto from 'node:crypto'
function verifySignature(rawBody, header, secret) {
const expected =
'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex')
return crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected))
}Rate limits
Limits are per rolling 5-minute window:
• Public job board reads: 10 requests / 5 min / IP. • Job feed: 30 requests / 5 min / IP. • Apply with a valid Careers API Key: 300 requests / 5 min per tenant. • Apply with a missing/invalid key: 10 requests / 5 min / IP (reCAPTCHA still applies).
A 429 response includes a Retry-After header and a retryAfterSeconds field.
Errors
Errors use a consistent JSON envelope: { "error": "..." } (some also include a human-readable message).
Common status codes: 400 (invalid/missing fields or consent), 404 (not found / invalid token), 409 (duplicate application), 429 (rate limited, with retryAfterSeconds).
Data API — Authentication
The Data API (/api/v1/*) reads and writes your jobs, candidates, applications, and clients. Authenticate with a Data API Key sent as an HTTP Bearer token: Authorization: Bearer sk_live_….
A company admin generates keys under Settings → Data API keys, choosing a scope — read, or read + write. The raw key is shown once; keep it on your server only. Write endpoints (POST / PATCH) require a key with the write scope, otherwise they return 403.
Every key is scoped to your tenant — it can only ever read or write your own data.
Data API — Quickstart
curl "https://api.sohamrecruit.com/api/v1/jobs?status=open" \
-H "Authorization: Bearer $DATA_API_KEY"curl -X POST "https://api.sohamrecruit.com/api/v1/candidates" \
-H "Authorization: Bearer $DATA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Asha Rao","email":"asha@example.com","skills":"React, Node"}'const res = await fetch(
'https://api.sohamrecruit.com/api/v1/applications/' + applicationId,
{
method: 'PATCH',
headers: {
Authorization: 'Bearer ' + process.env.DATA_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ status: 'interview' }),
},
)
const { application } = await res.json()Data API — Reference
All list endpoints accept `limit` (max 100) + `offset` pagination. Endpoints marked "write" need a key with the write scope.
/api/v1/jobsAPI keyList / search jobs (status, q).
/api/v1/jobswriteCreate a job.
/api/v1/jobs/{id}API keyGet a job.
/api/v1/jobs/{id}writeUpdate or close a job.
/api/v1/candidatesAPI keyList / search candidates (q, status).
/api/v1/candidateswriteCreate a candidate (email-deduped).
/api/v1/candidates/{id}API keyGet a candidate.
/api/v1/candidates/{id}writeUpdate a candidate.
/api/v1/applicationsAPI keyList applications (jobId, status).
/api/v1/applications/{id}API keyGet an application.
/api/v1/applications/{id}writeUpdate the application stage.
/api/v1/clientsAPI keyList / search clients (q, status).
/api/v1/clientswriteCreate a client.
/api/v1/clients/{id}API keyGet a client.
/api/v1/clients/{id}writeUpdate a client.
Questions? Contact support