Employer API v1
Create, update and close remote jobs from your own systems. Fields follow schema.org JobPosting, so your existing markup maps across directly.
Authentication
Send Authorization: Bearer <key> on every request. Keys are issued when you redeem an invitation. A key starting cr_test_ is a sandbox key: it validates your job and reports what would happen, and writes nothing.
Base URL: https://www.caferemote.com/api/v1 (HTTPS only). Machine-readable spec: openapi.json.
Rules
- Fully remote jobs only, in English. Hybrid or on-site wording is rejected.
- Description of at least 300 characters, at most 100 KB.
- An https apply link or an apply email.
-
remote.applicantCountries: ISO alpha-2 codes or"WORLDWIDE". - The first three jobs of a new employer are reviewed by a person.
Endpoints
| Method | Path | Scope | Purpose |
|---|---|---|---|
PUT | /jobs/{externalId} | jobs:write | Create or update (201 or 200) |
POST | /jobs/bulk | jobs:write | Up to 100 jobs in one call |
DELETE | /jobs/{externalId} | jobs:write | Close a job |
GET | /jobs | jobs:read | List your jobs, filter by status |
GET | /jobs/{externalId} | jobs:read | One job and its state |
GET | /taxonomies | key | Valid categories, skills and levels |
GET | /me | key | Your account and key details |
POST | /invites/redeem | public | Exchange an invite token for keys |
GET | /openapi.json | public | OpenAPI 3 specification |
Create or update a job
The same call creates and updates. Repeat it with the same externalId to change a job. Add an Idempotency-Key header to make retries safe for 24 hours.
curl -X PUT https://www.caferemote.com/api/v1/jobs/job-001 \
-H "Authorization: Bearer $KEY" \
-H "Idempotency-Key: abc123" \
-H "Content-Type: application/json" \
-d '{
"externalId": "job-001",
"title": "Senior Engineer",
"description": "<p>At least 300 characters of English text...</p>",
"applyUrl": "https://acme.example/j/1",
"remote": { "type": "TELECOMMUTE", "applicantCountries": ["US", "CA"] }
}'Bulk upload
POST /jobs/bulk takes up to 100 jobs, each shaped like the single-job body. Each job gets its own result, so one bad job does not block the rest.
Close a job
curl -X DELETE https://www.caferemote.com/api/v1/jobs/job-001 \
-H "Authorization: Bearer $KEY"List your jobs
curl "https://www.caferemote.com/api/v1/jobs?status=pending&per_page=50" \
-H "Authorization: Bearer $KEY"Fields
Required: externalId, title, description, remote, and one of applyUrl or applyEmail.
Optional: employmentType, salary (min, max, currency, period), datePosted, validThrough, category, skills, experienceLevel, intro, responsibilities, requirements, niceToHave, benefits (up to 40 items each) and a company block.
Tip: send intro and the list fields. Jobs with a short intro and bullet lists read much better and convert more applicants.
Webhooks
We POST an event to your endpoint when a job changes state: job.approved, job.rejected, job.published, job.expired, job.closed. Retries run after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours.
Headers: X-CafeRemote-Event, X-CafeRemote-Delivery and X-CafeRemote-Signature: t=<unix>,v1=<hex>.
Verify with v1 = HMAC-SHA256(secret, "<t>." + rawBody) and reject timestamps older than 5 minutes.
Errors and limits
Errors use application/problem+json (RFC 9457): 401 bad key, 403 scope, 404 not found, 422 validation with errors or reasons, 426 not https, 429 rate limited with Retry-After.
Limit: 60 requests per minute per key. See X-RateLimit-Limit and X-RateLimit-Remaining on every response.