<!-- Markdown copy of https://docs.creatorain.com/errors/ -->
# Errors

Every error has one envelope:

```json
{ "error": { "type": "permission_error", "code": "scope_missing", "message": "...", "field": "...", "doc_url": "https://docs.creatorain.com/errors#scope_missing", "request_id": "..." } }
```

-   **Branch on `code`**, never on `message`. Messages may change.
-   `type` groups codes: `invalid_request_error`, `authentication_error`, `permission_error`, `idempotency_error`, `rate_limit_error`, `api_error`.
-   `field` names the request field at fault, when one is.
-   `request_id` equals the `Request-Id` header. Quote it to support.
-   A `5xx` message never carries a cause.

Each code below has its own anchor, `/errors#<code>`. A code marked **Not live yet** is designed, but no live route returns it yet.

**Note:** Today an error’s `doc_url` still points at the old www address. It moves to this page at launch.

## 400 Bad request

### `parameter_invalid`

HTTP 400, type `invalid_request_error`.

A query or body field is wrong. `field` names it. A cursor you changed is this error too.

**Fix:** Correct the field named in `field` and retry.

### `invalid_json`

HTTP 400, type `invalid_request_error`.

The request body is not valid JSON.

**Fix:** Send a valid JSON body with `Content-Type: application/json`.

### `idempotency_key_invalid`

HTTP 400, type `invalid_request_error`.

The `Idempotency-Key` header is empty, longer than 255 characters, or has spaces or non-printable characters.

**Fix:** Send 1 to 255 printable ASCII characters, no spaces.

### `idempotency_key_required`

HTTP 400, type `invalid_request_error`.

This call needs an `Idempotency-Key` header. Location creates and money calls require one. A dry run needs one too.

**Fix:** Add a unique `Idempotency-Key` per logical request.

### `customization_not_supported`

HTTP 400, type `invalid_request_error`.

The request set a creator field, such as `min_followers`, `rules` or `approval_mode`. CreatoRain chooses the creators.

**Fix:** Remove every creator field from the request.

### `videos_per_month_out_of_range`

HTTP 400, type `invalid_request_error`.

`videos_per_month` is outside the plan's range. Paid: 2 to 10. Free: exactly the free plan's videos.

**Fix:** Send a value inside the range.

### `batch_invalid`

HTTP 400, type `invalid_request_error`.

A batch had one or more refused items. Nothing was written. `error.items` lists each refused item by index.

**Fix:** Fix every item in `error.items` and send the whole batch again.

### `terms_not_accepted`

HTTP 400, type `invalid_request_error`.

A new or returning store needs `accepted_terms`, the network terms version accepted.

**Fix:** Send `accepted_terms` with the terms version the store accepted.

### `invalid_filter`

