Manage candidates and applications

End-to-end guide to creating candidates, submitting applications, and advancing through the interview pipeline

Overview

This guide walks through the complete application workflow in Deel’s ATS API: creating a candidate record, submitting an application to a specific job, and advancing the application through interview plan stages until a hiring decision is reached. Each step depends on the previous one. You must have a candidate before you can create an application, and an application before you can advance stages.

When to use this workflow

Use this workflow when you need to:

  • Push candidates from an external sourcing tool into Deel’s ATS
  • Automate application creation as part of a recruitment integration
  • Advance pipeline stages programmatically in response to hiring decisions
  • Sync application status from Deel into an external HR system

Prerequisites

Before starting, ensure you have:

  • A valid API token with ats:read and ats:write scopes
  • An existing job ID and its corresponding job_employment_type_id. See Manage jobs.
  • Your hris_organization_user_id, required for advancing pipeline stages. See Getting started.

If you do not have an interview plan attached to your job, you can still create candidates and applications. You cannot call the stage advancement endpoint until you configure an interview plan in the Deel application.

Step-by-step workflow

The following example follows a single hire: Jane Doe, a Senior Software Engineer candidate applying to job job_01hxyzpqrstu.

1

Create a candidate

A candidate record stores the person’s contact information. Create a candidate before creating any application for them.

$curl --request POST 'https://api.letsdeel.com/rest/v2/ats/candidates' \
> --header 'Authorization: Bearer YOUR-TOKEN-HERE' \
> --header 'Content-Type: application/json' \
> --data '{
> "data": {
> "first_name": "Jane",
> "last_name": "Doe",
> "email": "jane.doe@example.com",
> "phone_number": "+1 555 000 1234",
> "linkedin_profile_url": "https://linkedin.com/in/jane-doe"
> }
> }'

Store the candidate.id. You need it in the next step.

A candidate’s email address must be unique within your organization. If a candidate with the same email already exists, the request will fail. Check for existing candidates using GET /ats/candidates?search=jane.doe@example.com before creating a new record.

2

Create an application

An application links a candidate to a specific job and employment type. You need the job_id, the job_employment_type_id (the join record ID from GET /ats/jobs), and the candidate_id.

$curl --request POST 'https://api.letsdeel.com/rest/v2/ats/applications' \
> --header 'Authorization: Bearer YOUR-TOKEN-HERE' \
> --header 'Content-Type: application/json' \
> --data '{
> "data": {
> "candidate_id": "cand_01hxyzabcdef",
> "job_id": "job_01hxyzpqrstu",
> "job_employment_type_id": "jet_01hxyz333bcd",
> "notes": [
> {
> "richtext_content": "<p>Referred by the engineering team. Strong background in distributed systems.</p>"
> }
> ]
> }
> }'

Store the application.id. You need it to advance stages and add notes.

The job_employment_type_id is the ID of the join record between the job and the employment type (e.g. jet_01hxyz333bcd), not the employment type ID itself (e.g. et_01hxyz789ghi). Retrieve it from GET /ats/jobs under job_employment_types[].id.

3

Advance the application through an interview plan stage

Move the candidate’s application to the first active stage of the interview plan. You need the interview_plan_stage_id from the job’s interview_plan_stages array, and your own hris_organization_user_id as the creator_id.

$curl --request POST 'https://api.letsdeel.com/rest/v2/ats/applications/app_01hxyzghijkl/interview-plan-stages' \
> --header 'Authorization: Bearer YOUR-TOKEN-HERE' \
> --header 'Content-Type: application/json' \
> --data '{
> "data": {
> "interview_plan_stage_id": "ips_01hxyzmnopqr",
> "creator_id": "hrou_01hxyz222pqr",
> "is_current_stage": true
> }
> }'

Repeat this step for each subsequent stage. Set is_current_stage: true on the stage you want to mark as the current active stage.

To trigger scheduled activities (such as sending a candidate self-scheduling email), include the applicable_job_activities array with the activity IDs and any custom participant assignments.

