GuidesAPI ReferenceChangelog
Changelog

Worker Contract Sign API

Sign a contract as a worker.

Endpoint: POST /rest/v2/workers/contracts/:contract_id/signatures

Token scopes: worker:write

API Reference: Sign worker contract

Request Example:

curl -X POST \
  "https://api.letsdeel.com/rest/v2/workers/contracts/37nex2x/signatures" \
  -H "Authorization: Bearer <worker_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "worker_signature": "John Doe"
    }
  }'

Enhancement: Add Candidate

API Reference: Retrieve Seniority Levels

Request body changes

Added personalEmail property to the parameters in order to allow differentiating between work email (email property) and personal email (personalEmail new property)

Endpoint improvements and new onboarding webhook events

🚀 New onboarding webhook events

  1. onboarding.status.updated: Triggered when the onboarding status is updated

    //Sample payload
    
    {
      "data": {
        "meta": {
          "event_type": "onboarding.status.updated",
          "event_type_id": "f37087e1-91fd-4d49-a4a8-a8e3218fd2e3",
          "organization_id": "98d14f88-c97a-4ec5-9858-36a731f6e2a5",
          "organization_name": "6QWYZCZ5",
          "tracking_id": "26c2f543-f93a-4fb0-a35b-618f77c09de5"
        },
        "resource": {
          "hiring_type": "contractor",
          "hris_profile_id": "5afd4d99-27da-4fc3-9683-65963a6e0914",
          "status": "ONBOARDING",
          "old_status": "PENDING_INVITE",
          "tracker_id": "eyJjb250cmFjdE9pZCI6IjN2cDUyNGsiLCJoaXJpbmdUeXBlIjoiY29udHJhY3RvciIsInVzZXJJZCI6MTY4NTgzNX0"
        }
      },
      "timestamp": "2025-07-21T16:52:23.907Z"
    }
    
  2. onboarding.checklist.updated: Triggered when the onboarding checklist is updated

    //Sample payload
    
    {
      "data": {
        "meta": {
          "event_type": "onboarding.checklist.updated",
          "event_type_id": "f37087e1-91fd-4d49-a4a8-a8e3218fd2e3",
          "organization_id": "98d14f88-c97a-4ec5-9858-36a731f6e2a5",
          "organization_name": "6QWYZCZ5",
          "tracking_id": "26c2f543-f93a-4fb0-a35b-618f77c09de5"
        },
        "resource": {
          "checklist_id": "7a3ef189-b191-4b58-bfda-211f1bf7af7a",
          "hiring_type": "contractor",
          "hris_profile_id": "5afd4d99-27da-4fc3-9683-65963a6e0914",
          "old_status": "PENDING",
          "status": "DONE",
          "step_id": "95611eee-ab61-419f-ae62-8adbcc41f778",
          "step_slug": "contractor_sign_up_to_deel",
          "tracker_id": "eyJjb250cmFjdE9pZCI6IjN2cDUyNGsiLCJoaXJpbmdUeXBlIjoiY29udHJhY3RvciIsInVzZXJJZCI6MTY4NTgzNX0"
        }
      },
      "timestamp": "2025-07-21T16:52:23.907Z"
    }
    

🚀 Enhancement: Retrieve Seniority Levels

API Reference: Retrieve Seniority Levels

Request body changes

Added support for filtering the seniorities list by EOR contracts

  • is_eor_contract (boolean, optional)
    New public API query parameter to include only levels valid for EOR contracts

🚀 New Endpoint: Create Child Organization

This process creates a new organization that includes the following elements:

  • An API token specific to the new organization, which can be used to perform API operations on its behalf.
  • A default group associated with the organization.
  • A hierarchical structure that connects the authenticated organization (the Parent Organization) to the new organization (the Child Organization). This hierarchy allows the Child Organization to inherit white-label settings from its Parent Organization.
  • A user from the Parent Organization who will be assigned to the Child Organization.
    This endpoint establishes the minimum requirements necessary for the new organization to be fully operational immediately after its creation.
    Prerequisites: Requires an organization token with the organizations: write scope. The organization associated with the token must have the partner portal feature enabled, and it must be a parent organization (i.e., it should not be a child of another organization in the hierarchy).
    Endpoint: POST /rest/v2/organizations/children
    Token scopes: organizations:write
    API Reference: Create Child Organization
    Request Example:
