GuidesAPI ReferenceChangelog
Changelog

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_messageon 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_refis added in response of GET endpoints
  • payroll_cycle_refis 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)
  • 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

EOR Worker additional fields

PATCH Update EOR worker additional fields

Updates additional information for an EOR employee agreement. Only works if the employee’s contract status is new, under_review, or waiting_for_employee_contract. Using other statuses can cause errors.

ā—Note: This endpoint works with dynamic properties. To retrieve the available properties, use the following endpoint: Get worker additional fields for (EOR). There are no required properties when updating additional worker information.

Endpoint: PATCH /rest/v2/eor/workers/contracts/{contract_id}/additional-information

Token scopes: worker:write

API Reference: Retrieve bank account guide

Request Example:

curl --location --request PATCH 'https://api.letsdeel.com/rest/v2/eor/workers/contracts/{contract_id}/additional-information' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{PUBLIC_API_TOKEN}}' \
--data-raw '{
    "data": {
        "dob": "1990-07-15",
        "gender": "Male",
        "marital_status": "Married",
        "id_type": "Emirates ID",
        "id_number": "784-1990-6543210-2",
        "passport_number": "A12345678",
        "passport_validate_date": "2030-05-20",
        "visa_status": "Resident",
        "zip_code": "00000"
    }
}'

Response Example:

{
    "data": {
      "updated": true
    }
}

Update properties for EOR Banks guide

Update response properties for Retrieve bank account guide to be consistent with Get worker additional fields for (EOR)

Actual changes:

  • Changed requiredto is_required
  • Rename validationsto validation
  • Changes in validationobject
    • Added property error_message
  • Added ui_guidesobject
    • Moved labelfrom root object to ui_guides
    • Added orderproperty
    • Add helper_textto ui_guides

Response Example:

{
  "data": [
    {
      "key": "swift_bic",
      "type": "text",
      "is_required": true,
      "ui_guide": {
        "label": "SWIFT BIC Code",
        "order": 5,
        "helper_text": "Bank identifier for international wire transfers."
      },
      "validation": [
        {
          "type": "MIN_LENGTH",
          "value": "1",
          "error_message": "Value must be at least 1 characters long."
        },
        {
          "type": "MAX_LENGTH",
          "value": "140",
          "error_message": "Value must be no more than 140 characters long."
        },
        {
          "type": "REGEX",
          "value": "^[a-zA-Z0-9 ]+$",
          "error_message": "Review the value entered"
        }
      ],
      "values_allowed": []
    },
    ...
  ]
}