# Errors and limits

> Every error code with its cause and fix, the per-row errors, rate limits, Retry-After, idempotency keys and the 500-row limit.

Every error answers `{ "code": <HTTP status>, "message": "…", "rcode": "…" }`. Branch on `rcode` (stable) and show `message` to people. Some errors have no `rcode`; use the HTTP status for those.

The connector returns the backend's message and `rcode` inside the tool result, marked as an error. A permission the connection lacks is refused by the connector itself before any call, with a message naming the permission.

## Error codes

| HTTP | rcode | Cause | Fix |
|---|---|---|---|
| 400 | none | The body is invalid. The message names the field, e.g. `"products[0].prize" is not allowed`. Unknown fields are refused by name. | Fix the field and send again. |
| 401 | `Y20` | No `Authorization: Bearer` header. | Send `Authorization: Bearer ssk_…`. |
| 401 | `Y21` | The key is unknown or revoked. | Ask the owner for a valid key. Don't retry with the same key. |
| 401 | `Y22` | The key has expired. | The owner creates a new key in **Settings → API keys**. |
| 403 | `Y31` | The shop is not on a monthly plan. | The owner moves the shop to a monthly plan. Retrying won't help. |
| 403 | `Y32` | The shop is not active (deactivated or archived). | Tell the owner. Retrying won't help. |
| 403 | `Y34` | The person who created the key, or approved the connection, left the shop or can no longer manage API keys. | An owner or admin creates a new key or connects again. |
| 403 | `Y35` | The key or connection doesn't have the permission this call needs (`catalog:write`, `stock:write` or `promotions:write`). | Create a key with that permission, or reconnect and tick it. |
| 401 | `Y41` | Connector only: the assistant's sign-in expired or isn't valid. | The assistant signs in again (most do this on their own). |
| 401 | `Y42` | Connector only: the owner disconnected the assistant. | The owner connects it again. |
| 403 | none | A marketplace promotion: read-only here. | Change it in the marketplace's seller center. |
| 404 | none | No promotion with this id and type in this shop. | List promotions to get a valid id. |
| 409 | none | On a promotion update: the new code is already used by another promotion of the shop. | Pick another code. |
| 429 | `R01` | Too many requests. | Wait the `Retry-After` seconds, then send the same request again. |

On creating a promotion, an unknown SKU or a code the shop already uses is a `400` whose message says which.

### Key management in the dashboard

| HTTP | rcode | Cause |
|---|---|---|
| 403 | `Y31` | Creating a key while the shop is not on a monthly plan. |
| 409 | `Y33` | The shop already has 10 live keys: revoke one first. |
| 404 | `Y30` | Revoking a key this shop doesn't have. |

## Row errors

Write calls answer `200` with one result per row, in the order sent, and a `summary` with the count per status plus `total`. A bad row never stops the others. A row with status `error` carries an `error` message. Report every one to the owner.

Common row errors:

- an unknown category;
- a SKU that exists only on a marketplace, not on the SellerSideKick store;
- `stock` or `parent_sku` sent for an existing product;
- a new product missing `name`, `price`, `category` or `brand`;
- a `parent_sku` that is a variant, a marketplace-only product or doesn't exist;
- the same SKU twice in one request;
- stock: `expected_from` no longer matches on hand, or a `delta` would go below what open orders hold, or a `delta` on a SKU that was never counted.

## Limits

| Limit | Value |
|---|---|
| Rows per write request | 500 (products, stock items). Split bigger sheets. |
| Requests per shop | 120 a minute, however many keys or connections |
| Requests per caller (IP) | 600 a minute, counted before the key is checked |
| Products per page | `limit` up to 500, default 100 |
| `idempotency_key` | 8–100 characters: letters, digits, `.` `_` `:` `-` |
| Stock `reason` | 200 characters |
| Product `name` / `description` | 500 / 10,000 characters per language |
| Promotion `code` / `name` / `description` | 64 / 200 / 2,000 characters |
| Products in a bundle or BOGO | up to 50 (a bundle needs 2 or more) |
| Live API keys per shop | 10 |

## Retrying

- **429:** wait the number of seconds in the `Retry-After` header, then resend the same request.
- **Product updates** (`POST /products/upsert`): safe to resend; rows already applied come back `unchanged`.
- **Stock** (`POST /stock`): safe to resend **with the same `idempotency_key`**; applied rows come back `already_applied`. Use a new key for each new change.
- **Promotion create:** not safe. List promotions first to see whether it was created.
- **Promotion update and status:** safe to resend.
- **401 and 403:** don't retry; tell the owner what the message says.