curl --request POST \
  --url https://api.letsdeel.com/rest/v2/organizations/children \
  --header 'accept: application/json' \
  --header 'content-type: application/json' \
  --header 'x-auth-token: {{token}}' \
  --data '{
    "data": {
      "child_organization": {
        "name": "Child organization",
        "headquarters_country": "US",
        "workforce_size": 100,
        "is_api_enabled": false,
        "department": "Finance"
      },
      "parent_organization": {
        "admin_email": "[email protected]"
      }
    }
  }

🚀 Enhancement: External HR Time Off Synchronization

API Reference: POST /rest/v2/time_offs/global-payroll/sync

Request body changes

  • Added Work accident leave value to policy_type enum

🚀 Enhancement: Retrieve onboarding right-to-work case for a worker

API Reference: GET /rest/v2/immigration/workers/{worker_id}/onboarding-case

Response field changes

  • Added rejection_reason and rejection_note to process object
  • Renamed case_created_at to created_at
  • Renamed last_updated_at to updated_at
{  
    "data": {  
        ...  
        "process": {  
            ...  
            "rejection_reason": "Poor image quality", // available when process has been rejected  
            "rejection_note": "This is the reason why the case was rejected.", // available when process has been rejected  
            "created_at": "2025-07-21T18:04:55.771Z",  
            "updated_at": "2025-07-21T18:04:55.771Z"  
        }  
    }  
}

🚀 Enhancements and Endpoint renamed: Retrieve a required document for a case

API Reference: GET /rest/v2/immigration/workers/{worker_id}/cases/{case_id}/required-document

Deprecated API Reference: GET /rest/v2/immigration/workers/{worker_id}/required-documents

Response field changes

  • Added immigration_document_requirement_id
  • Renamed previous_document_request to previous_rejected_document
  • Renamed expiry_date to expiration_date
  • Added created_at and updated_at
{
    "data": {
        "id": "f1a44946-6418-4295-b231-f4ae240e7663",
        "immigration_document_requirement_id": "ed1f24a0-3d59-4668-9c93-417b677e3e84", // static id
        "name": "Proof of employment",
        "description": "A government-issued document that proves your right to work in India. \n",
        "document": {
            "status": "PENDING",
        },
        "previous_rejected_document": {
            "id": "4ec1006d-df21-469a-b6fc-55eba5840940",
            "status": "REJECTED",
            "rejection_reason": "Incomplete information",
            "rejection_note": "The submitted document is missing some necessary details."
        },
				"created_at": "2025-07-21T18:04:55.771Z",  
        "updated_at": "2025-07-21T18:04:55.771Z"
    }
}

🚀 Enhancements and Endpoint renamed: Upload a required immigration document

API Reference: POST /rest/v2/immigration/workers/{worker_id}/cases/{case_id}/required-document/{document_request_id}

Deprecated API Reference: POST /rest/v2/immigration/workers/documents

Response field changes

  • Removed rejection_reason and note
  • Added created_at and updated_at
{
    "data": {
        "id": "c19c6d4a-6119-4283-b33d-bf429a344399",
        "status": "IN_REVIEW",
        "created_at": "2025-07-21T18:06:34.315Z",
        "updated_at": "2025-07-21T18:06:34.315Z"
    }
}

🚀 Enhancement: Update EOR Contract

API Reference: PATCH /rest/v2/eor/contract/{contract_id}

Request body changes

  1. The scope field now accepts either a plain string (as previously supported) or an object containing one of the following optional identifiers:

    1. scope_template_id: UUID referencing a predefined scope template.
    2. scope_validation_id: UUID referencing a validated scope of work.
    // Option 1: String
    "scope": "Scope of work description."
    
    // Option 2: Object
    "scope": {
      "scope_template_id": "00000000-0000-0000-0000-000000000000"
    }
    
    // Option 3: Object
    "scope": {
      "scope_validation_id": "00000000-0000-0000-0000-000000000000"
    }
    
  2. Added scope_of_work which represents the content sent on scope field in request body.

These changes align the update endpoint with the EOR contract creation endpoint, which has supported this flexible scope of work format. It ensures consistency across contract flows and provides a unified experience for clients integrating with both endpoints.

🚀 Enhancement: Retrieve payment receipts

API Reference: GET /rest/v2/payments

Introduced a new query param for filtering payment receipts based on status(paid, processing)


🚀 Enhancement: Create shifts

API Reference: POST /rest/v2/time_tracking/shifts

Added support for corrections of shifts. Clients can now add corrections via the create shifts API for the already processed shifts.


🚀 Enhancement: Amend contract

API Reference: POST /rest/v2/contracts/:contract_id/amendments

Enhanced Response Schema

The response for contract amendments has been enhanced to include additional useful information alongside existing fields.

Before:

{
    "data": {
        "created": true
    }
}

After:

