Skip to main content

Connect Recooty to your own systems with the Recooty API

The Recooty API lets your own website, HR system, or automation tool talk to Recooty directly — no manual copy-paste, no CSV imports.

Written by Khushi Punjabi

The Recooty API lets your own website, HR system, or automation tool talk to Recooty directly — no manual copy-paste, no CSV imports.

With it you can:

  • Show your live jobs anywhere — on your own website, intranet, or a partner's job board.

  • Create and update jobs from another system — an ATS, an ERP, a spreadsheet-driven workflow, or an automation tool like Power Automate, Zapier, or Make.

  • Receive applications from your own custom form and have them land in Recooty exactly as if the candidate applied on your careers page.

  • Pull candidate details — including screening answers and Recooty's AI resume insights — into your own dashboards.

  • Keep locations and departments in sync so jobs created by machine are filed in the right place.

Everything lives on one page in Recooty: Settings → Integrations → API.

Who this article is for. The first half ("Before you start", "Your two credentials", "Usage, credits and limits") is written for anyone. The per-API sections include the exact requests a developer needs. If you're handing this to a developer, they can start at Jobs API.

In this article:

BEFORE YOU START

1. Your plan must include API Access

The API is a paid feature. If API Access isn't on your plan, you'll see an upgrade prompt when you try to create a token, and every token-based API call returns:

{ "message": "Feature not available to your plan" }

with HTTP status 402 Payment Required.

One important exception: the three job listing endpoints (the ones that use your API key) are not plan-gated. They keep working on any plan, because they're what powers careers page feeds and the jobs widget. Everything else — creating jobs, receiving applications, reading candidates, locations, departments — requires API Access.

2. You need the right permission

What you want to do

Permission needed

See the API page and your API key

API and documentation

Create or revoke access tokens

Tokens

If you don't have the Tokens permission, the page still shows your API key and the full documentation, but instead of the token list you'll see:

You do not have permission to create or revoke API tokens. Ask a workspace admin to either grant you the permission or create the token for you.

3. Find your credentials

Go to Settings → Integrations → API. The first card, API Key & Access Tokens, holds both credentials.

YOUR TWO CREDENTIALS

Recooty uses two different credentials, and picking the wrong one is the single most common integration mistake. Every endpoint in the app is tagged so you can tell at a glance.

API key

Access token

Tag in the app

REQUIRES API KEY

REQUIRES TOKEN

What it is

One permanent key per workspace

A personal access token you create yourself

Where it goes

Already built into the URL

Authorization: Bearer <ACCESS_TOKEN> header

Can read

Published (open) jobs only

Everything your plan allows

Can write

Nothing

Jobs, applications, locations

Expires

No

1 year after it's created

Safe in front-end code?

Yes — it only exposes jobs you've already published

No — never

The API key

Your API key is shown at the top of the API page. You don't need to paste it anywhere: Recooty has already embedded it into every URL and code sample on the page tagged REQUIRES API KEY. Copy the request as shown and it works.

The API key only ever returns jobs you have already published publicly, so it is safe to use in browser JavaScript or a public widget.

Access tokens

Everything that writes data or reads candidate information needs a personal access token.

To create one:

  1. Go to Settings → Integrations → API.

  2. Click Create Token (top-right of the API Key & Access Tokens card).

  3. Give it a name that says where it will be used — Website careers form, Power Automate sync, Staging.

  4. Click Create.

  5. Copy the token immediately. It is shown once and never again.

If you lose a token, you can't recover it — revoke it and create a new one.

To revoke one: click Revoke next to the token. It stops working immediately, and any integration using it starts failing with 401.

Good practice:

  • One token per integration. If one leaks, you revoke just that one.

  • Tokens expire one year after creation — the expiry date is shown on the token card. Diary a renewal a few weeks before.

  • Never put a token in front-end JavaScript, a mobile app, or a public repository. Anyone holding it can read every candidate in your workspace.

  • Tokens are tied to the workspace (team) they were created in. A token can never see another workspace's data.

THE BASICS EVERY REQUEST FOLLOWS

