Stitchflow
Deel logo

Deel User Management API Guide

API workflow

How to automate user lifecycle operations through APIs with caveats that matter in production.

UpdatedMar 9, 2026

Summary and recommendation

Deel's REST API (base URL: https://api.letsdeel.com/rest/v2) uses Bearer token auth issued from Settings → Integrations → API Tokens, with OAuth 2.0 client credentials available for partner integrations. The critical architectural fact for any identity graph integration is that Deel's data model is contract-centric: worker creation, termination, and most lifecycle mutations operate on /contracts, not /people.

A person record is a side-effect of contract creation; a single person_id can be associated with multiple contract_ids (e.g., a contractor engagement followed by an EOR contract), and these identifiers are distinct and must both be stored.

SCIM 2.0 is available at https://app.deel.com/scim/v2 on Enterprise plans only, requires SAML 2.0 SSO as a prerequisite, and is officially supported for Okta, JumpCloud, and Microsoft Entra ID.

API quick reference

Has user APIYes
Auth methodBearer token (API key issued from Deel dashboard; OAuth 2.0 client credentials also documented for partner integrations)
Base URLOfficial docs
SCIM availableYes
SCIM plan requiredEnterprise

Authentication

Auth method: Bearer token (API key issued from Deel dashboard; OAuth 2.0 client credentials also documented for partner integrations)

Setup steps

  1. Log in to the Deel dashboard as an admin.
  2. Navigate to Settings → Integrations → API Tokens.
  3. Generate a new API token and copy the value immediately (shown once).
  4. Pass the token in the Authorization header: 'Authorization: Bearer '.
  5. For OAuth 2.0 partner flows: register an app in the Deel developer portal to obtain client_id and client_secret, then POST to https://api.letsdeel.com/oauth/token with grant_type=client_credentials.

Required scopes

Scope Description Required for
people:read Read worker/employee profile data. List and retrieve people/workers
people:write Create and update worker profiles. Invite or update workers
contracts:read Read contract details associated with workers. Fetching contract-linked user data
webhooks:write Register and manage webhook endpoints. Webhook subscription management

User object / data model

Field Type Description On create On update Notes
id string (UUID) Unique Deel identifier for the person. system-generated immutable Use this ID for all subsequent API calls.
first_name string Legal first name. required optional
last_name string Legal last name. required optional
email string Primary work email address. required optional Must be unique within the organization.
nationality string (ISO 3166-1 alpha-2) Country of nationality. optional optional
country_of_residence string (ISO 3166-1 alpha-2) Country where the worker resides. optional optional
job_title string Worker's job title. optional optional
department string Department or team name. optional optional
manager_id string (UUID) Deel ID of the direct manager. optional optional
employment_type enum Type of engagement: employee, contractor, eor. required read-only after creation Determines which contract flow applies.
start_date string (ISO 8601 date) Contract or employment start date. required optional
end_date string (ISO 8601 date) Contract end date (fixed-term). optional optional Null for indefinite contracts.
status enum Worker status: active, inactive, pending. system-set via termination/activation endpoints
currency string (ISO 4217) Payment currency. required optional
salary_amount number Gross salary or rate amount. required optional Interpretation depends on pay_frequency.
pay_frequency enum Payment frequency: monthly, biweekly, weekly. required optional
timezone string (IANA tz) Worker's timezone. optional optional
phone_number string Contact phone number. optional optional
custom_fields object Key-value map of organization-defined custom attributes. optional optional Keys must be pre-configured in Deel settings.
created_at string (ISO 8601 datetime) Timestamp of record creation. system-generated immutable

Core endpoints

List people (workers)

  • Method: GET
  • URL: https://api.letsdeel.com/rest/v2/people
  • Watch out for: Returns all worker types (employees, contractors, EOR). Filter by employment_type query param if needed.

Request example

GET /rest/v2/people?limit=20&offset=0
Authorization: Bearer <token>

Response example

{
  "data": [
    {"id": "abc-123", "first_name": "Jane", "last_name": "Doe", "email": "jane@acme.com", "status": "active"}
  ],
  "page": {"total": 150, "limit": 20, "offset": 0}
}

Get a single person

  • Method: GET
  • URL: https://api.letsdeel.com/rest/v2/people/{person_id}
  • Watch out for: person_id is the Deel UUID, not the contract ID. These are distinct identifiers.

Request example

GET /rest/v2/people/abc-123
Authorization: Bearer <token>

Response example

{
  "data": {
    "id": "abc-123",
    "first_name": "Jane",
    "email": "jane@acme.com",
    "status": "active",
    "job_title": "Engineer"
  }
}

Invite a new worker

  • Method: POST
  • URL: https://api.letsdeel.com/rest/v2/contracts
  • Watch out for: Worker creation is contract-centric in Deel. A person record is created as a side-effect of contract creation, not via a standalone /people POST.

Request example

POST /rest/v2/contracts
Authorization: Bearer <token>
Content-Type: application/json
{
  "type": "employee",
  "worker_email": "new@acme.com",
  "first_name": "John",
  "last_name": "Smith",
  "start_date": "2025-06-01"
}

