# How it works (/api/conventions)

## Ids [#ids]

Every id starts with what it is: `rec_` a recording, `tdo_` a to-do, `cal_` a calendar event, `wsp_` a workspace, `whe_` a webhook endpoint, `evt_` an event, `key_` a key, `req_` a request. They sort by time. Speakers are `sp_1`, `sp_2`… within a recording, in the order they first speak.

Store your own ids on a recording with `client_reference_id` (one per workspace) and `metadata` (up to 20 keys of your own), then find it again with `?client_reference_id=` or `?metadata[deal_id]=4471`.

## Lists [#lists]

Lists answer a page at a time:

```json
{ "object": "list", "data": [ … ], "has_more": true, "next_cursor": "eyJ2Ijoi…" }
```

Pass `limit` (1 to 100, 20 by default) and `cursor` (the `next_cursor` you were given). Pages hold steady while data changes underneath, so a list is never skipped or repeated.

**Syncing**: keep the newest `updated_at` you've seen and ask `GET /v1/recordings?updated_after=<it>`. Lists then run oldest change first.

## Times [#times]

Times are ISO 8601 in UTC (`2026-11-03T09:30:00.000Z`). Filters take a day (`2026-11-03`) or a full time. Lengths are in milliseconds (`duration_ms`), money in US dollars.

## Retrying safely [#retrying-safely]

Send an `Idempotency-Key` header (any unique string, a UUID say) with a `POST`, `PATCH` or `DELETE`. If the connection drops and you send it again with the same key, you get the first answer back, marked `Idempotent-Replayed: true`, and a paid call is never charged twice. Keys are kept 24 hours. The same key with a different request answers `409 idempotency_key_reused`.

## Changes from the app [#changes-from-the-app]

`PATCH` a recording with `If-Match: <its updated_at>` and, if someone changed it in Taad meanwhile, you get `412 version_conflict` instead of overwriting their change.

## Rate limits [#rate-limits]

300 requests a minute for a personal key's owner, 600 for an organization, all its keys together. Every answer says where you are:

| Header | What |
| --- | --- |
| `RateLimit-Limit` | requests allowed a minute |
| `RateLimit-Remaining` | left in this minute |
| `RateLimit-Reset` | seconds until it fills again |
| `Retry-After` | on a `429`: wait this many seconds |

## Versions [#versions]

`/v1` only grows: new fields and new calls arrive without notice, so ignore fields you don't know. Anything that would break your code would come as `/v2`, with a year of overlap and plenty of warning.

## Errors [#errors]

One shape for every error, with a message that says what to do next. See [Errors](/api/errors).