Base URL

<API_BASE_URL>/api/v1/

The exact base URL for your account is shown on the API page — copy it from there.

Headers

Accept: application/json Authorization: Bearer <ACCESS_TOKEN>   ← only for REQUIRES TOKEN endpoints Content-Type: application/json          ← when you send a JSON body

Responses are always JSON, with the data wrapped under a named key (job, jobs, location, applications, …).

Errors are always JSON with a message, plus an errors object when a field failed validation:

{     "message": "The title field is required.",     "errors": { "title": ["The title field is required."] } }

Two kinds of ID appear throughout:

Job ID

Application ID

Looks like

01JQ8Z0M2K7X… (a ULID)

7bd025e9c2

Where it comes from

id in any job response

application_id in any application response

Location and department IDs are ordinary numbers (12, 3).

Rate limits: Recooty does not currently apply a published per-minute limit to these endpoints. Build your integration to pause and retry if it ever receives a 429, and avoid tight polling loops — see Integration recipes.

USAGE, CREDITS AND LIMITS

This is the part most integrations get surprised by, so it's worth reading even if you're not technical.

Three things on your plan can be used up. When any of them runs out, the API replies 402 with a plain-English message — it does not silently do half the work.

Resource

What consumes it

What frees it

Jobs

Each job that is Open or Internal

Closing a job

Locations

Each location that exists

Deleting a location

Application view credits

The first time an application's full details are viewed

Nothing — credits refresh with your plan

How job credits actually work

  • A job saved as DRAFT costs nothing.

  • The moment it becomes Open or Internal, it uses one job credit.

  • Closing a job gives the credit back.

  • If you're at your limit and try to publish, you get 402 and the job is not created at all — the whole operation is rolled back, so you won't find a stray draft afterwards.

How location credits work

  • Every location row counts, whether or not a job uses it.

  • Creating one over the limit returns 402 and creates nothing.

  • There is no "find or create" — every POST /locations makes a brand-new row. If your automation calls it on every sync, you will build up duplicates and eventually hit 402. Store the location ID you get back and reuse it.

How application view credits work

This one is genuinely useful to understand:

Call

Costs a credit?

Returns contact details?

GET /jobs/{job_id}/applications (the list)

No

No — names and status only

GET /applications/{application_id} (the detail)

Yes, first time only

Yes — email, phone, resume, AI insights

Same detail call again, later

No

Yes

Applications you submitted through the API

No, ever

Yes

So you can poll the list endpoint as often as you like for free, and only spend a credit when you actually open a candidate.

The last row is worth repeating: an application your own form submitted through POST /jobs/{job_id}/applications is already marked as viewed, at no charge. You already had the candidate's details when you sent them, so Recooty doesn't charge you to read them back.

When credits run out:

{     "message": "You have reached your application view credit limit. Please upgrade your plan to continue." }

Important: running out of view credits does not stop applications arriving. Candidates can still apply, the applications are still stored, and the list endpoint still works. You just can't open new ones until you upgrade or your credits refresh.

JOBS API

Everything to do with job postings: reading the jobs you've published, looking one up, and creating or updating jobs from another system.

When you'd use it

  • Put your jobs on your own website — your web team renders the live list from the feed, styled however they like.

  • Feed a partner site or internal portal with your open roles.

  • Keep Recooty in sync with your ATS or HR system — when a requisition opens over there, the job appears in Recooty automatically; when it's filled, the job closes.

  • Avoid duplicates by checking whether a job code already exists before creating it.

The endpoints

What it does

Request

Credential

Status

List published jobs

GET /api/v1/jobs/<API_KEY>

API key

Stable

Retrieve one job

GET /api/v1/jobs/<API_KEY>/<JOB_ID>

API key

Stable

Find a job by job code

GET /api/v1/jobs/<API_KEY>?code=<JOB_CODE>

API key

Stable

Create a job

POST /api/v1/jobs

Access token

Beta

Update a job

PATCH /api/v1/jobs/<JOB_ID>

Access token

Beta

