API reference
Version 1.0. JSON over HTTPS. Reading live listings needs no key; managing your own listings needs one from your dashboard.
Authentication
curl https://jobs.co.nz/api/v1/me \
-H "Authorization: Bearer jcnz_your_key_here"
Keys carry read or read write. A key inherits the
account's standing: if posting is blocked in the dashboard — unverified, over quota,
revoked — the API returns 403 with the same reason.
Endpoints
| Method & path | Key | What it does |
|---|---|---|
GET /api/v1/jobs | — | Search live listings |
GET /api/v1/jobs/{id} | — | One live listing |
GET /api/v1/meta | — | Valid values for every enumerated field |
GET /api/v1/me | read | Account, quota and credits |
GET /api/v1/employer/jobs | read | Your listings, any status |
POST /api/v1/employer/jobs | write | Create a listing |
PATCH /api/v1/employer/jobs/{id} | write | Update a listing |
POST /api/v1/employer/jobs/{id}/close | write | Take a listing down |
GET /api/v1/employer/jobs/{id}/applications | read | Applications to your listing |
Creating a listing
curl -X POST https://jobs.co.nz/api/v1/employer/jobs \
-H "Authorization: Bearer jcnz_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"title": "Registered Nurse — Emergency Department",
"description": "At least eighty characters describing the role…",
"category": "Healthcare & Medical",
"region": "Wellington",
"salary_min": 78000,
"salary_max": 92000
}'
A new employer's first listing returns 201 with
status: "pending_review" — every employer's first listing is read by a
moderator, through the API as much as through the site.
Job fields
Generated from the schema the server validates against, so this table can't describe a rule the API doesn't enforce.
| Field | Type | Rules |
|---|---|---|
title required |
str | min 3 chars. max 140 chars. Role title as candidates will see it. |
description required |
str | min 80 chars. max 20000 chars. Plain text. The first two lines show in search results. |
category required |
str | One of: Accounting & Finance, Administration, Agriculture & Fishing, Construction & Trades, Education & Training, Engineering … (18 values, see /api/v1/meta).
|
region required |
str | One of: Northland, Auckland, Waikato, Bay of Plenty, Gisborne, Hawke's Bay … (16 values, see /api/v1/meta).
|
town |
str | max 80 chars. Defaults to .
|
employment_type |
str | One of: full-time, part-time, fixed-term, contract, casual, internship. Defaults to full-time.
|
work_mode |
str | One of: onsite, hybrid, remote. Defaults to onsite.
|
salary_min |
int | min 0. max 10000000. |
salary_max |
int | min 0. max 10000000. |
salary_period |
str | One of: year, hour. Defaults to year.
|
salary_visible |
bool | Defaults to True.
Show the salary on the listing. Roles that do rank higher.
|
apply_mode |
str | One of: internal, external, email. Defaults to internal.
|
apply_target |
str | max 300 chars. Defaults to .
Required for apply_mode external (URL) or email (address).
|
Unknown fields are rejected rather than ignored, and no value is
coerced: "salary_min": "80000" is a string and will be refused, because
silently accepting it is how a serialiser bug reaches the database.
Errors
{
"error": {
"code": "validation_failed",
"message": "Some fields are invalid.",
"errors": [
{"field": "region", "message": "must be one of: Northland, Auckland, …"},
{"field": "salary_max", "message": "must be at least salary_min"}
]
}
}
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_query / invalid_json | Malformed request |
| 401 | unauthorized | No key, or an unknown/revoked one |
| 403 | forbidden / not_permitted | Wrong scope, or the account can't post |
| 404 | not_found | No such listing, or not yours |
| 409 | identity_locked | Title/category/region locked after publication |
| 413 | payload_too_large | Body over 64 KB (measured on the body, not the Content-Length header) |
| 415 | unsupported_media_type | Missing Content-Type: application/json |
| 422 | validation_failed | Fields failed validation — see errors |
| 429 | rate_limited | Over the limit — see Retry-After |
Every error names the field where there is one, and all failures are reported together rather than one per round trip.
Rate limits
| Caller | Limit | Metered by |
|---|---|---|
| No key | 120 / 60s | IP |
| Key, reading | 600 / 60s | key |
| Key, writing | 60 / 60s | account |
Writes get the smallest budget because they change what everyone
else reads, and they are metered per account — minting extra keys doesn't buy
more write throughput. Reads are metered per key, so two integrations on one account
don't starve each other. Every response carries X-RateLimit-Limit,
X-RateLimit-Window and X-RateLimit-Scope.