Response example

{
  "data": {
    "id": "contract-456",
    "status": "pending",
    "worker_email": "new@acme.com"
  }
}

Update a person's profile

  • Method: PATCH
  • URL: https://api.letsdeel.com/rest/v2/people/{person_id}
  • Watch out for: Not all fields are patchable post-contract-signing. Employment type and salary changes may require a contract amendment flow.

Request example

PATCH /rest/v2/people/abc-123
Authorization: Bearer <token>
Content-Type: application/json
{
  "job_title": "Senior Engineer",
  "department": "Platform"
}

Response example

{
  "data": {
    "id": "abc-123",
    "job_title": "Senior Engineer",
    "department": "Platform"
  }
}

Terminate a worker

  • Method: POST
  • URL: https://api.letsdeel.com/rest/v2/contracts/{contract_id}/terminations
  • Watch out for: Termination is contract-scoped. A person with multiple contracts requires separate termination calls per contract.

Request example

POST /rest/v2/contracts/contract-456/terminations
Authorization: Bearer <token>
Content-Type: application/json
{
  "termination_date": "2025-07-31",
  "reason": "resignation"
}

Response example

{
  "data": {
    "contract_id": "contract-456",
    "status": "terminated",
    "termination_date": "2025-07-31"
  }
}

List contracts

  • Method: GET
  • URL: https://api.letsdeel.com/rest/v2/contracts
  • Watch out for: Contract IDs and person IDs are different. Store both if you need to cross-reference.

Request example

GET /rest/v2/contracts?status=active&limit=50
Authorization: Bearer <token>

Response example

{
  "data": [
    {"id": "contract-456", "type": "employee", "status": "active", "worker_email": "jane@acme.com"}
  ],
  "page": {"total": 80, "limit": 50, "offset": 0}
}

List webhook subscriptions

  • Method: GET
  • URL: https://api.letsdeel.com/rest/v2/webhooks
  • Watch out for: Webhook secrets must be stored at creation time; they are not retrievable afterward.

Request example

GET /rest/v2/webhooks
Authorization: Bearer <token>

Response example

{
  "data": [
    {"id": "wh-789", "url": "https://yourapp.com/hook", "events": ["contract.created"]}
  ]
}

Create a webhook subscription

  • Method: POST
  • URL: https://api.letsdeel.com/rest/v2/webhooks
  • Watch out for: The 'secret' field is only returned on creation. Use it to verify HMAC signatures on incoming payloads.

Request example

POST /rest/v2/webhooks
Authorization: Bearer <token>
Content-Type: application/json
{
  "url": "https://yourapp.com/hook",
  "events": ["contract.created", "contract.terminated"]
}

Response example

{
  "data": {
    "id": "wh-789",
    "secret": "whsec_abc123",
    "events": ["contract.created", "contract.terminated"]
  }
}

Rate limits, pagination, and events

  • Rate limits: Deel enforces per-token rate limits. Official documentation does not publish exact numeric limits publicly; limits are enforced and communicated via response headers.
  • Rate-limit headers: Yes
  • Retry-After header: Yes
  • Rate-limit notes: When rate limited, Deel returns HTTP 429. Inspect X-RateLimit-Limit, X-RateLimit-Remaining, and Retry-After headers. Exact limits are not published in official docs as of this research.
  • Pagination method: offset
  • Default page size: 10
  • Max page size: 100
  • Pagination pointer: limit / offset
Plan Limit Concurrent
Standard API token Not publicly documented; contact Deel for specifics 0
  • Webhooks available: Yes
  • Webhook notes: Deel supports outbound webhooks registered via the API or dashboard. Payloads are signed with HMAC-SHA256 using a secret provided at subscription creation.
  • Alternative event strategy: Poll GET /rest/v2/people or GET /rest/v2/contracts with updated_since filter for systems that cannot receive webhooks.
  • Webhook events: contract.created, contract.updated, contract.terminated, contract.signed, payment.completed, worker.profile_updated, offboarding.initiated

SCIM API status

  • SCIM available: Yes

  • SCIM version: 2.0

  • Plan required: Enterprise

  • Endpoint: https://app.deel.com/scim/v2

  • Supported operations: GET /Users, GET /Users/{id}, POST /Users, PUT /Users/{id}, PATCH /Users/{id}, DELETE /Users/{id}, GET /Groups, POST /Groups, PATCH /Groups/{id}, DELETE /Groups/{id}

Limitations:

  • Requires SAML 2.0 SSO to be configured before SCIM can be enabled.
  • Supported IdPs: Okta, JumpCloud, Microsoft Entra ID (Azure AD). Google Workspace and OneLogin not officially documented.
  • SCIM provisioning creates pending worker invitations; workers must still complete onboarding in Deel.
  • Deprovisioning via SCIM deactivates the Deel account but does not automatically terminate contracts.
  • Group push maps to Deel departments; department names must match exactly.
  • Available on Enterprise plan only; not available on free HR or standard paid tiers.

