> This page is for CLI.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developer.deel.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developer.deel.com/_mcp/server.

# Idempotency and retries

> How the Deel CLI makes mutating commands safe to retry

The Deel API supports the `Idempotency-Key` header so that a retried request does not create a second record. The CLI attaches this header to every mutating request automatically and uses it to retry transient failures.

## Derived idempotency keys

For every `POST`, `PUT`, `PATCH`, and `DELETE` request, the CLI derives a UUID version 5 key from a canonical form of the request: the method, the path, the query parameters, and the body with object keys sorted. Re-running the identical command produces the identical key, and the API returns the original result instead of creating a duplicate.

```bash
deel adjustments create --invoice --input file://bonus.json --debug
# [debug] idempotency-key: 2f1a7c0e-9b3d-4e21-8a6f-5c9d3e7b1a04  (derived)
```

Because the key is derived from the content, two commands that differ in any field produce different keys. A command that intentionally creates a second identical record must supply its own key.

For multipart uploads the key is derived from the text fields plus each file's name and size, not the file bytes.

## Supplying your own key

`--idempotency-key <value>` replaces the derived key. Use it when you want a fresh attempt for a body that was already accepted, or when your own system already tracks an idempotency key per operation.

```bash
deel adjustments create --invoice --input file://bonus.json --idempotency-key "$(uuidgen)"
```

The key is also available in the local log entry of the request under `idempotency_key`, so an operator can correlate a CLI run with the API's view of the request.

## Retry policy

Which failures the CLI retries automatically:

| Condition                                               | Retried                     |
| ------------------------------------------------------- | --------------------------- |
| `GET` requests                                          | Yes                         |
| Mutating requests with an idempotency key (the default) | Yes                         |
| HTTP `429 Too Many Requests`                            | Yes, honoring `Retry-After` |
| HTTP `5xx`                                              | Yes                         |
| HTTP `4xx` other than `429`                             | No                          |
| Network errors and timeouts                             | No                          |

The CLI makes up to three attempts. When the response carries a `Retry-After` header, the CLI waits for that many seconds; otherwise it backs off exponentially starting at 200 ms. After the last attempt the response is returned as is and, for error statuses, mapped to the [error envelope](/cli/usage/errors).

> **Note**
>
> Retries are safe for mutating requests only because the same idempotency key is sent on every attempt. Passing `--idempotency-key` does not change this: the CLI reuses your key across its own retries.

## Relationship to the API

The CLI follows the API's [idempotency](/api/idempotency) semantics. Keys are scoped by the API in the same way as for any other client, so a key sent by the CLI and the same key sent by your application refer to the same request.

## Next steps

#### [Asynchronous jobs](/cli/usage/async-jobs)

Follow bulk operations that return a job id

#### [Errors and exit codes](/cli/usage/errors)

The error envelope after the last retry