About the Beta tag. Create and update work today and are used in production integrations, but the response shape may still gain fields. Nothing will be removed without notice. Build against them, and let us know what you're using them for.

How to use it

  1. List your published jobs — no token needed, key already in the URL:

    curl --request GET \   --url <API_BASE_URL>/api/v1/jobs/<API_KEY> \   --header 'Accept: application/json'
    {     "company": "TechFlow Solutions",     "job_count": 3,     "jobs": [         {             "id": "7f8a9b2c3d4e5f6a7b8c9d0e1f2a3b4c",             "title": "Senior Frontend Developer",             "jobcode": "TF001",             "description": "<strong>Job Responsibilities</strong>…",             "city": "San Francisco",             "state": "California",             "country": "United States",             "zip": "94105",             "date": "2024-01-15 09:30:45",             "industry": "Technology",             "employment_type": "Full Time",             "remote": "Hybrid",             "experience": "Mid Level",             "details_url_external": "https://careers.example.com/techflow/senior-frontend",             "apply_url_external": "https://careers.example.com/techflow/senior-frontend/apply"         }     ] }

    details_url_external and apply_url_external are ready-made links to your Recooty careers page — the simplest way to build a job list on your own site is to render the titles and point them at these URLs.

  2. Check whether a job already exists, before creating it:

    curl --request GET \   --url '<API_BASE_URL>/api/v1/jobs/<API_KEY>?code=REQ-10432' \   --header 'Accept: application/json'

    job_count: 0 means it doesn't exist yet → create it. job_count: 1 means it does → take jobs[0].id and update it instead.

  3. Create a job:

    curl --request POST \   --url <API_BASE_URL>/api/v1/jobs \   --header 'Accept: application/json' \   --header 'Authorization: Bearer <ACCESS_TOKEN>' \   --header 'Content-Type: application/json' \   --data '{     "title": "Software Engineer",     "code": "ENG-001",     "description": "<p>We are hiring a software engineer…</p>",     "location_id": 1,     "department_id": 1,     "location_type": "REMOTE",     "experience_required": "MID_SENIOR",     "employment_type": "FULL_TIME",     "resume_required": true,     "status": "CAREER_PAGE"   }'

    Returns 201 with the new job, including the id you'll use for every future update.

    Fields on create:

Field

Required

Notes

title

Yes

Max 512 characters

code

Yes

Max 24 characters, letters/numbers/hyphens/underscores only, unique within your workspace

description

Yes

Minimum 30 words. HTML allowed and cleaned server-side

location_id

Yes

Must be one of your locations — get it from the Locations API

location_type

Yes

ON_SITE, HYBRID, REMOTE

experience_required

Yes

INTERNSHIP, ENTRY_LEVEL, ASSOCIATE, MID_SENIOR, VICE_PRESIDENT, PRESIDENT

employment_type

Yes

FULL_TIME, PART_TIME, CONTRACTOR, INTERN, OTHER

resume_required

Yes

true / false

status

Yes

DRAFT, CAREER_PAGE, JOB_BOARDS

department_id

No

Must be one of your departments

industry_type

No

Free text

min_pay / max_pay

No

If you send one you must send both, and min_pay must be less than max_pay

pay_interval

With pay

HOUR, DAY, WEEK, MONTH, YEAR

pay_currency

With pay

ISO code — USD, GBP, EUR, INR, …

fields

No

Screening questions — see below

Publishing is controlled by status:

You send

What happens

DRAFT

Saved privately in Recooty. Uses no job credit. Nobody can see it

CAREER_PAGE

Goes live on your Recooty careers page. Uses one job credit

JOB_BOARDS

Goes live and is submitted to job boards for approval. Uses one job credit

  1. Update a job — send only the fields you're changing:

    curl --request PATCH \   --url <API_BASE_URL>/api/v1/jobs/<JOB_ID> \   --header 'Accept: application/json' \   --header 'Authorization: Bearer <ACCESS_TOKEN>' \   --header 'Content-Type: application/json' \   --data '{ "status": "CLOSED" }'

    Status changes follow strict rules. Anything not in this table returns 409:

