Build with the JobMaker API
Manage projects, generate and publish job descriptions, stream Agent updates, and much more — all via a simple HTTP API.
Get API keyAuthentication
API access is available exclusively on the Max plan. See pricing to upgrade.
All requests must include an Authorization header with a Bearer token. API keys are scoped to a workspace and never expire unless revoked.
Base URL + Auth header
Base URL https://api-jobmaker.vercel.app Authorization: Bearer jm_live_xxxxxxxxxxxxxxxxxxxx
Projects
Projects are top-level containers that group related job descriptions (e.g. by department or hiring round).
Job Descriptions
Job descriptions live inside projects and progress through draft → published → archived.
JobMaker Agent
The JobMaker Agent streams content modifications token-by-token as Server-Sent Events (SSE) — avoiding long-poll timeouts and letting you display output in real-time. No WebSocket needed.
/v1/job-descriptions/{id}/aiAgent · SSE · text/event-streamSend a natural-language instruction to the JobMaker Agent. It streams delta events back until the revision is complete.
Request
POST /v1/job-descriptions/jd_10BB/ai
Authorization: Bearer <API_KEY>
Content-Type: application/json
Accept: text/event-stream
{
"instruction": "Make the responsibilities section more concise",
"section": "responsibilities" // optional — omit to apply to whole document
// options: mission | responsibilities | profile
// benefits | about | vision
}Response stream (SSE)
data: {"section":"responsibilities","delta":"Lead the design"}
data: {"section":"responsibilities","delta":" and delivery of"}
data: {"section":"responsibilities","delta":" core platform features."}
data: [DONE]Client — fetch + ReadableStream (browser)
const res = await fetch('/v1/job-descriptions/jd_10BB/ai', {
method: 'POST',
headers: {
'Authorization': 'Bearer jm_live_xxx',
'Content-Type': 'application/json',
'Accept': 'text/event-stream',
},
body: JSON.stringify({ instruction: 'Make it more concise' }),
});
const reader = res.body!.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
for (const line of chunk.split('\n')) {
if (!line.startsWith('data:')) continue;
const payload = line.slice(5).trim();
if (payload === '[DONE]') { reader.cancel(); break; }
const { delta } = JSON.parse(payload);
appendToEditor(delta); // your UI update
}
}Templates
Templates define the structure and default sections of a job description. Pass a templateId when creating a JD to pre-fill its layout.
Themes
Themes control the visual style of the public-facing job description page. Pass a themeId when creating or updating a JD.
Errors
All errors return a consistent JSON body. Use the code field for programmatic handling; message is human-readable.
Error object
{
"error": {
"code": "not_found",
"message": "Job description jd_10BB does not exist.",
"status": 404
}
}| Status | Code |
|---|---|
| 400 | bad_request |
| 401 | unauthorized |
| 403 | forbidden |
| 404 | not_found |
| 409 | conflict |
| 422 | unprocessable |
| 429 | rate_limit_exceeded |
| 500 | server_error |
Rate limits
API access is available on the Max plan. Limits are applied per API key on a rolling 60-second window. When exceeded the API returns 429 with a Retry-After header.
| Plan | Read (GET) | Write | Agent |
|---|---|---|---|
| Max | 300 / min | 100 / min | 30 / min |
Response headers X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset are present on every response.