> ## Documentation Index
> Fetch the complete documentation index at: https://code.dcycle.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Delete Employees (v2)

> Delete up to 5,000 employees by id, asynchronously, as an ingest job

[← Employees API](/api-reference/employees/overview)

Delete employees of the commuting survey by id. The request checks every id and answers `202 Accepted` with an
[ingest job](/api-reference/ingest-jobs/get) that deletes them in the background (see
[how bulk ingestion works](/api-reference/ingest-jobs/overview)). Follow it with
[`GET /v2/ingest-jobs/{id}`](/api-reference/ingest-jobs/get) or, for a job submitted with an API key, the
[`ingest_job.finished`](/api-reference/webhooks/overview) webhook.

The ids are the ones [Create Employees (v2)](/api-reference/employees/create-v2) answers, or the `id`s of
[List Employees](/api-reference/employees/list). Deleting an employee deletes their commuting periods, with their
emissions, and their survey answers.

<Warning>
  **Permanent.** Deleted employees cannot be recovered. Use `dry_run=true` first if you are not sure.
</Warning>

<Warning>
  **Beta.** Part of the bulk ingest API, in beta. The contract may still change before general availability.
</Warning>

<RequestExample>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST "https://api.dcycle.io/v2/employees/delete" \
    -H "x-api-key: ${DCYCLE_API_KEY}" \
    -H "x-organization-id: ${DCYCLE_ORG_ID}" \
    -H "Idempotency-Key: 2e1d0c9b-8a7f-4e6d-9c5b-4a3f2e1d0c9b" \
    -H "Content-Type: application/json" \
    -d '{"ids": ["4c3b2a19-0f8e-4d7c-9b6a-5f4e3d2c1b0a"]}'
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import os
  import uuid

  import requests

  response = requests.post(
      "https://api.dcycle.io/v2/employees/delete",
      headers={
          "x-api-key": os.environ["DCYCLE_API_KEY"],
          "x-organization-id": os.environ["DCYCLE_ORG_ID"],
          "Idempotency-Key": str(uuid.uuid4()),  # keep it to retry this same batch
      },
      json={"ids": ["4c3b2a19-0f8e-4d7c-9b6a-5f4e3d2c1b0a"]},
      timeout=60,
  )
  response.raise_for_status()
  print(response.json()["id"])
  ```
</RequestExample>

<ResponseExample>
  ```json 202 theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "id": "9d8c7b6a-5f4e-4d3c-8b2a-190f8e7d6c5b",
    "status": "processing",
    "entity_type": "employees",
    "operation": "delete",
    "source": "api_bulk",
    "counts": { "submitted": 1, "succeeded": 0, "failed": 0 },
    "chunks_total": 1,
    "chunks_done": 0,
    "created_at": "2026-10-20T09:20:31.877Z",
    "finished_at": null,
    "links": {
      "self": "/v2/ingest-jobs/9d8c7b6a-5f4e-4d3c-8b2a-190f8e7d6c5b",
      "items": "/v2/ingest-jobs/9d8c7b6a-5f4e-4d3c-8b2a-190f8e7d6c5b/items"
    }
  }
  ```

  ```json 422 theme={"theme":{"light":"github-light","dark":"github-dark"}}
  {
    "type": "https://code.dcycle.io/api-reference/errors#BULK_RECORDS_REJECTED",
    "title": "Unprocessable Entity",
    "status": 422,
    "code": "BULK_RECORDS_REJECTED",
    "detail": "1 of the submitted records are invalid; nothing was written.",
    "errors": [
      {
        "source_row_index": 0,
        "client_row_id": null,
        "error_code": "NOT_FOUND",
        "error_params": { "field": "ids", "value": "4c3b2a19-0f8e-4d7c-9b6a-5f4e3d2c1b0a" }
      }
    ],
    "rejected": 1,
    "request_id": "b2248a31-0f1b-4a7d-83ce-b29bd5977b4c"
  }
  ```

  ```json 200 (dry_run=true) theme={"theme":{"light":"github-light","dark":"github-dark"}}
  { "dry_run": true, "submitted": 1, "valid": 1 }
  ```
</ResponseExample>

## How it works

1. **The request checks every id.** One that does not exist, is deleted, is outside your organization's
   [perimeter](/api-reference/ingest-jobs/overview#perimeter) or is repeated rejects the **whole** request with `422`,
   and nothing is deleted.
2. **The job deletes them in the background**, with their commuting periods, the emissions, calculation data and
   custom column values of those periods, their own custom column values and their survey answers.
3. **When every chunk is done** the job is `completed` (or `completed_with_errors`). For a job submitted with an API
   key, `ingest_job.finished` is sent with `"operation": "delete"` to the webhook endpoints of the `x-organization-id`
   organization.

## Request

### Headers

<ParamField header="x-api-key" type="string" required>
  Your API key (see [Authentication](/api-reference/introduction#authentication)).
</ParamField>

<ParamField header="x-organization-id" type="string" required>
  The organization the employees are deleted for. Its employees, and those of the organizations under it that you can
  write to (its [perimeter](/api-reference/ingest-jobs/overview#perimeter)), can be deleted.
</ParamField>

<ParamField header="Idempotency-Key" type="string" required>
  1 to 255 characters, one per batch, looked up per organization across every v2 bulk route. Within 24 hours, the
  same key with the same route and body returns the original job (with `Idempotent-Replayed: true`); the same key with
  another body or on another route is `422 IDEMPOTENCY_KEY_REUSED`, and while the first request is still being
  processed `409 IDEMPOTENCY_KEY_IN_PROGRESS`. After 24 hours the key is free, and a request with it is a new one. See
  [The Idempotency-Key](/api-reference/ingest-jobs/overview#the-idempotency-key).
</ParamField>

### Query Parameters

<ParamField query="dry_run" type="boolean" default="false">
  Check only: the same `422` for bad ids, nothing deleted, no job; `200` with `{"dry_run": true, "submitted": n,
      "valid": n}` when every id is valid. It does not check or store the `Idempotency-Key`.
</ParamField>

### Body Parameters

<ParamField body="ids" type="array[uuid]" required>
  Employee ids, 1 to 5,000, each once.
</ParamField>

## Response

`202 Accepted` with the job (`entity_type: employees`, `operation: delete`) and a `Location` header to it.
[`GET /v2/ingest-jobs/{id}/items`](/api-reference/ingest-jobs/list-items) has one item per employee, in the order sent;
an item is `failed` with `DELETE_FAILED` when its employee was already gone by the time the job reached it.

## Errors

[Problem details](/api-reference/errors). Per-id codes in `errors[].error_code` of a `422 BULK_RECORDS_REJECTED`
(`source_row_index` is the position in `ids`):

| `error_code` | Cause |
| - | - |
| `NOT_FOUND` | The employee does not exist, is deleted or is outside your organization's [perimeter](/api-reference/ingest-jobs/overview#perimeter) (all answer the same). |
| `DUPLICATE_ID` | The employee is already in the request. |

Request-level errors: `401` for a missing or invalid API key, `403 LOGGED_USER_NOT_MEMBER` when the key's user is not a
member of the organization, `422 REQUEST_VALIDATION_FAILED` for a malformed body (no `ids`, more than 5,000, no
`Idempotency-Key`), `422 IDEMPOTENCY_KEY_REUSED`, `409 IDEMPOTENCY_KEY_IN_PROGRESS`, and `429` beyond the
[rate limits](/api-reference/rate-limits).

## Limits

| Limit | Value |
| - | - |
| Ids per request | 1 to 5,000 |
| Employees per deletion chunk | 200 |

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Create Employees (v2)" icon="plus" href="/api-reference/employees/create-v2">
    Create employees in bulk
  </Card>

  <Card title="List Employees" icon="users" href="/api-reference/employees/list">
    Find the ids to delete
  </Card>

  <Card title="Get Ingest Job" icon="magnifying-glass" href="/api-reference/ingest-jobs/get">
    Follow the deletion
  </Card>

  <Card title="List Job Items" icon="list" href="/api-reference/ingest-jobs/list-items">
    The outcome of each id
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.