Current status

Can change to

Draft

CAREER_PAGE, JOB_BOARDS

Open

CLOSED, INTERNAL

Internal

CLOSED

Closed

(nothing — closed is final via the API)

Notes / what to keep in mind

  • Job code is your anchor. It's unique per workspace and searchable, so use your own system's reference number as the code. That single field is what lets an automation decide "update the existing job" instead of creating a duplicate every run. You don't need any custom fields to track the link.

  • The single-job lookup only returns open jobs. GET /jobs/<API_KEY>/<JOB_ID> returns 404 for a draft, internal, or closed job. If you need a job in any status, use the job-code lookup instead — that one searches everything.

  • The plain list only shows open jobs too. Drafts, internal and closed jobs never appear in the public feed. That's deliberate: it's a public endpoint.

  • Job codes look different in different responses. The API-key lookups return it as jobcode; create and update return it as code. Same value, legacy naming.

  • Descriptions must be at least 30 words. Short placeholder text will be rejected with 422. This protects your job board distribution — most boards reject thin descriptions.

  • Editing an approved job's title or description queues a re-approval. If the job is already approved on job boards, your edit is parked rather than applied. The response includes "pending_reapproval": true, and the live posting keeps the old text until an admin approves. Your API call still succeeds.

  • Screening questions can only be set when the job is created. Sending fields or resume_required on an update is rejected with 422 and the message "Screening questions cannot be updated through this endpoint." Change them in the Recooty UI.

  • Jobs are never deleted, only closed. There is no delete endpoint by design — closing preserves the applications attached to the job.

  • Closed jobs can't be reopened via the API in this version. Reopen it in the Recooty UI, or create a new job.

  • There are no job webhooks yet. To detect changes, use the job-code lookup on a schedule rather than polling constantly.

Screening questions (fields, optional on create):

"fields": [   { "field_name": "Years of React experience", "field_type": "NUMBER", "is_required": true },   { "field_name": "Preferred location", "field_type": "DROP_DOWN", "is_required": true,     "data": ["London", "Remote"] },   { "field_name": "Do you need visa sponsorship?", "field_type": "TOGGLE",     "is_required": true, "auto_reject": true } ]

field_type accepts TEXT, TEXT_AREA, DROP_DOWN, CHECK_BOX, RADIO, NUMBER, DATE, FILE, URL, TOGGLE, BOOLEAN, INFORMATION. data (the list of options) is required for DROP_DOWN, CHECK_BOX and RADIO. auto_reject only works on TOGGLE fields, whose options are fixed to Yes/No.

Troubleshooting

Symptom

Most likely cause

Fix

Job list is empty but you have jobs

None are Open — they're drafts, internal, or closed

Publish one, or use the ?code= lookup

A job you can see in Recooty returns 404 from the single-job lookup

That endpoint only serves open jobs

Use ?code= instead

422 on code

A job with that code already exists in your workspace

Look it up by code and update it instead of creating

422 on description

Fewer than 30 words

Expand the description

422 on location_id

The location belongs to a different workspace, or was deleted

Call GET /locations and use an ID from there

422 on pay_interval/pay_currency

You sent min_pay/max_pay without them

Send all four, or none

409 on a status change

Not an allowed transition

Check the transition table above

402 when publishing

You're at your active-job limit

Close a job you don't need, or upgrade

Job created but title change didn't appear

It's queued for job-board re-approval

Check pending_reapproval in the response; an admin approves it

CANDIDATES API

What it is

The candidate side: sending applications into Recooty from your own form, listing who applied, and opening a candidate's full profile including Recooty's AI resume insights.

When you'd use it

  • You built your own application form — on your website, in a chatbot, inside your intranet — and want the submissions to land in Recooty's pipeline exactly like careers-page applications.

  • You want applicant counts on an internal dashboard without giving people Recooty logins.

  • You're piping candidate data into a BI tool, a background-check vendor, or your HRIS.

The endpoints

What it does

Request

Credential

Submit an application

