Magic Link Authentication for Workers
Create Magic Link
Generate secure, time-limited magic links that enable password-free, seamless worker authentication for quick and safe access. Ideal for temporary sessions or low-friction login flows.
Prerequisites: Requires a worker session token created via the existing POST /rest/v2/workers/session endpoint using an organization token with admin:worker scope.
Endpoint: POST /rest/v2/magic-link
Token scopes: worker:read
API Reference: Create Magic Link
Request Example:
curl --request POST \
--url https://api.letsdeel.com/rest/v2/magic-link \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'authorization: Bearer {{token}}'
List of ActionableJourneys
Provides a list of Actionable Journeys for Workers
Returns a paginated list of actionable journeys assigned to the authenticated worker. Actionable journeys are learning paths or training programs that require active participation from the worker, such as completing courses, assessments, or other learning activities. The response includes journey details, completion status, and pagination metadata to support efficient data retrieval.
These journeys are personalised for the specific worker based on their role, department, and organisational requirements
Endpoint: GET rest/v2/engage/learning/actionable-journeys
Token scopes: worker:read
API Reference: List of ActionableJourneys
curl --request POST \
--url https://api.letsdeel.com/rest/v2/engage/learning/actionable-journeys \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'authorization: Bearer {{token}}'
EOR contract documents signature for quote flow
Fetch EOR contract documents
Returns a list of all documents that are available for the given EOR contract, expecting client signature. The response will contain the document types and additional signature details when available.
These documents are intended for the client to review and sign, but not the employee, and are available only for certain countries, such as Framework Agreement for Belgium.
Endpoint: GET /rest/v2/eor/contracts/:contract_id/documents
Token scopes: contracts:read
API Reference: Fetch EOR contract documents
Request Example:
curl --request GET \
--url 'https://api.letsdeel.com/rest/v2/eor/contracts/abc123/documents' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'authorization: Bearer {{token}}'
Fetch EOR contract document
Returns the document in PDF format for the given EOR contract and document type for download. This file can be shared with the client as a reference.
Endpoint: GET /rest/v2/eor/contracts/:contract_id/documents/:document_type
Token scopes: contracts:read
API Reference: Fetch EOR contract document
Request Example:
curl --request GET \
--url 'https://api.letsdeel.com/rest/v2/eor/contracts/abc123/documents/FRAMEWORK_AGREEMENT' \
--header 'accept: application/pdf' \
--header 'content-type: application/json' \
--header 'authorization: Bearer {{token}}'
Sign EOR contract document
Signs a document with the provided signature and title. Can be used after the client has reviewed the document and is ready to sign. A document can only be signed once - otherwise the signature will be rejected and the endpoint will return an error.
After signature, the responses for both this endpoint and for fetching all documents will contain the signature details.
Endpoint: POST /rest/v2/eor/contracts/:contract_id/documents/:document_type/sign
Token scopes: contracts:write
API Reference: Sign EOR contract document
Request Example:
curl --request POST \
--url 'https://api.letsdeel.com/rest/v2/eor/contracts/abc123/documents/FRAMEWORK_AGREEMENT/sign' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'authorization: Bearer {{token}}' \
--data '{
"data": {
"signature": "John Doe",
"client_job_title": "Software Engineer"
}
}'
Improvements:
GET /v2/immigration/workers/:worker_id/onboarding-case
Change: The documents.status enum values have been updated.
Before:
{
"status": "IN_REVIEW" // or "APPROVED" or "REJECTED"
}
After:
{
"status": "EXPIRED" // or "EXPIRING" or "ACTIVE" or "IN_REVIEW"
}
GET /v2/immigration/workers/:worker_id/required-documents
Change: Complete restructure of the response document object.
Before:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"description": "Passport document required for verification",
"documents": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "IN_REVIEW",
"rejection_reason": "File / photo poor quality",
"note": "Please provide a clear scan"
}
]
}
After:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Passport Requirement",
"description": "Passport document required for verification",
"status": "COMPLETED", // 'PENDING', 'IN_REVIEW', 'REJECTED', 'COMPLETED', 'FAILED', 'PROCESSING'
"document": { // can be null if no document has been uploaded
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Proof of employment document",
"status": "EXPIRING", // "EXPIRED" or "EXPIRING" or "ACTIVE" or "IN_REVIEW"
"expiry_date": "2025-09-31"
},
"previous_document_request": { // only available if the current document request does not have a document and the current uploaded document was rejected
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "REJECTED", // 'REJECTED' only
"rejection_reason": "File / photo poor quality",
"rejection_note": "Please provide a clear scan"
}
}
POST /v2/immigration/workers/documents
Change: Request body requirements have been updated.
Before:
{
"worker_id": "550e8400-e29b-41d4-a716-446655440000", // optional
"case_id": "550e8400-e29b-41d4-a716-446655440000",
"immigration_document_requirement_id": "550e8400-e29b-41d4-a716-446655440000",
"file": "file_data"
}
After:
{
"worker_id": "550e8400-e29b-41d4-a716-446655440000", // now required
"document_request_id": "550e8400-e29b-41d4-a716-446655440000", // now required
"case_id": "550e8400-e29b-41d4-a716-446655440000", // still required
"file": "file_data" // still required
}
Added:
reject_reason
on List of employee compliance documents
rejection_message
on Get onboarding details by onboarding hris profile oid
Cost Centers management for contracts and legal entities
Assign Cost Centers
Register the allocation of active cost centers of a legal entity to an employment contract of that entity. The new configuration requires an effective day to become valid and the allocation must add up exactly to 1 (100% allocated). The returned id represents an employment term where this information is registered.
Endpoint: POST /rest/v2/contracts/:contract_id/cost-centers
Token scopes: contracts:write
API Reference: Assign cost centers to an employment contract
Request Example:
curl --request POST \
--url https://api.letsdeel.com/rest/v2/contracts/contract_id/cost-centers \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'authorization: Bearer {{token}}'
Get cost centers for legal entity
Fetches a list of all available cost centers for a legal entity, which does not includes archived cost centers. Does not include cost centers allocations by contract, even if the legal entity is a part on these contracts.
Endpoint: GET /rest/v2/legal-entities/:legal_entity_id/cost-centers
Token scopes: legal-entity:read
API Reference: Get cost centers by legal entity
Request Example:
curl --request GET \
--url https://api.letsdeel.com/rest/v2/legal-entities/id/cost-centers \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'authorization: Bearer {{token}}'
Synchronize cost centers for legal entity
Define the active cost center data for a legal entity. This will delete existing items that are not present on the payload, create new items, and finally update cost centers that maintain the same name. Please be aware that is not possible to delete cost centers that are currently allocated to one or more contracts.
Endpoint: POST /rest/v2/legal-entities/:legal_entity_id/cost-centers/synchronize
Token scopes: legal-entity:write
API Reference: Sync cost centers for legal entity
Request Example:
curl --request POST \
--url https://api.letsdeel.com/rest/v2/legal-entities/id/cost-centers/synchronize \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'authorization: Bearer {{token}}'
Added group_id to the response of the GET /v2/payments/:payment_id/breakdown
endpoint.
Check the API Reference
Response example:
{
"data": [
{
"date": "2022-10-01T00:59:28.482Z",
"work": "3000.00",
"bonus": "500.00",
"total": "3500.00",
"others": "0.00",
"currency": "USD",
"expenses": "0.00",
"group_id": "4fd2daf5-7d59-4990-ba17-5dfc5f1034d0",
"overtime": "0.00",
"pro_rata": "0.00",
"approvers": "John Smith",
"frequency": "monthly",
"adjustment": "0.00",
"deductions": "0.00",
"commissions": "0.00",
"approve_date": "2022-10-28T14:32:15.847Z",
"payment_date": "2022-11-01T17:20:32.837Z",
"contract_type": "ongoing_time_based",
"processing_fee": "0.00",
"contract_country": "US",
"contractor_email": "[email protected]",
"payment_currency": "USD",
"contract_start_date": "2020-03-31T10:58:49.780Z",
"general_ledger_account": "6000 - Office Expenses",
"total_payment_currency": "1000.00",
"contractor_employee_name": "Jane Doe",
"contractor_unique_identifier": "550e8400-e29b-41d4-a716-446655440000"
}
]
}
Added: work_schedule object to the response of contract by ID
Reference: https://developer.deel.com/reference/getcontractbyid
Example:
"work_schedule": {
"name": “GP” work schedule,
"work_hours_per_week": 40,
"country": "DE",
"employment_type": "FULL_TIME",
"worker_types": [
"HOURLY_DIRECT_EMPLOYEE_PAYROLL",
"SALARIED_DIRECT_EMPLOYEE_PAYROLL"
],
"work_schedule_type": "Fixed work schedule",
"days": [
{
"day": "MONDAY",
"start": "09:00:00",
"end": "17:00:00",
"work_hours": 8
},
{
"day": "TUESDAY",
"start": "09:00:00",
"end": "17:00:00",
"work_hours": 8
},
{
"day": "WEDNESDAY",
"start": "09:00:00",
"end": "17:00:00",
"work_hours": 8
},
{
"day": "THURSDAY",
"start": "09:00:00",
"end": "17:00:00",
"work_hours": 8
},
{
"day": "FRIDAY",
"start": "09:00:00",
"end": "17:00:00",
"work_hours": 8
}
]
}
Submit external KYC
The endpoint standardises identity verification and compliance processes, combining automated Live ID verification (IDV) and manual review workflows
Endpoint: POST /rest/v2/screenings/kyc/external
Token scopes: worker:write
API Reference: Submit external KYC
Example:
curl --location 'https://api.letsdeel.com/rest/v2/screenings/kyc/external' \
--header 'Authorization: {{PUBLIC_API_TOKEN}}' \
--form 'first_name="John"' \
--form 'last_name="Doe"' \
--form 'date_of_birth="1985-11-23"' \
--form 'screening_type="manual"' \
--form 'screening_status="approved"' \
--form 'front=@"/dock.jpg"' \
--form 'selfie_with_id=@"/dock2.jpg"' \
--form 'kyc_document[type]="DRIVING_LICENSE"' \
--form 'kyc_document[id_number]="X12345678"' \
--form 'kyc_document[issuance_date]="2025-06-01"' \
--form 'kyc_document[expiration_date]="2045-06-01"' \
--form 'kyc_document[issuance_country]="US"' \
--form 'back=@"/2.png"'
Updated: time-off policies
API Reference: List Policies
Extended List policies API to expose more policy fields:
- policy allowance settings data
- policy proration rules
- notice period
- auto approval rules for when workers are granted the right to start to request time off (probation period)
Person without a contract
Create a person without a contract
Create a person without a contract hired under your own entity to Deel's HRIS
Endpoint: POST /rest/v2/pwac
Token scopes: people:write
API Reference: Create a person without a contract
Example:
curl --location 'https://api.letsdeel.com/rest/v2/pwac' \
--header 'accept: application/json' \
--header 'authorization: Bearer {{PUBLIC_API_TOKEN}}' \
--header 'Content-Type: application/json' \
--data-raw '{
"person": {
"email": "[email protected]",
"work_email": "[email protected]",
"first_name": "John",
"last_name": "Snow",
"preferred_first_name": "Johny",
"preferred_last_name": "S",
"state": "SP",
"country": "BR",
"nationality": "US",
"external_id": "external-id-123",
"job_title": "Job Title",
"seniority": "Seniority",
"start_date": "2025-06-18",
"end_date": "2026-06-18"
},
"client": {
"team": {
"id": "2c58e51f-44ee-450b-bba5-dec37d1d5579",
"direct_manager_id": "99aebce6-b71d-4922-99b4-d9f2e41e6827",
"direct_reports_ids": ["451a67fc-e024-456e-8591-1403d5786df9"]
},
"department": {
"id": "07939d85-4214-4f69-ba02-e02ba27313d9"
},
"legal_entity": {
"id": "365d2ce4-db71-4c03-ace9-fcd2fcf37b7a"
}
}
}'
Updated: shifts endpoints to handle delayed submissions
New field added to the shifts endpoints to handle delayed submissions.
payroll_cycle_ref
is added in response of GET endpointspayroll_cycle_ref
is added in response and requestBody of POST and PATCH endpoints
Endpoints:
Updated: POST /v2/time_tracking/shift_rates endpoint
Parameters type
and value
are now optional
Endpoints:
Time tracking
Create Uncategorized (Raw) Shifts
Endpoint to create uncategorized (raw) shifts.
Endpoint: POST /rest/v2/time_tracking/shifts/raw
Token scopes: time-tracking:write
API Reference: Create Uncategorized (Raw) Shifts
curl --location --request POST 'https://api.letsdeel.com/rest/v2/time_tracking/shifts/raw' \
--header 'Authorization: Bearer {{token}}' \
--header 'Content-Type: application/json' \
--data '{
"data": {
"contract_id": "abcd56",
"shifts": [
{
"external_id": "shift_456",
"description": "Raw entry with start/end times",
"date_of_work": "2024-04-01",
"meta": {
"start": {
"date": "2024-04-01",
"time": "09:00",
"is_rest_day": false,
"is_public_holiday": false
},
"end": {
"date": "2024-04-01",
"time": "17:00",
"is_rest_day": false,
"is_public_holiday": false
},
"approval_date": "2024-04-03"
}
}
]
}
}'
Update Uncategorized (Raw) Shifts
Endpoint to update uncategorized (raw) shifts
Endpoint: PATCH /rest/v2/time_tracking/shifts/raw/:external_id
Token scopes: time-tracking:write
API Reference: Update Uncategorized (Raw) Shifts
curl --location --request PATCH 'https://api.letsdeel.com/rest/v2/time_tracking/shifts/raw/shift_example45' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{token}}' \
--data '{
"data": {
"description": "This is a sample updated shift",
"date_of_work": "2023-10-01"
}
}'
Updated: POST EOR Contract Creation
Following fields were made optional in compensation_details.fixed_adjustments
object in request body: "description", "value", "is_recurring"
- Fixed adjustment fields are no longer required when the fixed adjustment is country specific.
- In those cases, only the
rule_cost_id
is required - The
opt_out
flag should also be included when applicable (depending on whether the fixed adjustment is optional)
- In those cases, only the
- It's no longer necessary to include these fields in the request payload at all.
- If not provided, the fixed adjustments will still be created based on the allowances configured for the country
- If values are provided, they will be overwritten with the data associated with the
rule_cost_id
Endpoint: POST /rest/v2/eor
API Reference: Crete EOR Contract