List jobs
GET /api/v1/jobs returns the jobs in your workspace, a page at a time, with every parameter and field.
Overview
GET /api/v1/jobs lists the jobs in your workspace. You get the jobs you can see in the app, minus any team your key's team access leaves out. The key needs the Read permission.
The Attia API covers keys, errors and rate limits. 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", "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 |
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 closed |
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.
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.
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"