{
    "data": {
        "created": true,
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "worker_id": "550e8400-e29b-41d4-a716-446655440001",
        "status": "PENDING",
        "rate": 100,
        "scale": "HOURLY",
        "job_title": "Software Engineer",
        "created_at": "2023-12-01T10:30:00Z",
        "updated_at": "2023-12-01T15:45:00Z",
        "currency_code": "USD",
        "scope_of_work": "Full-stack development",
        "special_clause": "Remote work allowed",
        "termination_notice_days": 30
    }
}

New Response Fields:

  • id - The unique identifier of the created amendment
  • worker_id - The unique identifier of the worker
  • status - Status of the amended work statement (INITIAL, PENDING, ACTIVE, OUTDATED, APPROVED, DECLINED)
  • rate - Rate/amount for the amended work statement (sensitive field)
  • scale - Payment scale for the amended work statement (HOURLY, DAILY, WEEKLY, MONTHLY, BIWEEKLY, SEMIMONTHLY, CUSTOM)
  • job_title - Job title for the amended work statement
  • created_at - Timestamp when the work statement was created
  • updated_at - Timestamp when the work statement was last updated
  • currency_code - Currency code for the amended work statement
  • scope_of_work - Scope of work for the amended work statement
  • special_clause - Special clause for the amended work statement
  • termination_notice_days - Number of days notice required for termination

🚀 New Endpoint: Sign amendment

Allows workers to sign contract amendments with their signature.

API Reference: POST /rest/v2/workers/amendments/:amendment_id/sign

Request Body:

{
    "data": {
        "contractor_signature": "John Doe"
    }
}

Response:

{
    "data": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "is_signed": true
    }
}

Parameters:

  • contract_id (path, required) - The unique identifier of the contract
  • amendment_id (path, required) - The unique identifier of the amendment to sign

Token Scopes: worker:read, worker:write, benefits:read

Allowed Tokens: PAT:WORKER

Updated: GET /v2/eor/workers/compliance-documents/{document_id}/templates/download

Added updated_at parameter to response in order to show when document was last updated.

Endpoint:


Employee Agreement and Onboarding Tracking endpoints update

Improves Employee Agreement and Onboarding Tracking endpoints to allow for version validation during signature collection to avoid inconsistencies that could be caused by race condition.


Updated: POST /v2/eor/workers/contracts/:contract_id/signatures

  • Add an optional version property to the payload in order to allow the client to specify the version of the Employment Agreement to be signed. In case of a mismatch, the API will return a 409 Conflict error. If the version either matches the internal version or is not provided, the endpoint will behave as before.
  • Add a 409 Conflict error response to the response schema.

Endpoint: Sign a contract


Updated: GET /v2/eor/workers/contracts/:contract_id/employee-agreement/download

  • Add an optional version query param to the endpoint in order to allow the client to specify the version of the Employment Agreement to be downloaded. We don't keep multiple Employment Agreements saved, so this version is for checking if the client has the correct version of the EA. In case of a mismatch, the API will return a 409 Conflict error. If the version either matches the internal version or is not provided, the endpoint will behave as before.
  • Add a 409 Conflict error response to the response schema.

Endpoint: Download employee agreement PDF


Updated: GET /v2/onboarding/tracker/hris_profile/:hris_profile_id

  • Add a employee_agreement object to the response schema, with the following properties:
    • version_hash: Version of the Employment Agreement. Can be null if the EA has not yet been generated.
    • status: Status of the Employment Agreement. Can be null if the EA has not yet been generated.
  • The version_hash can be used to check if the client has the correct version of the EA when downloading or signing it as mentioned in the previous endpoints.

Endpoint: Get onboarding details by employee HRIS profile ID


Updated: GET /v2/onboarding/tracker/:tracker_id

  • Same changes as the previous onboarding endpoint.

Endpoint: Get onboarding details by onboarding tracker ID

List HR verification letters and documents

List all HR verification letters and documents available.

Endpoint: GET /rest/v2/eor/workers/contracts/:contract_id/hr-documents

Token scopes: worker:read

API Reference: List HR verification letters and documents

curl --request GET \
     --url 'https://api.letsdeel.com/rest/v2/eor/workers/contracts/:contract_id/hr-documents' \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'authorization: Bearer {{token}}'


Cost centers endpoints changes

Updated: Cost centers are now retrieved by legal_entity_id parameter, and the request and response format has been adjusted to cost_center_number and cost_center_name instead of number and name.

API Reference:

Updated: POST /v2/contacts endpoint

Added optionalcontract_template_id parameter to body to allow specifying a contract template when creating a contract.

Endpoints:

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