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

# API conventions

> Transport, timestamps, caching and error shapes that hold across every Zero-Dash endpoint.

These rules apply to both API surfaces. They are short, and every one of them is checked during certification.

## Transport

<CardGroup cols={2}>
  <Card title="HTTPS with a valid certificate" icon="lock">
    Both directions. A self-signed or expired certificate on your callback host fails the integration outright.
  </Card>

  <Card title="JSON only" icon="brackets-curly">
    `Content-Type: application/json` is the only accepted content type for request bodies. Nothing else is processed.
  </Card>

  <Card title="RESTful paths" icon="route">
    Resource paths, HTTP verbs and status codes carry meaning. See [Errors and retries](/wallet/errors-and-retries).
  </Card>

  <Card title="Signed, every call" icon="key">
    No exceptions, in either direction. See [Request signature](/security/signature).
  </Card>
</CardGroup>

## Timestamps

All timestamps in request and response **bodies** use **ISO-8601 in UTC**:

```
2026-01-29T14:05:29.678Z
```

<Warning>
  `X-Zd-Timestamp` is the exception: it is **Unix time in milliseconds**, not ISO-8601. Two different formats, two different jobs — one for data, one for replay protection.
</Warning>

| Where                                            | Format            | Example                    |
| ------------------------------------------------ | ----------------- | -------------------------- |
| `X-Zd-Timestamp` header                          | Unix milliseconds | `1778920901644`            |
| `createdAt`, `updatedAt`, `startDate`, `endDate` | ISO-8601 UTC      | `2026-01-29T14:05:29.678Z` |

Always send UTC. A local-time offset in a body field is treated as a bad request.

## Currencies

Currency codes follow **ISO-4217** — `EUR`, `USD`, `BTC`, `ETH` — and crypto codes use the same convention. The virtual `FUN` currency is reserved for [free-to-play](/launch/free-to-play) sessions and never reaches your wallet.

How amounts are represented, and the exact precision per crypto asset, is covered in [Amounts and currencies](/wallet/amounts).

## Caching and performance

Every Customer API response carries:

```http theme={null}
ETag: "a1b2c3d4"
Last-Modified: Thu, 29 Jan 2026 14:05:29 GMT
Cache-Control: public, max-age=300
```

Send them back and skip the payload when nothing has changed:

```http theme={null}
GET /api/v1/games HTTP/1.1
X-Operator: your-operator-id
X-Zd-Signature: …
X-Zd-Timestamp: 1778920901644
If-None-Match: "a1b2c3d4"
```

```http theme={null}
HTTP/1.1 304 Not Modified
ETag: "a1b2c3d4"
```

<Tip>
  The game catalogue is the payload that matters here — it is large, it carries every artwork URL, and it changes rarely. Poll it on a schedule with `If-None-Match` rather than fetching it on every page render, and store the `ETag` next to your cached copy.
</Tip>

| Header you send     | Paired with     | Result when unchanged          |
| ------------------- | --------------- | ------------------------------ |
| `If-None-Match`     | `ETag`          | `304 Not Modified`, empty body |
| `If-Modified-Since` | `Last-Modified` | `304 Not Modified`, empty body |

<Note>
  Conditional requests are still signed like any other request. A `GET` with no query string signs `path\|timestamp\|` — the conditional headers are not part of the signed data.
</Note>

## Error shape

Wherever an error can carry an explanation, use this body:

```json theme={null}
{
  "message": "insufficient balance"
}
```

Concrete messages are worth real time during certification and incident response. `"error"` tells nobody anything; `"currency mismatch: campaign is USD, player is EUR"` closes the ticket.