POST /api/v1/jobs/<JOB_ID>/applications

Access token

List a job's applications

GET /api/v1/jobs/<JOB_ID>/applications

Access token

View one application in full

GET /api/v1/applications/<APPLICATION_ID>

Access token

Note on the submit URL. Older integrations use the singular /application. It still works, but it's deprecated and its responses now carry a Deprecation: true header. Move to the plural /applications when you next touch the code.

How to use it

  1. Submit an application. The body must be multipart/form-data because it carries a CV file:

    curl --request POST \   --url <API_BASE_URL>/api/v1/jobs/<JOB_ID>/applications \   --header 'Accept: application/json' \   --header 'Authorization: Bearer <ACCESS_TOKEN>' \   --header 'Content-Type: multipart/form-data' \   --form 'first_name=John' \   --form 'last_name=Doe' \   --form '[email protected]' \   --form 'mobile_number=9999999999' \   --form 'resume=@/path/to/resume.pdf'

Field

Required

Rules

first_name

Yes

2–512 characters

last_name

Yes

2–512 characters

email

Yes

Valid email address

mobile_number

Yes

Also accepted as phone_number

resume

Yes

PDF, DOC or DOCX only

The response returns the new application_id — store it if you want to fetch the candidate later.

  1. List a job's applications (free, no contact details):

    curl --request GET \   --url <API_BASE_URL>/api/v1/jobs/<JOB_ID>/applications \   --header 'Accept: application/json' \   --header 'Authorization: Bearer <ACCESS_TOKEN>'

    Returns 10 per page, newest first. Follow next_page_url, or add ?page=2.

  2. Open one candidate (costs one view credit the first time):

    curl --request GET \   --url <API_BASE_URL>/api/v1/applications/<APPLICATION_ID> \   --header 'Accept: application/json' \   --header 'Authorization: Bearer <ACCESS_TOKEN>'

    This returns everything: contact details, resume link, answers to your screening questions, current pipeline stage, and an ai_insights block:

    "ai_insights": {   "parse_status": "PARSED",   "score": 78,   "pros": ["Relevant experience in a similar role."],   "cons": ["No exposure to one of the required reporting tools."],   "resume": { "personal_info": {}, "experience": [], "education": [], "skills": [] } }

    parse_status tells you what state the AI analysis is in:

Value

Meaning

Should you poll again?

UNPARSED

Not started

Yes, shortly

PROCESSING

Being analysed right now

Yes — this will change on its own

PARSED

Done — score, pros, cons, resume are populated

No

FAILED

Couldn't be analysed (unreadable or image-only CV)

No — it won't change

CANCELED

Analysis was stopped

No

resume is null — not an empty skeleton — until parsing finishes, so "no data yet" is never confused with "a CV with nothing in it".

Notes / what to keep in mind

  • Submitting an application doesn't spend a view credit, and never will for that application. Recooty marks it as already seen, since you supplied the data.

  • The list endpoint is free and contains no personal contact details — just names, dates and stage. Poll it as much as you like; spend a credit only when you open someone.

  • Once you've opened a candidate, opening them again is free. Credits are charged per candidate, not per request.

  • One application per email address per job. A second submission with the same email returns 409. This is a deliberate anti-duplicate guard, not an error in your code — treat 409 as "already applied" and move on.

  • You can only apply to jobs that are open or internal. A closed or draft job returns 410.

  • CV file types are strictly PDF, DOC and DOCX. Images, ZIPs and plain text are rejected with 422.

  • AI insights are machine-generated. The score, pros and cons come from Recooty's model, not a human recruiter. If you display them, label them as AI output so your hiring managers don't mistake them for a colleague's assessment.

  • AI insights arrive after the application does. Right after submission the status will usually be PROCESSING. Don't build a flow that assumes the score is there immediately.

  • A token can only reach its own workspace's jobs. Requesting a job from another workspace returns 401.

Troubleshooting

Symptom

Most likely cause

Fix

409 Duplicate Application already in the system

That email already applied to this job

Expected behaviour — show the candidate a friendly "you've already applied" message