HTTP 400, type `invalid_request_error`. Not returned: see [`parameter_invalid`](#parameter_invalid).

Named in the design for a bad search filter. The API does not return it: a bad filter answers `parameter_invalid`.

**Fix:** Handle `parameter_invalid`.

### `invalid_request`

HTTP 400, type `invalid_request_error`. Not returned: see [`parameter_invalid`](#parameter_invalid).

Named in the design for a bad request field. The API does not return it: a bad field answers `parameter_invalid`.

**Fix:** Handle `parameter_invalid`.

### `cursor_expired`

HTTP 400, type `invalid_request_error`. Not returned: see [`parameter_invalid`](#parameter_invalid).

Named in the design for a cursor that no longer works. The API does not return it: a changed cursor answers `parameter_invalid`.

**Fix:** Handle `parameter_invalid`, then start the list again without a cursor.

## 401 Unauthorized

### `invalid_key`

HTTP 401, type `authentication_error`.

The key is missing, unknown or revoked.

**Fix:** Send `Authorization: Bearer <key>` with an active key.

### `test_key_on_live`

HTTP 401, type `authentication_error`.

A `crp_test_` key was sent to the live host.

**Fix:** Use a live key on live, or call the sandbox.

### `live_key_on_sandbox`

HTTP 401, type `authentication_error`.

A `crp_live_` key was sent to the sandbox.

**Fix:** Use a test key on the sandbox.

## 402 Payment required

### `insufficient_balance`**(Not live yet)**

HTTP 402, type `invalid_request_error`.

Your balance cannot cover this call. A batch create with `require_funded: true` and a billed creator-data call answer it. A store added without `require_funded` waits in `awaiting_payment` instead.

**Fix:** Top up, then retry with a new `Idempotency-Key`. A 402 answer is stored for the old key.

### `spend_limit_reached`**(Not live yet)**

HTTP 402, type `invalid_request_error`. Not in the v1 spec yet.

A creator-data call would go over the daily or monthly data spend limit. Nothing is billed.

**Fix:** Wait for the next day or month, or raise the limit in the app. Retry with a new `Idempotency-Key`.

### `max_cost_exceeded`**(Not live yet)**

HTTP 402, type `invalid_request_error`. Not in the v1 spec yet.

The call's worst-case cost is above the `max_cost_cents` you sent. It did not run.

**Fix:** Raise `max_cost_cents`, or ask for fewer rows. Retry with a new `Idempotency-Key`.

### `reveal_expired`**(Not live yet)**

HTTP 402, type `invalid_request_error`. Not in the v1 spec yet.

`GET /v1/creators/{id}` came more than 30 days after the last paid read of that creator. A GET never spends money.

**Fix:** Call `POST /v1/creators/enrich/handle` to read the creator again (billed).

## 403 Forbidden

### `scope_missing`

HTTP 403, type `permission_error`.

The key lacks the scope this route needs.

**Fix:** Create a key with the scope, or ask the workspace owner.

### `forbidden_ip`

HTTP 403, type `permission_error`.

The key has an IP allowlist, and this request came from another address.

**Fix:** Call from an allowed address, or update the allowlist in the app.

### `forbidden`

HTTP 403, type `permission_error`.

The action is not allowed for this account.

**Fix:** Check the account's state with `GET /account`.

### `live_key_requires_top_up`

HTTP 403, type `permission_error`.

A live key needs one paid top-up on the account first.

**Fix:** Make a first top-up in the app, then approve the key again.

### `limit_raise_requires_dashboard`**(Not live yet)**

HTTP 403, type `permission_error`.

The API can lower a spend limit, never raise one.

**Fix:** Raise the limit in the app.

## 404 Not found

### `not_found`

HTTP 404, type `invalid_request_error`.

No such object for this account. A malformed id, an unknown id and another account's id all answer the same.

**Fix:** Check the id and the key's workspace.

## 409 Conflict

### `idempotency_conflict`

HTTP 409, type `idempotency_error`.

The same `Idempotency-Key` was sent with a different body.

**Fix:** Use a new key for a new request.

### `idempotency_in_progress`

HTTP 409, type `idempotency_error`.

The first request with this key is still running.

**Fix:** Wait, then retry with the same key and body.

### `conflict`

HTTP 409, type `invalid_request_error`.

The request conflicts with the object's current state.

**Fix:** Read the object again, then retry.

### `location_already_in_network`

HTTP 409, type `invalid_request_error`.

Another team of this account holds the place, or the same place is listed under another name.

**Fix:** Use the existing location, or ask the team that holds it.

### `external_id_conflict`**(Not live yet)**

HTTP 409, type `invalid_request_error`.

Your `external_id` label is already used in this workspace.

**Fix:** Use a unique `external_id`.

### `dispute_open`**(Not live yet)**

HTTP 409, type `invalid_request_error`.

A card dispute is open on this account.

**Fix:** Contact support with the `request_id`.

### `job_limit_reached`**(Not live yet)**

HTTP 409, type `invalid_request_error`. Not in the v1 spec yet.

The account already has 5 active creator-data jobs.

**Fix:** Wait for a job to finish, then create the new one.

## 413 Request too large

### `request_too_large`

HTTP 413, type `invalid_request_error`.

The request body is too large.

**Fix:** Send fewer items per request. A batch takes at most 50 locations.

## 422 Unprocessable

### `address_not_verified`**(Not live yet)**

HTTP 422, type `invalid_request_error`.

The store's address could not be verified.

**Fix:** Send the full street address, or a `google_place_id`.

### `not_food_business`**(Not live yet)**

HTTP 422, type `invalid_request_error`.

The place is not a restaurant or food business.

**Fix:** Check the address or place id.

### `metro_not_served`**(Not live yet)**

HTTP 422, type `invalid_request_error`.

CreatoRain does not serve this metro yet.

**Fix:** Try again later, or contact support.

### `package_not_available`

HTTP 422, type `invalid_request_error`.

The plan asked for is not the account's plan, or a free-plan account tried to bring back a store that already ran its free term.

**Fix:** Omit `plan` to use the account's plan.

### `account_location_limit`**(Not live yet)**

HTTP 422, type `invalid_request_error`.

The account has reached its location limit.

**Fix:** Contact support to raise it.

### `commit_limit_exceeded`**(Not live yet)**

HTTP 422, type `invalid_request_error`.

The call would go over the account's monthly spend limit.

**Fix:** Raise the limit in the app, or plan fewer videos.

### `top_up_exceeds_feasible`**(Not live yet)**

HTTP 422, type `invalid_request_error`.

The top-up is larger than the account can spend soon.

**Fix:** Top up a smaller amount.

### `no_saved_card`**(Not live yet)**

HTTP 422, type `invalid_request_error`.

The call needs a saved card, and the account has none.

**Fix:** Save a card in the app.

### `data_price_not_set`**(Not live yet)**

HTTP 422, type `invalid_request_error`. Not in the v1 spec yet.

A creator-data product has no published price yet, so the call is refused and nothing is billed.

**Fix:** Try again after prices are published.

### `min_locations_not_met`**(Not live yet)**

HTTP 422, type `invalid_request_error`. Not in the v1 spec yet.

Creator data needs an account with enough counting locations and a prepaid balance. `blockers[]` and `next_action` say what is missing. Never billed.

**Fix:** Do the `next_action`, then retry.

### `platform_not_supported`**(Not live yet)**

HTTP 422, type `invalid_request_error`. Not in the v1 spec yet.

The platform is not one CreatoRain holds. At launch: `instagram`, `tiktok`, `youtube`. Never billed.

**Fix:** Send one of the supported platforms.

### `audience_not_available`**(Not live yet)**

HTTP 422, type `invalid_request_error`. Not in the v1 spec yet.

Audience fields are reserved in the schema, but no data is served for them yet. Never billed.

**Fix:** Leave the audience fields out of the request.

## 429 Too many requests

### `rate_limited`

HTTP 429, type `rate_limit_error`.

Over the limit: 600 requests a minute per workspace, the onboarding create limit, or an address blocked after failed sign-ins.

**Fix:** Wait `Retry-After` seconds, then retry.

### `quota_exceeded`**(Not live yet)**

HTTP 429, type `rate_limit_error`.

A usage quota for this period is used up.

**Fix:** Wait for the next period, or contact support.

### `slow_down`

HTTP 429, type `rate_limit_error`.

An onboarding session was polled sooner than its `interval`. The interval grows by 5 seconds, up to 60.

**Fix:** Wait `Retry-After` seconds between polls.

## 500 Server error

### `internal_error`

HTTP 500, type `api_error`.

Something failed on our side. The message never carries a cause.

**Fix:** Retry with the same `Idempotency-Key`. Quote the `request_id` to support if it repeats.

## 503 Unavailable

### `service_unavailable`

HTTP 503, type `api_error`.

The service cannot answer right now. A concurrent write to the same locations also answers this. The bill preview answers it over 2,000 locations.

**Fix:** Retry after `Retry-After` with the same key.

### `vendor_unavailable`**(Not live yet)**

HTTP 503, type `api_error`. Not in the v1 spec yet.

The outside source behind a vendor-backed creator-data field cannot answer right now. Never billed.

**Fix:** Retry after `Retry-After`.
