Overview
V1 has three public endpoints. Use /public/generate when you only need a preview. Use /public/jobs when you want CazVid to create a real job record. Use /public/usage to check your remaining daily quota without spending it.
/public/generateincludeDescription: true to include generated job description HTML./public/jobs/public/usageAuthentication
Send your API key with the x-api-key header or as an Authorization: Bearer token. Keys belong to an organization and can be scoped to one or more workspaces. Plaintext keys are shown once when created and stored hash-only by CazVid. Treat keys as secrets: do not put them in frontend code, mobile apps, screenshots, logs, or support messages.
x-api-key: cazvid_jb_...
Authorization: Bearer cazvid_jb_...
Content-Type: application/jsonPreview generated details
Preview calls do not write job records. They return a normalized public DTO that your integration can inspect before creating a draft or publishing.
curl -X POST https://aio-backend-prod.cazvid.app/api/v3.0/job-builder/public/generate \
-H "x-api-key: cazvid_jb_..." \
-H "Content-Type: application/json" \
-d '{
"prompt": "Looking for a remote customer support specialist in Mexico",
"language": "en",
"organizationId": "ORG_ID",
"workspaceId": "WORKSPACE_ID",
"includeDescription": true
}'Create jobs
The jobs endpoint always generates details and description. Screening questions are skipped in v1. Premium and Premium+ jobs remain in-app because they depend on payment flow.
| Field | Type | Required | Description |
|---|---|---|---|
| prompt | string | Required | Plain-language hiring request (1 to 10000 characters), including role, location or remote intent, and useful requirements. |
| language | en | es | nl | pt | Required | Language for generated job details and description. CazVid job surfaces are English and Spanish, so en or es is recommended. |
| organizationId | ObjectId | Optional | Organization that owns the job. Defaults to the API key's organization when omitted. |
| workspaceId | ObjectId | Optional | Workspace where the job should be created. Defaults to the API key's default workspace when omitted. |
| publishMode | draft | publish | Optional | draft (the default) saves an editable job. publish creates a standard job and sends it through CazVid approval. |
Create a draft
curl -X POST https://aio-backend-prod.cazvid.app/api/v3.0/job-builder/public/jobs \
-H "x-api-key: cazvid_jb_..." \
-H "Content-Type: application/json" \
-d '{
"prompt": "Looking for a bilingual customer support specialist in Mexico",
"language": "en",
"organizationId": "ORG_ID",
"workspaceId": "WORKSPACE_ID",
"publishMode": "draft"
}'Publish a standard job
curl -X POST https://aio-backend-prod.cazvid.app/api/v3.0/job-builder/public/jobs \
-H "x-api-key: cazvid_jb_..." \
-H "Content-Type: application/json" \
-d '{
"prompt": "Looking for a bartender in Monterrey",
"language": "en",
"organizationId": "ORG_ID",
"workspaceId": "WORKSPACE_ID",
"publishMode": "publish"
}'Work modes and location
Remote within country
Prompt example: Looking for a remote customer support specialist in Mexico.
Returns workMode.type remote, scope country, countryCode MX, no city coordinates.
Remote worldwide
Prompt example: Looking for a virtual assistant, fully remote worldwide.
Returns workMode.type remote, scope worldwide, and clears country, city, GeoName, and coordinates.
Onsite or hybrid
Prompt example: Looking for a truck driver in Managua.
Returns canonical city data resolved through CazVid location services.
Response shape
Draft and publish responses include the created post id, publish mode, job status, completePost, jobBuilderProgress, and the generated public job DTO. Drafts keep jobBuilderProgress for resuming in-app; publishing clears it to null. Published jobs also include listId when the job list is created (drafts return listId null).
{
"postId": "POST_ID",
"listId": "LIST_ID",
"publishMode": "publish",
"status": "pending",
"completePost": true,
"jobBuilderProgress": null,
"job": {
"title": "Bartender",
"language": "en",
"description": "<p>Generated job description...</p>",
"workMode": {
"type": "onsite",
"scope": null,
"countryCode": "MX",
"countryName": "Mexico",
"city": "Monterrey",
"region": "Nuevo Leon",
"displayName": "Monterrey, Nuevo Leon, Mexico",
"geoNameId": "3995465",
"coordinates": {
"longitude": -100.3161,
"latitude": 25.6866
}
},
"salary": {
"low": 8000,
"recommended": 10000,
"high": 12000,
"period": "monthly",
"currency": "MXN",
"currencySymbol": "MX$",
"negotiable": false,
"additionalCompensation": []
},
"primaryEmploymentType": "fullTime",
"employmentTypes": ["fullTime", "partTime"],
"categories": [
{
"id": "CATEGORY_ID",
"name": "Food Service",
"primary": true
}
],
"education": ["High School Diploma or equivalent"],
"skills": ["Customer service", "Attention to detail"]
}
}Idempotency
Send an optional Idempotency-Key header on POST /public/jobs to make job creation safe to retry. The key is 1 to 255 visible ASCII characters. The same key with the same request body replays the stored response (with an Idempotency-Replayed: true response header) without creating a second job and without consuming quota - the retry must still pass the daily rate limit, so a replay attempted while the organization is at its daily cap returns 429 RATE_LIMIT_EXCEEDED. Replays are available for 24 hours after the original request completes; after that the key behaves as new. The same key with a different body returns 422 IDEMPOTENCY_KEY_REUSED. A concurrent duplicate that arrives while the first is still running returns 409 IDEMPOTENCY_IN_PROGRESS; an unfinished request holds the key for at most 10 minutes, so 409s resolve within that bound. A malformed header returns 400 IDEMPOTENCY_KEY_INVALID. If the idempotency store is unreachable, the request is not processed and returns 503 IDEMPOTENCY_STORE_UNAVAILABLE with the quota slot refunded - retry with the same key.
curl -X POST https://aio-backend-prod.cazvid.app/api/v3.0/job-builder/public/jobs \
-H "x-api-key: cazvid_jb_..." \
-H "Idempotency-Key: 7c9e6a2f-unique-per-job-intent" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Looking for a bartender in Monterrey",
"language": "en",
"organizationId": "ORG_ID",
"workspaceId": "WORKSPACE_ID",
"publishMode": "publish"
}'Check remaining quota
GET /public/usage returns the calling organization's daily Job Builder quota. It uses the same authentication as the other endpoints and does not count against the quota, so you can poll it before a batch to avoid 429 responses. Polling is throttled to 60 requests per minute per API key; exceeding it returns the standard 429 shape with details.period set to minute.
/public/usagecurl https://aio-backend-prod.cazvid.app/api/v3.0/job-builder/public/usage \
-H "x-api-key: cazvid_jb_..."| Field | Type | Description |
|---|---|---|
| dailyQuota | number | Total successful calls allowed per organization per UTC day. |
| used | number | Quota-consuming API calls made with this organization's API keys today (UTC). |
| remaining | number | Successful calls left before the quota resets. |
| resetsAt | string (ISO 8601) | ISO 8601 timestamp of the next UTC midnight, when the quota resets. |
| period | "utc_day" | Quota window. Always utc_day in v1. |
{
"dailyQuota": 10,
"used": 3,
"remaining": 7,
"resetsAt": "2026-07-07T00:00:00.000Z",
"period": "utc_day"
}Errors
Error responses use stable errorCode values so integrations do not need to parse prose messages. Every error echoes the request path; 429 responses add retryAfter, the number of seconds until the UTC day resets.
| Status | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | Request body failed validation. |
| 400 | IDEMPOTENCY_KEY_INVALID | The Idempotency-Key header is malformed (it must be 1 to 255 visible ASCII characters). |
| 401 | API_KEY_MISSING | No API key was sent. |
| 401 | API_KEY_INVALID | The key does not exist or cannot be verified. |
| 401 | API_KEY_EXPIRED | The key is past its expiry date. |
| 401 | API_KEY_REVOKED | The key was revoked. |
| 403 | ORG_ACCESS_DENIED | The key cannot access this organization. |
| 403 | WORKSPACE_ACCESS_DENIED | The key cannot access this workspace. |
| 403 | PLAN_REQUIRED | Production API access requires a Platinum plan or higher. |
| 409 | IDEMPOTENCY_IN_PROGRESS | A request with the same Idempotency-Key is still being processed. Retry once it completes. |
| 422 | IDEMPOTENCY_KEY_REUSED | The Idempotency-Key was already used with a different request body. |
| 429 | RATE_LIMIT_EXCEEDED | The org reached its daily successful-call quota. |
| 503 | IDEMPOTENCY_STORE_UNAVAILABLE | Idempotency could not be verified, so nothing was created. Retry with the same key. |
{
"statusCode": 429,
"errorCode": "RATE_LIMIT_EXCEEDED",
"message": "Daily Job Builder API quota exceeded.",
"details": {
"limit": 10,
"period": "utc_day"
},
"retryAfter": 21600,
"path": "/api/v3.0/job-builder/public/jobs"
}Limits and behavior
- V1 quota is 10 successful
generateorjobscalls per organization per UTC day. publishMode: "publish"creates standard jobs only. Premium and Premium+ remain in-app for v1.- Published jobs enter the existing CazVid pending and approval pipeline. The API does not directly mark jobs as approved.
- Rotate keys by creating a new key, updating your integration, then revoking the old key.
Also using the Candidate Search API? Review its acceptable-use terms.
Use from an agent (MCP)
Prefer to drive Job Builder from an AI agent instead of raw HTTP? The CazVid MCP server exposes preview_job and create_job (plus list_api_usage) to Claude Code, Claude.ai, ChatGPT, Cursor, and VS Code, using this same API key and daily quota.