# Errors

> Every error is the same JSON, with a status, a stable code and a message for people.

Source: https://taseli.co.il/en/developers/errors

Response 404:

```json
{
  "error": {
    "code": "not_found",
    "message": "No account with that id in this workspace."
  }
}
```

Branch on `code`. `message` is for logs and may change.

## Codes

| Status | Code | Meaning |
| --- | --- | --- |
| 400 | `invalid_parameter` | A query parameter is out of range or not one of its values. The message names it. |
| 400 | `invalid_body` | The body isn't a JSON object of at most 256 KB. |
| 400 | `invalid_url` | A webhook url isn't a public https address on the default port. |
| 400 | `refused` | Taseli couldn't do what was asked (for example, no competitor by that name). The message says why. |
| 401 | `unauthorized` | No key, or the key is expired, revoked or cut off. |
| 403 | `scope` | The key is read-only and the route writes. |
| 403 | `role` | Only an owner or admin manages webhooks. |
| 403 | `app_token` | Webhooks take a personal key, not a connected app's token. |
| 403 | `client_scope` | The key's owner is limited to one client. The API isn't open to them. |
| 403 | `workspace` | The key's workspace can't be opened anymore. |
| 404 | `not_found` | No such endpoint, or no such object in this workspace. |
| 404 | `not_enabled` | Competitor watching isn't on for this business. |
| 405 | `method_not_allowed` | The endpoint doesn't take that method. Allow lists the ones it does. |
| 409 | `limit` | The workspace already has 5 webhooks. |
| 429 | `rate_limited` | Over a limit. Wait Retry-After seconds. |
| 500 | `server_error` | Taseli failed. Safe to retry a read after a minute. |
| 503 | `unavailable` | The feature isn't available in this environment. |

A parameter outside its values is an error, never ignored. Unknown parameters are ignored, so a new parameter can't break an old call.

## Retries

| Request | Retry? |
| --- | --- |
| Any `GET` | Yes. Reads change nothing. |
| `429` | After `Retry-After` seconds. |
| `500` | After a minute. |
| `4xx` other than `429` | No. It fails the same way until the request changes. |
| `POST /webhooks` | Not blindly. There's no idempotency key: after a timeout, [list webhooks](https://taseli.co.il/en/developers/reference#list-webhooks) first, or you may make a second one. |
| `DELETE /webhooks/{id}` | Yes. A second try answers `404`, and the webhook is gone either way. |
| `POST /webhooks/{id}/test` | Yes. It sends another test. |

## Request-Id

Every response carries a `Request-Id` header. Log it. When you write to support, send it: Taseli can find any failed request by it.
