> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firetone.com.au/llms.txt
> Use this file to discover all available pages before exploring further.

# Conventions

> Paging, filtering, money, and the difference between absent and zero.

These hold across every endpoint. Learning them once is most of learning the
API.

## Paging

```
GET /campaigns?limit=25&offset=50&sort=name&order=asc
```

Every list returns the same envelope:

```json theme={null}
{ "items": [], "total": 0, "limit": 25, "offset": 0 }
```

`limit` defaults to 50 and is at most 500. An unknown `sort` key is a **400
naming the keys that exist**, not a silently ignored parameter.

## Filtering

Filters are an allow-list per endpoint and are documented on each. `q` is
free-text search over that endpoint's own searchable columns.

## Times

Every time is RFC 3339 in UTC (`2026-09-15T13:50:10Z`), in and out. Filters
such as `from`, `to` and `since` take the same form.

## Your own ids

Calls, campaigns, campaign contacts and contacts can carry **your** id, as
`reference` or `external_ref`. It comes back on every event, callback, result
and export, so you rarely need to store ours.

## Money is a string

```json theme={null}
{ "sell_amount": "0.062000" }
```

Never a JSON number. Rates are fractions of a cent and binary floating point
cannot represent them exactly.

## Absent is not zero

The convention worth internalising before you write any reporting.

| In a response           | Means                                       |
| ----------------------- | ------------------------------------------- |
| A value                 | That is the value                           |
| The field is **absent** | Not permitted, not applicable, or not known |
| `0`                     | Genuinely zero                              |

Cost and margin are **omitted** when the caller may not see them. An AI charge
is absent when no price matched or when the tenant's own key paid. Substituting
zero in your own code turns "unknown" into a false assertion.

## Scope is applied server-side

A supervisor's list is already narrowed to their teams; an agent's to their own
work. You do not filter for this and you cannot widen it by asking.

<Note>
  Where FireTone cannot show a record is yours, it does not return it. "Cannot
  prove it is yours" resolves to no.
</Note>