410 The job is expired or no longer available

The job is closed or still a draft

Check the job's status before showing your form

422 on resume

Wrong file type, or the file didn't reach the server

Restrict your upload control to .pdf, .doc, .docx, and confirm you're sending multipart/form-data

422 on mobile_number

Field missing entirely

Send mobile_number (or phone_number) — it's required

402 when opening a candidate

View credits exhausted

Upgrade, or wait for credits to refresh. Applications are still arriving safely

ai_insights.score is null

Analysis still running, or the CV couldn't be read

Check parse_status — poll on PROCESSING, stop on FAILED

401 on every call

Token expired, revoked, or copied incorrectly

Tokens last one year. Create a new one and update your integration

Applications arrive but with no screening answers

The job's screening questions weren't included in your submission

Screening answers are optional in the API; send them if your own form collects them

LOCATIONS API

Locations are the addresses your jobs are attached to. Every job needs one. This API lists them, creates new ones, and edits existing ones.

When you'd use it

Almost always as a supporting step for the Jobs API: before you can create a job from another system, you need a location_id.

  • Look up the ID of a location you already have in Recooty.

  • Create a new office when you open one, so jobs can be filed against it.

  • Correct an address that changed.

The endpoints

What it does

Request

Credential

Status

List your locations

GET /api/v1/locations

Access token

Beta

Create a location

POST /api/v1/locations

Access token

Beta

Update a location

PATCH /api/v1/locations/<LOCATION_ID>

Access token

Beta

How to use it

  1. List what you already have (25 per page):

    curl --request GET \   --url <API_BASE_URL>/api/v1/locations \   --header 'Accept: application/json' \   --header 'Authorization: Bearer <ACCESS_TOKEN>'
    {     "locations": {         "data": [             {                 "id": 1,                 "name": "Headquarters",                 "address": "123 Main Street",                 "city": "San Francisco",                 "state": "California",                 "country": "United States",                 "country_code": "US",                 "zip_code": "94105",                 "is_default": true             }         ]     } }

    Take the id and use it as location_id when creating a job.

  2. Create one only if it doesn't exist:

    curl --request POST \   --url <API_BASE_URL>/api/v1/locations \   --header 'Accept: application/json' \   --header 'Authorization: Bearer <ACCESS_TOKEN>' \   --header 'Content-Type: application/json' \   --data '{     "name": "Headquarters",     "address": "123 Main Street",     "city": "San Francisco",     "state": "California",     "country": "United States",     "country_code": "US",     "zip_code": "94105"   }'

    Every field is individually optional, but you must send at least one of name, city or address. If you leave name out, Recooty builds one from city, state (or the address). country_code must be exactly two letters. zip_code is also accepted as zip.

  3. Update one:

    curl --request PATCH \   --url <API_BASE_URL>/api/v1/locations/<LOCATION_ID> \   --header 'Accept: application/json' \   --header 'Authorization: Bearer <ACCESS_TOKEN>' \   --header 'Content-Type: application/json' \   --data '{ "address": "500 Market Street", "zip_code": "94103" }'

Notes / what to keep in mind

  • This is the number-one place automations go wrong. There is no "find or create". Every POST /locations creates a brand-new row, even if an identical address already exists. An automation that creates a location on every sync will fill your account with duplicates and eventually hit your location limit. The fix: call GET /locations first, match on your side, and only create when there's genuinely no match. Store the ID you get back and reuse it forever.

  • Locations are shared. Every job pointing at a location shares the same address record, so editing it changes the address on all of those jobs at once. If only one job's address changed, create a new location for it instead of editing the shared one.

  • Every location counts towards your plan limit, whether or not a job uses it. Housekeeping matters.

  • Creating over the limit changes nothing. The operation is wrapped in a transaction, so a 402 leaves no half-created row behind.

  • There's no delete endpoint. Remove unused locations in the Recooty UI.

Troubleshooting

Symptom

Most likely cause

Fix

Duplicate offices piling up

Your automation creates a location every run

Look up first, create only on no match, cache the ID

