# Conventions

Base URL, rate limits, pagination, and timestamp formats shared across all endpoints.

These rules apply across the entire API. Resolve them once and reuse them on every endpoint.

## Base URL & transport

All requests go to your Talent-Ray instance over HTTPS. Request and response bodies are JSON (`Content-Type: application/json`).

- **Shared platform:** `https://app.talent-ray.com`
- **Dedicated deployment:** your own subdomain, e.g. `https://acme.talent-ray.com`

Paths and contracts are identical across instances — only the host changes. The examples in these docs use `app`.

## Rate limits

Each key is limited to **600 requests per minute** by default. Exceeding the limit returns `429 Too Many Requests`.

```
HTTP/1.1 429 Too Many Requests
Retry-After: 30
```

<Notice type="warning" title="Honor Retry-After">
On a `429`, wait the number of seconds in the `Retry-After` header before retrying, and back off on repeated limits.
</Notice>

## Pagination

There are two pagination styles, depending on the endpoint family.

**Offset pagination (`/api/v1` lists).** Pass `page` (0-indexed) and `pageSize` (max 100, default 20). The response wraps results in a `{ data, pagination }` envelope:

```json
{
  "data": [ "...rows..." ],
  "pagination": { "page": 0, "pageSize": 20, "totalCount": 134, "totalPages": 7 }
}
```

Request `page=1`, `page=2`, … up to `totalPages - 1`. Some small, naturally-ordered `/api/v1` sub-lists (a role's steps, a candidate's steps) are returned in full as `{ data: [...] }` with no `pagination` object.

**Cursor pagination (API-key usage log).** Ordered newest-first. Pass `limit` for page size and `before` (an ISO 8601 timestamp) to fetch older rows:

```json
{
  "pagination": { "limit": 50, "hasMore": true, "nextBefore": "2026-06-04T15:20:00Z" }
}
```

To get the next page, pass `nextBefore` as the `before` parameter. When `hasMore` is `false`, you have reached the end.

## Timestamps

All timestamps are **ISO 8601 in UTC** (e.g. `2026-06-04T15:30:45Z`).

## Scopes

The versioned `/api/v1/*` endpoints are gated by **per-key scopes** in addition to the key owner's role. Each endpoint documents the scope it needs (e.g. `candidates:read`); a missing scope returns `403 insufficient_scope`. See [Authentication → Scopes](/docs/api/authentication/#scopes).

## Versioning

The stable surface lives under **`/api/v1/*`** and changes **additively only** — new fields and endpoints may be added, but existing ones keep their contract. Breaking changes would ship under a new version namespace (`/api/v2`). The legacy unversioned routes are not a stable contract. The [OpenAPI spec](/docs/api/openapi.json) carries the current API version in its `info.version` field.