From candidate to contract
Overview
When a candidate accepts an offer in Deel’s ATS, the hiring record is complete but no contract exists yet. This guide walks through the steps to retrieve the accepted offer from the ATS, determine the correct contract type based on the offer’s worker_type, and initiate the contract creation request using Deel’s contracts API.
The process is partly manual today: offer retrieval and contract creation are separate API surfaces, and the link between them requires passing key fields from the offer (such as candidate email, employment type, and location) into the contract request.
When to use this workflow
Use this workflow when you need to:
- Automatically trigger contract creation as soon as a candidate accepts an offer
- Sync hire decisions from Deel’s ATS into a downstream HRIS or payroll system
- Build an end-to-end recruitment-to-onboarding automation without manual handoffs
- Audit which ATS applications have progressed to active contracts
Prerequisites
Before starting, ensure you have:
- A valid API token with
ats:readscope to retrieve offer data - Contract creation permissions:
contracts:writescope and a Deel account configured for the relevant contract type - A completed ATS application that has reached a
COMPLETEDstage with an accepted offer. See Manage candidates and applications. - The
application_idof the hired candidate
Step-by-step workflow
The following example follows Jane Doe, whose application app_01hxyzghijkl has progressed to a COMPLETED stage with an accepted offer.
Retrieve the application and check offer status
Fetch the full application record to confirm an offer exists and has been accepted.
Response (abbreviated):
Confirm two conditions before proceeding:
current_application_interview_plan_stage.interview_plan_stage.category_type_slugis"COMPLETED"offers[0].offer_statusis"ACCEPTED"
If no offer exists or the offer status is not "ACCEPTED", the application is not ready for contract creation.
Retrieve offer details
Fetch the full offer to get the fields required for contract creation.
Response (abbreviated):
Store the following fields. You will need them in the next step:
worker_type: determines which contract endpoint to callsalary,start_date,country_code,job_title- The candidate’s email from the application record
If offers is empty on the application record, the job’s interview plan may not have an offer stage configured. Set up offer stages in the Deel application under the interview plan settings.
Determine the contract type
The worker_type on the offer determines which Deel contract API to use.
The candidate’s offer has worker_type: "EOR_EMPLOYEE", so you will create an EOR contract.
Create the contract
Pass the offer details into the contract creation request. The exact fields required vary by contract type. Refer to the Contracts API reference for the full schema.
A successful response returns the new contract ID. Store it to link the contract back to the ATS application in your own system.
Contract creation does not automatically update the ATS application. There is no API to attach a contract ID to an application record. Track the link between application_id and contract_id in your own system.
Common scenarios
Contractor instead of EOR employee
If worker_type is CONTRACTOR, use POST /contracts/ic instead. The key difference is that IC contracts require the worker to register as a contractor entity. Ensure the worker has completed their Deel contractor profile before creating the contract.
Offer not yet accepted
If offer_status is SENT (not yet ACCEPTED), the candidate has not yet accepted. Poll GET /ats/offers/{offer_id} or set up an ats.application.transitioned webhook to receive a notification when the application stage changes to COMPLETED. Do not create a contract for an unaccepted offer.
Multiple offers on one application
An application can have more than one offer (for example, if a first offer was rejected and a new one was extended). Always check the full offers array and use the offer with offer_status: "ACCEPTED". If multiple offers exist, use the one with the most recent created_at timestamp.
Troubleshooting
offers array is empty on the application
Deel generates an offer only when the interview plan includes an offer stage and a hiring manager creates one in the Deel application. If the offers array is empty, the application has not reached the offer stage yet, or a hiring manager has not created the offer. Check the application’s current_application_interview_plan_stage and confirm the interview plan includes an offer stage.
offer_status is SENT but never moves to ACCEPTED
The candidate must accept the offer through their Deel candidate portal. If the candidate has not received the email, verify their email address on the candidate record with GET /ats/candidates/{candidate_id}. Resend the offer email in the Deel application.
Contract creation returns 422: worker email not found
The worker email must match a Deel user account. If the candidate does not yet have a Deel account, contract creation will prompt them to register. Ensure the email on the offer matches the email you are sending to the contracts endpoint.
worker_type on the offer does not match expectations
Deel sets the worker_type when a hiring manager creates the offer, based on the employment type configured for the job. If the value is unexpected, verify the job_employment_type on the application and the offer configuration in the Deel application.
Cannot find the correct contract endpoint for the worker_type
Use the worker_type value from the offer to select the correct endpoint: EOR_EMPLOYEE → /contracts/eor, CONTRACTOR → /contracts/ic, DIRECT_EMPLOYEE → /contracts/direct, GLOBAL_PAYROLL_EMPLOYEE → /contracts/gp. Full schema for each endpoint is in the Contracts API reference.
Next steps
Full schema and required fields for EOR, IC, direct, and global payroll contracts.
Review the full application workflow before the hire decision.
Receive real-time notifications when an application reaches a completed stage.
Review the full ATS data model and API capabilities.