402 You have reached your location limit

Too many locations, usually from the above

Delete unused locations in the UI, or upgrade

422 on country_code

Not exactly two characters

Use the ISO code — US, GB, IN

422 — nothing identifies the location

You sent none of name, city, address

Send at least one

404 on update

The location belongs to another workspace, or was deleted

Re-list and use a current ID

Editing one job's address changed several jobs

They all share that location

Create a separate location for that job

DEPARTMENTS API

A read-only list of the departments in your workspace, so you can tag jobs to the right team.

When you'd use it

To resolve a department_id before creating or updating a job. Department names in your HR system rarely match Recooty's IDs, so you look them up here and map them once.

The endpoint

What it does

Request

Credential

Status

List your departments

GET /api/v1/departments

Access token

Beta

How to use it

curl --request GET \   --url <API_BASE_URL>/api/v1/departments \   --header 'Accept: application/json' \   --header 'Authorization: Bearer <ACCESS_TOKEN>'
{     "departments": {         "data": [             { "id": 1, "name": "Engineering" },             { "id": 2, "name": "Marketing" }         ]     } }

Use id as department_id on a job.

Notes / what to keep in mind

  • Read-only. You cannot create, rename or delete departments through the API — do that in the Recooty UI. This is intentional: departments drive reporting and permissions, so they're managed by people, not machines.

  • department_id is optional on a job. Leave it out if you don't use departments.

  • Departments don't consume any credit or limit.

  • Returns 25 per page. With more than 25, follow next_page_url or add ?page=2 — a common cause of "our department is missing" is only reading page one.

  • Sorted alphabetically by name, not by ID.

Troubleshooting

Symptom

Most likely cause

Fix

A department is missing from the response

It's on a later page

Follow next_page_url, or add ?page=2

422 on department_id when creating a job

The ID belongs to another workspace, or was deleted

Re-list and use a current ID

You need a new department

Not possible via the API

Create it in Recooty, then re-list to get its ID

The list is empty

Your workspace has no departments yet

Create one in Recooty, or omit department_id

ERROR CODES — THE COMPLETE REFERENCE

Every Recooty API error returns a JSON message. The HTTP status tells you what kind of problem it is and, crucially, whether retrying will help.

Code

Meaning

Typical message

Retry?

200 / 201

Success

401

Not authenticated, or the resource belongs to another workspace

Unauthorized

No — fix the token

402

Plan or credit problem

Feature not available to your plan / You have reached your active job limit… / You have reached your location limit… / You have reached your application view credit limit…

No — upgrade or free up capacity

404

Not found, or not visible to you

Job post not found, Location not found

No

409

Conflict with the current state

Duplicate Application already in the system, or an invalid status transition

No — it means "already done" or "not allowed from here"

410

The job is gone or closed

The job is expired or no longer available

No

422

A field failed validation

Field-by-field detail in errors

No — fix the data

429

Too many requests

Yes — wait and retry

500

Something broke on our side

Unable to save job, Unable to fetch applications, …

Yes — retry with backoff; contact support if it persists

The three codes people misread

402 is not one problem, it's two. Read the message:

  • "Feature not available to your plan" → API Access isn't on your plan at all. Nothing will work until you upgrade.

  • "You have reached your … limit" → your plan is fine, you've simply used up jobs, locations or view credits. Free some up or upgrade.

409 usually means "it already happened". A duplicate application isn't a failure — the candidate is already in your pipeline. Handle it as a normal outcome, not an alert.

401 on an integration that used to work almost always means an expired or revoked token. Tokens last one year. Check the expiry date on the token card in Recooty.

INTEGRATION RECIPES

Sync jobs from another system into Recooty

