# Capabilities and API tokens

The word *capability* is used for two different things in Zaroz. They are related but not the same.

## Service capabilities: what a service can do

Each service instance exposes a list of **capabilities** that its product offers and that its resources support: `log_stream`, `metrics`, `files`, `source`, `deployments`, `environment`, `external_access`, `schedules`, `backups`, `custom_domain`, and so on. The console builds its tabs from this list, and so can you:

**curl**

```bash
curl -sS "$ZAROZ_API/service-instances/$SERVICE/capabilities" -H "$AUTH"
```

**TypeScript**

```ts
const { body: caps } = await call("GET", `/service-instances/${SERVICE}/capabilities`);
console.log(caps.map((c: any) => c.capability));   // e.g. ["log_stream", "metrics", "source", "deployments"]
```

**Python**

```python
_, caps = call("GET", f"/service-instances/{SERVICE}/capabilities")
print([c["capability"] for c in caps])   # e.g. ["log_stream", "metrics", "source", "deployments"]
```


A product without `deployments` has no deployments tab and its deployments route answers 404. This is how one API serves a Minecraft server, a VPS and a Workload without special cases.

## API tokens

A token is a credential for scripts. It carries a list of **grants**, each one a permission and a scope:

```json
{"capability": "services.deploy",
 "scope": {"kind": "resource", "resource_type": "service_instance", "resource_id": "<uuid>"}}
```

| Scope `kind` | Reaches |
|---|---|
| `global` | the permission on everything the token's owner can reach |
| `resource_type` | every resource of one type, such as all service instances |
| `resource` | exactly one resource |
| `resource_tree` | one resource and the ones that descend from it |

Rules that keep tokens safe:

- A token can never do more than the person who made it can do right now: permissions are checked again on every request.
- You can only grant what you hold (`GET /me/api-token-capabilities` lists it). Staff-only permissions cannot be put on an organization token, and on a personal token they need an elevated staff session.
- An empty grant list makes a token that can do nothing. Absence denies.
- The secret is shown once and only its digest is stored. Revoke with `DELETE /me/api-tokens/{token_id}` or, for an organization, `DELETE /organizations/{id}/api-tokens/{token_id}`.
- Organization tokens default to `membership_tied` (revoked when the creator leaves) and can be `organization_owned` to outlive them.

The permissions that act on a service are named after the service:

| Permission | Allows |
|---|---|
| `services.read` | every non-secret read of a service |
| `services.manage` | change the service: environment, backups, files, firewall, and also everything `services.deploy` does |
| `services.deploy` | CI deploys: set the source and create deployments, nothing else |
| `services.power` | start, stop, restart |
| `services.console` | logs stream, command console, SSH |
| `services.files.read` | browse and download files |
| `services.external_access.manage` | open and close public ports |
| `services.schedules.manage` | schedules |
| `services.databases.read` | browse attached databases |

For the narrow case of CI, see [Deploy from CI](/guides/ci/overview). Code running **inside** a Workload should not use a token of yours at all: use a [service principal](/guides/units-api/principals).
