# Generate your own client from the specification

There is currently no published client for the Szenera API. This guide shows you how to generate your own from `openapi.json` and map the conventions of the API into it: credential, errors, version check, idempotency, and paging.

> **Type:** guide
> **For:** Anyone who calls the API from a programming language and does not want to write every call by hand.
> **Prerequisite:** a generator for OpenAPI 3.1 in your language and an `ak_…` key
> **Where:** command line

## The honest status

The platform has a TypeScript client, but it is part of the portals and is not published. The developer site does not promise one. What exists is the specification: complete, with an example per schema, in the OpenAPI 3.1.0 format. Any common generator can produce a client from it.

## Steps

1. Download the specification:

   ```bash
   curl -sS -o openapi.json "https://developer.szenera.com/api/openapi.json"
   ```

   Or download it from your environment if its version differs from the release: `curl -sS -o openapi.json "$SZENERA_API/v1/openapi.json"`.

2. Generate the client with a generator of your choice. First check that it understands OpenAPI **3.1**: The specification uses types such as `["string", "null"]`, which a 3.0 generator does not know. The 19 tags of the specification work well as module boundaries.

3. Set the credential centrally: `Authorization: Bearer ak_…` on every call, taken from an environment variable and never from the source code. A key does not expire after 15 minutes, so your client needs no refresh.

4. Map errors to `code`. Every error has the form `Area.Cause`. Derive one typed error per namespace (`Auth.*`, `Permission.*`, `Validation.*`, `Conflict.*`, `RateLimit.*`, `*.NotFound`, `Integration.*`) and carry `traceId` in each of them. Never branch on `message`. The format is described under [The error format](/api/error-format).

5. Map the version check: For scenes, playlists, programs, roles, and displays, read the `version` field and send it as `If-Match` with every change. On `409 Conflict.OptimisticLock`, your client reads again and retries once. See [Concurrent changes](/api/etag-and-if-match).

6. Give every modifying call an `Idempotency-Key`: self-chosen, at least 8 characters, new for each action. A repeat with the same key returns the stored response with `Idempotent-Replay: true`, and the same key with a different body answers `422 Validation.IdempotencyKeyReused`. Details are described under [Idempotency from the start](/getting-started/idempotency).

7. Build a cursor loop for lists: send `limit` and `cursor`, collect `items`, and continue with `nextCursor` until it is missing. Handle the four routes with `page` separately, see [Paging](/api/pagination).

## Check the result

- The schema examples are your first test data: all 741 schemas of the served specification carry one, and they fit together (same identifiers, same organization).
- A first read call, `GET /v1/me`, answers `200` with the `tenantId` of your organization.
- A call with a wrong key lands in your typed `Auth` error with `code: Auth.ApiKeyUnknown`.
- Every operation your client offers carries `x-stability: stable` or `beta` in the specification (with `beta`, the shape can still move). You compare a later version of the specification with [Compare the specification against your version](/changes/compare-specification).

## If something goes wrong

| Symptom | Meaning | Solution |
|---|---|---|
| The generator aborts with a format error | It does not know OpenAPI 3.1. | Choose a generator with 3.1 support. |
| `422 Validation.Failed` with `details.issues` | The body violates the schema, and `issues` names the field path. | Compare the example of the request schema with your body. |
| `403 Permission.Denied` on a route that the client offers | The generator produces every operation, including those a key may not call. | Check the permission in the reference. Permissions that are not key-capable stay reserved for sessions, see [Authentication](/api/authentication). |
| A field the client requires is missing from the response | Your environment runs a different build than the specification you generated from. | Download the specification of the environment (`GET /v1/openapi.json`) and generate again. |

## Related

- [Read the reference](/api/read-reference)
- [The error format](/api/error-format)
- [Compare the specification against your version](/changes/compare-specification)