Run this whenever a requisition changes in your system:

  1. Resolve the location. Reuse a stored location_id if you have one. Only if you don't, call GET /locations, look for a match, and create one as a last resort. Cache the ID.

  2. Resolve the department (if you use them) with GET /departments. Map names to IDs once and cache.

  3. Check whether the job exists: GET /jobs/<API_KEY>?code=<YOUR_REFERENCE>.

    • job_count: 0POST /jobs with code set to your reference.

    • job_count: 1 → take jobs[0].id and PATCH /jobs/{id} with only the changed fields.

  4. Mirror the status. Requisition filled or cancelled → PATCH with status: "CLOSED". Reopened → publish with CAREER_PAGE. The lookup response includes the current status, so skip the call when nothing changed.

Because job code is unique per workspace, this loop is safe to run repeatedly — it will never create a duplicate.

Put your live jobs on your own website

  1. Copy the List published jobs URL from the API page (your key is already in it).

  2. Have your web team fetch it and render title, city, employment_type and remote.

  3. Link each entry to details_url_external, and any Apply button to apply_url_external.

No token needed, so this is safe to run from browser JavaScript. If you'd rather not write code at all, use the Jobs Widget instead — see the widget article.

Accept applications from your own form

  1. Create an access token named after the form.

  2. Store it on your server, never in the page.

  3. On submit, POST to /jobs/<JOB_ID>/applications as multipart/form-data from your backend.

  4. Handle 409 as "you've already applied", and 410 as "this role has closed".

Pull applicants into a dashboard

  1. Poll GET /jobs/<JOB_ID>/applications on a schedule — free, no contact details.

  2. Show counts, names and stages from that alone.

  3. Call GET /applications/<APPLICATION_ID> only when someone actually clicks into a candidate. That's when the view credit is spent.

FREQUENTLY ASKED QUESTIONS

Do I need a developer?

For reading and displaying jobs, not necessarily — the Jobs Widget covers that with no code. For anything that writes into Recooty or reads candidates, yes.

What happens if my plan doesn't include API Access?

The API page is still visible and your API key still works for the three job-listing endpoints. Everything else returns 402 until you upgrade.

What happens if I run out of application view credits?

Applications keep arriving normally and nothing is lost. You can still list them. Opening a candidate you haven't opened before returns 402 until credits refresh or you upgrade. Candidates you've already opened stay open.

What happens if I hit my job limit?

Publishing another job returns 402 and creates nothing. Close a job you no longer need — that frees the credit immediately — or upgrade. Drafts are free, so you can stage work in advance.

What happens if I hit my location limit?

Creating another location returns 402 and creates nothing. Delete unused locations in the UI. This limit is usually hit by an automation creating duplicates — see the Locations notes.

Can I delete a job?

No, and that's deliberate — deleting would take its applications with it. Close it instead.

Can I reopen a closed job?

Not through the API in this version. Reopen it in the Recooty UI, or create a new job.

Can I get notified when something happens, instead of polling?

Recooty has webhooks for application events (Settings → Integrations → Webhooks). Job events aren't covered yet — for those, use the job-code lookup on a schedule.

My token stopped working.

Tokens expire one year after creation, and revoking one takes effect immediately. Check the expiry on the token card, then create a replacement.

Someone left the company — what should I do with their tokens?

Revoke them. Tokens are created by a person but act on the whole workspace, so treat them like any other shared credential during offboarding.

Is my API key sensitive?

Less so than a token. It only returns jobs you've already published publicly, so it's safe in a website or widget. It is not a password and can't be used to write anything or read candidates.

Can one workspace see another's data?

No. Every token is bound to a single workspace when it's created, and requests for another workspace's jobs or locations return 401 or 404.

Which endpoints are Beta?

Create/update job, all three location endpoints, and list departments. They work in production today; their responses may gain fields, but nothing will be removed without notice. They're marked with a Beta tag on the API page.

GETTING HELP

  1. Start on the API page — Settings → Integrations → API. Every endpoint has a working example with your own key already filled in, plus a sample response.

  2. Read the error message. Recooty's API returns plain-English messages, and the status code tells you whether retrying will help.

  3. Still stuck? Contact Recooty support with: the endpoint you called, the HTTP status, the full JSON error, and roughly when it happened. That's usually enough to resolve it on the first reply.

Please never share an access token in a support ticket, email, or screenshot. Support never needs it.

Did this answer your question?