4

Add a note to an application

Use notes to record decisions, feedback, or context during the hiring process.

Request
$curl --request POST 'https://api.letsdeel.com/rest/v2/ats/applications/app_01hxyzghijkl/notes' \
> --header 'Authorization: Bearer YOUR-TOKEN-HERE' \
> --header 'Content-Type: application/json' \
> --data '{
> "data": {
> "richtext_content": "<p>Technical interview completed. Strong systems design skills. Recommend advancing to final round.</p>"
> }
> }'
5

Tag a candidate

Tags help categorize candidates across jobs. Create a tag on a candidate for filtering and reporting.

Request
$curl --request POST 'https://api.letsdeel.com/rest/v2/ats/candidates/cand_01hxyzabcdef/tags' \
> --header 'Authorization: Bearer YOUR-TOKEN-HERE' \
> --header 'Content-Type: application/json' \
> --data '{
> "data": {
> "tag_ids": ["tag_01hxyz999zzz"]
> }
> }'

Retrieve available tag IDs with GET /ats/tags.

6

Retrieve application status

Check the full application record at any point to see the current stage, all stage history, and offer details.

Request
$curl --request GET 'https://api.letsdeel.com/rest/v2/ats/applications/app_01hxyzghijkl' \
> --header 'Authorization: Bearer YOUR-TOKEN-HERE'

The response includes current_application_interview_plan_stage, the full all_application_interview_plan_stages history, and any associated offers. When an application reaches a COMPLETED stage with an accepted offer, it is ready for contract creation. See From candidate to contract.

Common scenarios

Sourcing a candidate externally

When a candidate applies via an external job board and you want to push the record into Deel:

  1. Create the candidate with POST /ats/candidates
  2. Create the application with source_slug: "EXTERNAL_CAREER_PAGE" in the request if the field is available, or with the relevant job_posting_id
  3. Advance the stage immediately to LEAD category to start the screening process

Multiple applications per candidate

A candidate can apply to more than one job. Each application is independent. Create separate application records using the same candidate_id and different job_id values. The candidate’s total_applications_count increments with each new application.

Archiving an application

To archive an application (candidate not progressing), advance it to a COMPLETED category stage and provide a candidate_archivation_reason_id. Retrieve available reasons with GET /ats/reasons. Optionally provide a candidate_archivation_email_template_id to send a rejection notification.

Request
$curl --request POST 'https://api.letsdeel.com/rest/v2/ats/applications/app_01hxyzghijkl/interview-plan-stages' \
> --header 'Authorization: Bearer YOUR-TOKEN-HERE' \
> --header 'Content-Type: application/json' \
> --data '{
> "data": {
> "interview_plan_stage_id": "ips_01hxyz_rejected",
> "creator_id": "hrou_01hxyz222pqr",
> "is_current_stage": true,
> "candidate_archivation_reason_id": "reason_01hxyz_overqualified"
> }
> }'

Troubleshooting

You are using the employment_type.id instead of the job_employment_type_id. The job_employment_type_id is the ID of the join record (jet_...) returned under job_employment_types[].id in GET /ats/jobs. These are different values.

Each candidate email must be unique within your organization. Use GET /ats/candidates?search=email@example.com to check if the candidate already exists. If they do, retrieve their id and create a new application directly without creating a new candidate record.

The creator_id must be the hris_organization_user_id of a hiring member in your organization, not the candidate ID or application ID. Retrieve your hiring members with GET /ats/hiring-members and use the hris_organization_user_id field.

The job must have an interview plan attached (interview_plan_id) before you can advance applications. Attach an interview plan in the Deel application under the job settings. You can also retrieve available stage IDs from GET /ats/jobs under interview_plan_stages.

The current_stage_category_type_slugs and current_stage_default_type_slugs filters apply to the candidate’s most recent application stage across all their applications, not to a specific job. Use GET /ats/applications filtered by job_id for job-specific stage filtering.

Next steps