<!-- Source: https://useworkloom.com/dev/errors/ · Workloom API v1 -->

# Errors

Errors use ordinary HTTP status codes and always return the same JSON: a `code` to branch on and an `error` sentence you can show.

**Error response**

```json
{
  "error": "This person is already in your workspace.",
  "code": "duplicate",
  "duplicates": [
    {
      "type": "contact",
      "id": "66f2a1c0e4b0a1b2c3d4e5f6",
      "name": "Priya Nair",
      "reason": "Same email",
      "yours": true
    }
  ],
  "can_force": false
}
```

409 Conflict

- `code`: The exact reason, from the list below. It does not change, so branch on this.
- `error`: Plain words for logs or your own screens. It may be reworded, so do not match on it.
- `…`: Some codes add details: `required` and `granted`, `unknown_fields` and `accepted_fields`, `missing_fields`, `problems`, `duplicates` and `can_force`, `deal_id`.

## All error codes

| Status | Code | What happened | What to do |
| --- | --- | --- | --- |
| 401 | `authentication_required` | No key was sent. | Send `Authorization: Bearer` with your key, or `X-API-Key`. |
| 401 | `invalid_key` | The key is wrong, revoked or expired. One answer for all three. | Check you copied the whole key. If it was revoked, make a new one in Settings › API and webhooks. |
| 403 | `organisation_inactive` | The workspace is not active. | The workspace is closed or suspended. Ask its admin. |
| 403 | `seat_inactive` | The person or service account this key acts for is no longer active. | The key acts for a person or service account that was suspended. Use another key. |
| 403 | `missing_scope` | The key was not given the scope this endpoint needs. `required` and `granted` say which. | Add the scope named in `required`, or use a key that has it. |
| 403 | `forbidden` | The key’s role or reach does not allow this. | The key’s role does not allow this, or a condition on the role (hours, network) refused it. |
| 404 | `not_found` | No such record, or one the key cannot reach. The same answer for both. | Check the id, and that the key’s workspace and reach include the record. |
| 400 | `invalid_request` | The request is missing something or a value is wrong. `problems` lists each one when there are several. | Read `error` (and `problems` or `missing_fields`), fix the value and send again. |
| 400 | `unknown_fields` | The body has a field this endpoint does not accept. `unknown_fields` and `accepted_fields` say which. | Remove the fields in `unknown_fields`. `accepted_fields` lists what the endpoint takes. |
| 400 | `reason_required` | Moving a deal to a lost stage needs `reason_code`. | Send `reason_code`, one of your lost reasons. |
| 422 | `stage_requirements_missing` | The stage needs fields the deal does not have yet. `missing_fields` lists each `{ key, label }`; send them in `fields`. | Send the fields in `missing_fields` in the move’s `fields`, then move again. |
| 409 | `suppressed` | The contact was deleted and is on the do-not-contact list, so the same address is not added again. | They were deleted and asked not to be contacted. Keep them out of your source of contacts. |
| 409 | `duplicate` | The record already exists. `duplicates` (contacts, companies) or `deal_id` (deals) points at it when the key can reach it. | Use the record in `duplicates` or `deal_id`. For a contact or company with only a similar name, send `force: true`. |
| 409 | `conflict` | The record changed in a way that stops this request. | Read the record again and decide from what it says now. |
| 409 | `idempotency_key_in_use` | A request with this Idempotency-Key is still running. Retry shortly. | Wait a moment and retry with the same key. |
| 422 | `idempotency_key_reused` | This Idempotency-Key was used for a different request. | Use a new Idempotency-Key for a new request. |
| 400 | `unsupported_version` | The `Workloom-Version` header names no version. `versions` lists the ones there are. | Send one of the versions in `versions`, or leave `Workloom-Version` out to use your key’s. |
| 404 | `sandbox_only` | This endpoint works in a developer sandbox only: sandbox-api.useworkloom.com, with a `wl_sbx_` key. | Send it to the sandbox, `https://sandbox-api.useworkloom.com/api/public/v1`, with a `wl_sbx_` key. |
| 401 | `sandbox_key` | A developer sandbox key (`wl_sbx_`) was sent to the live API. Send it to sandbox-api.useworkloom.com. | Send a `wl_sbx_` key to the sandbox address, or use a live key here. |
| 429 | `rate_limited` | More requests a minute than the key is allowed. Wait `Retry-After` seconds. | Wait `Retry-After` seconds, then retry. |
| 500 | `internal_error` | Something failed on our side. Safe to retry with the same Idempotency-Key. | Retry with backoff and the same Idempotency-Key. If it keeps happening, email us. |

## Safe retries

Retry `429` and `5xx` answers with backoff. Send an `Idempotency-Key` header on every POST: if a retry reaches Workloom twice, the second gets the first answer instead of making a duplicate. A key is kept 24 hours. Using it again for a different request gets `422` `idempotency_key_reused`, and using it while the first request is still running gets `409` `idempotency_key_in_use`.
