Jobs
GET /api/v1/jobs returns the jobs in your workspace a page at a time, and GET /api/v1/jobs/{id} returns one, with every parameter and field.
Overview
GET /api/v1/jobs lists the jobs in your workspace, and GET /api/v1/jobs/{id} returns one of them. You get the jobs you can see in the app, minus any team your key's team access leaves out. Both need the Read permission.
Authentication, Errors and Rate limits cover what every operation shares. This page covers the parameters and the fields.
Request
curl "https://attia.app/api/v1/jobs?limit=50" \ -H "Authorization: Bearer $ATTIA_API_KEY"All four query parameters are optional.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
limit | integer, 1 to 100 | 25 | How many jobs to return |
cursor | string | none | The next_cursor of the previous page |
updated_since | RFC 3339 timestamp | none | Only jobs updated at or after this time |
include_archived | true or false | false | Also return archived jobs |
A parameter outside this table gets a 400 with the code invalid-request. So does a parameter sent twice.
Response
The answer holds the jobs in data, sorted by updated_at and then id, oldest change first. next_cursor is a string when more jobs exist and null on the last page.
{ "data": [ { "id": "0192f3a1-6b02-7d4c-8e11-5a9c0b7d3e01", "title": "Backend developer", "slug": "backend-developer", "status": "live", "publish_status": "published", "team_id": "0192f39f-11aa-7c3e-b2d4-9e8f7a6b5c4d", "employment_type": "full_time", "contract_type": "permanent", "workplace_type": "hybrid", "locations": ["Eksempelvik"], "positions_count": 2, "application_deadline": "2026-11-15", "published_at": "2026-09-28T07:30:00.000000Z", "closed_at": null, "archived_at": null, "created_at": "2026-09-25T12:04:51.220417Z", "updated_at": "2026-10-01T09:42:10.118305Z" } ], "next_cursor": null}| Field | Type | Meaning |
|---|---|---|
id | UUID | The job's id. It never changes |
title | string | The job title |
slug | string | The job's name in its URL, unique in the workspace |
status | enum | draft, live, paused or closed. Whether candidates can apply, which the app calls Publish. See Job status |
publish_status | enum | unpublished, scheduled or published. The job's status in the app. A scheduled job goes out at its publish time, and an unpublished job with a closed_at was published before |
team_id | UUID | The team that owns the job |
employment_type | enum | full_time or part_time |
contract_type | enum | permanent, temporary, fixed_contract, seasonal, project, trainee, apprenticeship, self_employed or agency |
workplace_type | enum | remote, hybrid or onsite |
locations | list of strings | The places the job names. Empty when it names none |
positions_count | integer | How many people the job hires, at least 1 |
application_deadline | date or null | The last day to apply, YYYY-MM-DD |
published_at | timestamp or null | When the job went live |
closed_at | timestamp or null | When the job was last unpublished. null while it is scheduled or published |
archived_at | timestamp or null | When the job was archived |
created_at | timestamp | When the job was created |
updated_at | timestamp | When the job last changed |
An enum can gain a value in version 1, so handle one you do not know. Timestamps, nulls and enums describes each format.
Page through every job
Ask for a page, then send next_cursor back as cursor until it is null.
curl "https://attia.app/api/v1/jobs?limit=100&cursor=eyJ1IjoiMjAyNi0xMC0wMlQwODoxNTozMC40ODI5MTNaIiwiaSI6IjAxOTJmM2ExLTdjNDQtN2IxZS05YTUwLTNmMWQyYzZlOGEwMiJ9" \ -H "Authorization: Bearer $ATTIA_API_KEY"The cursor stays stable while people edit jobs. A job edited during your read moves behind the cursor, and you may see it again on a later page. Keep the latest copy per id. Pagination explains the sort order.
Poll for changes
updated_since is inclusive. Send a time five minutes before the largest updated_at you have stored. A change gets its updated_at when the save starts, so it can turn up with a time older than one you already read. The answer repeats jobs you already have, so drop the repeats by id. With 2026-10-01T09:42:10.118305Z as the largest, the call is this.
curl "https://attia.app/api/v1/jobs?updated_since=2026-10-01T09:37:10.118305Z" \ -H "Authorization: Bearer $ATTIA_API_KEY"You can combine updated_since with cursor and limit when one poll returns more than a page.
Archived jobs
The list leaves archived jobs out unless you ask for them. That matters when you keep a copy. A job that someone archives stops appearing in the default list, and your copy never learns why. Send include_archived=true when you poll, and an archived job comes back with a time in archived_at.
curl "https://attia.app/api/v1/jobs?include_archived=true&updated_since=2026-10-01T00:00:00Z" \ -H "Authorization: Bearer $ATTIA_API_KEY"Get one job
GET /api/v1/jobs/{id} returns the job with that id. It takes no query parameters, so one gets a 400 with the code invalid-request.
curl "https://attia.app/api/v1/jobs/0192f3a1-6b02-7d4c-8e11-5a9c0b7d3e01" \ -H "Authorization: Bearer $ATTIA_API_KEY"The answer holds the job in data, with the same fields as a job in the list. An archived job comes back too, with a time in archived_at.
{ "data": { "id": "0192f3a1-6b02-7d4c-8e11-5a9c0b7d3e01", "title": "Backend developer", "slug": "backend-developer", "status": "live", "publish_status": "published", "team_id": "0192f39f-11aa-7c3e-b2d4-9e8f7a6b5c4d", "employment_type": "full_time", "contract_type": "permanent", "workplace_type": "hybrid", "locations": ["Eksempelvik"], "positions_count": 2, "application_deadline": "2026-11-15", "published_at": "2026-09-28T07:30:00.000000Z", "closed_at": null, "archived_at": null, "created_at": "2026-09-25T12:04:51.220417Z", "updated_at": "2026-10-01T09:42:10.118305Z" }}A 404 with the code not-found means no job your key can see has that id. The job may not exist, may be deleted, may belong to another workspace, or may sit in a team the list leaves out for you. Every one of these gets the same answer, so a 404 never tells you whether the job exists. An id that is not a UUID gets the same 404.