<!-- https://api.ibusisrael.online/docs/limits/ -->
# Limits and errors

## Limits

| Who | Per minute (burst) | Per day, UTC | Per month, UTC | At once | Heavy: per minute / day |
|---|---|---|---|---|---|
| Project, «trial» | 30 (10) | 1,000 | 20,000 | 2 | — |
| Project, «standard» | 120 (30) | 20,000 | 400,000 | 4 | — |
| Project, individual (example) | 120 (30) | 20,000 | 400,000 | 4 | 6 / 300 |
| Without a key: older addresses only, per address (transition) | 60 (30) | 20,000 | 400,000 | 6 | 20 / 600 |

- Limits belong to the **project**: all its keys share one budget. A new or rotated key does not add a budget, and neither do other addresses of the same data (`app.ibusisrael.online`, older paths).
- Per minute with a short burst, per day and per month (reset at 00:00 UTC), requests at the same time, and a separate budget for heavy operations (only for projects that have them).
- A request counts when it is admitted to the data. Refusals of the access check (`401`, `403`, `429`) do not count; our failures (`502`, `503`, `504`) are given back.
- Keyed answers carry `X-RateLimit-Limit` and `X-RateLimit-Remaining` for the current minute. The [developer cabinet](https://app.ibusisrael.online/developers) shows the day and the month.
- Without a key only the older addresses without `/transport` answer (transition); their limits apply per address: one IPv4 address or one IPv6 /64.
- Over a limit: `429` with `Retry-After` and a code that names the limit ([access errors](/docs/access/#codes)). `503` with `CAPACITY_RESERVED` means the service keeps capacity for passengers: retry later.

## Error format

Every answer that is not 2xx has the same JSON body:

```json
{"code": "RATE_LIMITED", "detail": "", "source_state": null}
```

`code` is for your program, `detail` is a short technical hint (often empty), `source_state` is `unavailable` when a data source failed.

## Error codes

| code | HTTP | What it means and what to do |
|---|---|---|
| `BAD_REQUEST` | 400 | A parameter has a wrong form (checked by the gateway). Fix the request; repeating it does not help. |
| `UPSTREAM_422` | 422 | A query parameter is missing or out of range (e.g. `limit=0`). Fix the request. |
| `NOT_FOUND` | 404 | The address is not a published path, or a code has a wrong form. |
| `UPSTREAM_404` | 404 | The object is not in the source (e.g. `Stop not found`, an alert that already ended). |
| `METHOD_NOT_ALLOWED` | 405 | Only GET and HEAD are accepted. |
| `RATE_LIMITED` | 429 | Too many requests per minute: of your project (with a key) or of your network (without a key). Wait `Retry-After` seconds. |
| `UPSTREAM_UNAVAILABLE` | 502 / 503 | An internal service or the data source is not reachable. Retry later with a growing pause. |
| `UPSTREAM_TIMEOUT` | 504 | The data source answered too slowly. Retry later. |
| `GATEWAY_BUSY` | 503 | The gateway is at its concurrency limit. Retry after a short pause. |
| `UPSTREAM_BAD_ANSWER` | 502 | The internal service answered something that is not valid JSON. Retry later; report it if it repeats. |

Refusals of the access check (key, IP address, project, limits) have their own codes: [access errors](/docs/access/#codes).

## Retrying

- Retry only network errors, `429`, `502`, `503` and `504`. Never retry other `4xx`: the request itself is wrong.
- Wait `Retry-After` when it is present, otherwise pause 1, 2, 4… seconds with some randomness, and stop after a few attempts.
- An unknown stop code is not an error for arrivals: the answer is `200` with `source: "unknown_stop"` and an empty list.

## Timeouts

The gateway waits up to 12 seconds for arrivals and up to 20 seconds for a day timetable before it answers `504`. Set your client timeout a little longer, for example 15–25 seconds.
