# Units that your code controls
:::note
Everything on this page is available in the API: create, start, stop and destroy by key, allocate, rollouts, events, webhooks and service accounts. The step-by-step requests are in the [Units API guide](/guides/units-api/overview).
:::

Fixed and autoscaled policies let Zaroz decide how many units run. Some programs know better than a CPU percentage: a game hub that needs a fresh server the moment two players match, or a platform that runs one unit per customer. For these, a Workload can be put in **code mode**, where your program decides which units exist.

## The idea

In code mode there is no count. Instead each unit is something your program creates, by name:

- **Key.** Every unit has a name you choose (1 to 40 characters, lower case letters, digits and hyphens). It is the unit's private name, so the unit `duel-77` of the Workload `duels` is reachable at `duel-77.duels`. A key never changes.
- **Labels.** Up to 16 small tags you can change at any time, to find units later ("region=eu", "mode=ranked").
- **User data.** One JSON document up to 64 KiB handed to the unit when it starts (the match settings, the customer id). It is not a secret store; keep secrets in the environment.

## Creating, stopping, destroying

| call | what it does |
|---|---|
| `POST .../units` | create a unit by key and start it. Calling it again with the same key returns the same unit, so it is safe to retry |
| `POST .../units/{key}/stop` | drain, then stop. Key, labels and user data are kept, and a stopped unit costs nothing |
| `POST .../units/{key}/start` | start a stopped unit again, optionally with new user data |
| `DELETE .../units/{key}` | drain, then destroy. Final; the key can be reused |
| `PATCH .../units/{key}` | replace labels |

Code mode is a policy choice: in `fixed` and `autoscaled` modes the platform owns which units exist, and creating or stopping one by hand is refused.

## Warm units and allocate

A cold start takes time. A **warm buffer** keeps a number of ready, unassigned units waiting (`warm_units`). `POST .../units/allocate` takes one, atomically, hands it your labels and user data, and the buffer refills. Two callers never receive the same unit. Pass an `Idempotency-Key` header and a retry returns the same unit. If none is ready the call answers `409 no-warm-unit`, or, with `if_none: create`, cold-starts one for you. Warm units are billed as ordinary extra units.

## Signals and rollouts

A unit can tell the platform when it is `accepting` players, `idle` or `busy`, and when it is shutting down. With these, autoscaling can keep N servers accepting (`keep_accepting`) and remove only idle ones when scaling down. A unit with players in it is not removed. Code mode adds `replace_idle` and `next_start` rollouts, which replace units only when they are idle or the next time they start, instead of interrupting a match.

## Events and webhooks

Every transition is an event: `unit.created`, `unit.ready`, `unit.allocated`, `unit.idle`, `unit.stopped`, `unit.exited`, `unit.failed`, `unit.destroyed`, `units.scaled` and others, each with a gapless per-Workload sequence number, kept 30 days.

- **Events route.** `GET .../units/events?after=<seq>&wait=<0..30>` reads events after a cursor and long-polls up to 30 seconds. `next_after` is the cursor to send next. See the API reference.
- **Webhooks.** Up to 5 per Workload, signed with `Zaroz-Signature: v1=<HMAC-SHA256 of timestamp.body>`, delivered in order, at least once, with retries. A webhook that fails for 72 hours is disabled and the owners are told.

## Service accounts: letting your code call Zaroz

A program inside your Workload needs permission to call the unit routes. Rather than putting a person's key in an environment variable, you create a **service account** for the Workload ("Let code in this service use the Zaroz API" in the Workload's settings). The platform mounts a short-lived token into every unit at `/zaroz/credentials/token` and refreshes it for you. You give it **grants** per target Workload in the same project: no access, read, or start and stop. Programs outside Zaroz use a named credential that you create, see once and can revoke.

The service-account routes (`principal`, `principal/grants`, `principal/credentials`) are people-only: a program may control units, but it cannot change its own grants.

## What to remember

- Code mode is for programs that create units. If you only want "more copies when busy", use an autoscaled policy.
- Every unit you create that has a pod counts against the same [limits](/units/limits) and the spend cap.
- Calls from a service account are rate limited (50 per second per account).