Common scenarios

Three integration patterns cover the majority of production use cases. First, contractor onboarding: POST to /rest/v2/contracts with type=contractor; the returned response contains both contract_id and person_id, both of which must be persisted for downstream identity graph resolution.

The contract status stays 'pending' until the worker completes KYC and banking setup-poll GET /rest/v2/contracts/{contract_id} or subscribe to the contract. signed webhook to gate downstream provisioning on confirmed activation.

Second, directory sync: paginate GET /rest/v2/people with limit=100/offset=0, storing id, email, status, job_title, department, and manager_id per record; subscribe to worker. profile_updated and contract.

terminated webhooks for real-time delta updates, since updated_since filtering availability is not guaranteed and full-page polling is expensive at scale.

Third, SCIM deprovision (Enterprise): IdP deactivation sends PATCH /Users/{id} with active=false to Deel's SCIM endpoint, which disables login access only-contract termination must be triggered separately via POST /rest/v2/contracts/{contract_id}/terminations, as SCIM deactivation does not cascade to payroll or contract obligations.

Onboard a new contractor

  1. POST /rest/v2/contracts with type=contractor, worker_email, first_name, last_name, start_date, currency, and rate fields.
  2. Store the returned contract_id and the associated person_id from the response.
  3. Poll GET /rest/v2/contracts/{contract_id} or listen for the contract.signed webhook to confirm the worker has completed onboarding.
  4. Once active, use GET /rest/v2/people/{person_id} to retrieve the full profile.

Watch out for: The worker receives an email invitation and must self-complete KYC/banking details. The contract status remains 'pending' until they do.

Sync Deel workers to an external directory via REST API

  1. GET /rest/v2/people?limit=100&offset=0 and paginate through all pages.
  2. For each person, store id, email, status, job_title, department, and manager_id.
  3. On subsequent syncs, use an updated_since query parameter (if supported) or compare stored records to detect changes.
  4. Subscribe to worker.profile_updated and contract.terminated webhooks to receive real-time delta updates.

Watch out for: If updated_since filtering is unavailable, full-page polling is required, which is expensive for large orgs. Webhooks are strongly preferred for change detection.

Deprovision a worker via SCIM (Enterprise)

  1. Ensure SAML SSO and SCIM are configured in Deel Settings → Integrations → SSO & SCIM.
  2. In the IdP (e.g., Okta), deactivate or unassign the user from the Deel SCIM application.
  3. The IdP sends a PATCH /Users/{id} with active=false to Deel's SCIM endpoint.
  4. Verify in Deel dashboard that the worker's account is deactivated.
  5. Separately initiate contract termination via POST /rest/v2/contracts/{contract_id}/terminations if required, as SCIM deactivation does not auto-terminate contracts.

Watch out for: SCIM deactivation only disables login access. Payroll and contract obligations remain active until explicitly terminated through the Deel contract termination flow.

Why building this yourself is a trap

Several non-obvious behaviors will cause silent failures in automated pipelines. API token scopes are immutable after creation; changing required scopes means generating a new token entirely.

SCIM bearer tokens are issued from the SSO/SCIM settings section and are separate from general API tokens-using the wrong token against the SCIM endpoint will return auth errors with no clear indication of the cause.

Pagination is offset-based with no cursor support; concurrent writes during a full sync can produce duplicate or missing records across pages, so large-org syncs should be scheduled during low-write windows or reconciled against webhook events.

Webhook HMAC secrets (used to verify SHA-256 signatures on incoming payloads) are returned only at subscription creation and are not retrievable afterward; losing the secret requires deleting and recreating the subscription. Rate limit thresholds are not publicly documented-implement exponential backoff on HTTP 429 and inspect X-RateLimit-Limit, X-RateLimit-Remaining, and Retry-After response headers to adapt dynamically.

Finally, the v1 base URL (https://api.letsdeel.com/v1) is deprecated in favor of v2 (https://api.letsdeel.com/rest/v2); any integration built against v1 endpoints should be migrated before they are removed.

Automate Deel workflows without one-off scripts

Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.

Every app coverage, including apps without APIs
60+ app integrations plus browser automation for apps without APIs
IT graph reconciliation across apps and your IdP
Less than a week to launch, maintained as APIs and admin consoles change
SOC 2 Type II. ~2 hours of your team's time

UpdatedMar 9, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

15Five logo

15Five

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

15Five uses a fixed role-based permission model with six predefined roles: Account Admin, HR Admin, Billing Admin, Group Admin, Manager, and Employee. No custom roles can be constructed. User management lives at Settings gear → People → Manage people p

1Password logo

1Password

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

1Password's admin console at my.1password.com covers the full user lifecycle — invitations, group assignments, vault access, suspension, and deletion — without any third-party tooling. Like every app that mixes role-based and resource-level permissions

8x8 logo

8x8

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

8x8 Admin Console supports full lifecycle user management — create, deactivate, and delete — across its X Series unified communications platform. Every app a user can access (8x8 Work desktop, mobile, web, Agent Workspace) is gated by license assignmen