# ZRAZU API — developer overview

> Base address, key sign-in, idempotency, error format and limits of the ZRAZU API — for your own scripts, integrations and AI agents.

URL: https://zrazu.com/en/docs/api-overview/

The ZRAZU API gives scripts and programs what you do in the cabinet: read the list of domains, DNS zones and certificates, put a domain under monitoring. It works with a key that you issue yourself.

Separately there is [MCP for AI agents](https://zrazu.com/en/docs/api-mcp.md): it is open, needs no key, and only reads and shows the passport of a public domain.

## What the API does with a key

Base address: `https://api.zrazu.com/v1`.

| Group | What you can do |
| --- | --- |
| Key | `GET /v1/api-keys/current` — which rights, domains and term this key has |
| Domains | `GET /v1/domains` — the organization's domains with term, auto-renewal and locks |
| Monitoring | `GET /v1/monitoring`, `POST /v1/monitoring`, `DELETE /v1/monitoring/{name}` — read, add and remove names |
| DNS | `GET /v1/dns/zones`, `GET /v1/dns/zones/{name}`; editing records and new zones — see [domains and DNS through the API](https://zrazu.com/en/docs/api-domains-dns.md) |
| SSL | `GET /v1/ssl/catalog`, `GET /v1/ssl/certificates`, certificate files, ordering and reissue |
| Balance | `GET /v1/balance` — the organization's balance |

What your key can do depends on its rights: see [API keys](https://zrazu.com/en/docs/api-keys.md).

The API cannot register or renew domains, change contacts or locks, or get a transfer code. This is deliberate: those actions stay in the cabinet.

## Signing in with a key

Send the key only in a header:

```sh
curl -H "Authorization: Bearer zr_live_..." https://api.zrazu.com/v1/api-keys/current
```

A key in the request address (`?key=…`) is refused: addresses end up in server and browser logs. The key starts with `zr_live_`. A key placed in the code of a web page will not work: the API does not accept requests from other sites' pages in the browser, and this is intentional.

## Safe retries of changes

Every request that changes something (`POST`, `PUT`, `DELETE`) needs an `Idempotency-Key` header — any string up to 120 characters, for example a UUID.

```sh
curl -X POST https://api.zrazu.com/v1/monitoring \
  -H "Authorization: Bearer zr_live_..." \
  -H "Idempotency-Key: 6f1d8c0e-5b2a-4c1f-9a3e-0d7b2e4a1c11" \
  -H "Content-Type: application/json" \
  -d '{"names": ["example.com.ua"]}'
```

- A repeated request with the same key within 24 hours returns the first response with the header `Idempotent-Replayed: true` — the change is not made twice.
- The same `Idempotency-Key` with a different request body gives error `422`.
- If the first request is still running, the repeat gets `409` — retry in a moment.

If the key was issued with “Changes only with my confirmation”, the change is not made at once: the API answers `202` and a `plan_id`, and a person confirms the plan in the cabinet under “Plans”.

## Response and error format

Lists come in pages: `{"data": [...], "next": "…"}`. To get the next page, pass `next` as the `after` parameter; `limit` is up to 500, 100 by default.

An error always has the same shape:

```json
{ "error": { "code": "right_missing", "message": { "uk": "…", "en": "…" } } }
```

`code` is stable — rely on it in your code; the `message` text may change.

| Code | HTTP | Meaning |
| --- | --- | --- |
| `key_required` | 401 | no `Authorization: Bearer zr_…` header |
| `key_invalid` | 401 | not a ZRAZU key, or a mistake in it |
| `key_unknown` | 401 | key not found |
| `key_revoked`, `key_expired`, `key_idle` | 401 | key revoked, term over, or not called for 90 days |
| `key_in_query` | 400 | key passed in the request address |
| `ip_not_allowed` | 403 | the key does not work from this IP address |
| `right_missing` | 403 | the key lacks the needed right |
| `out_of_scope` | 403 | the name is outside the key's domains |
| `not_found` | 404 | zone or certificate not found |
| `idempotency_key_required` | 400 | no `Idempotency-Key` header |
| `idempotency_key_reused` | 422 | `Idempotency-Key` already used with another request |
| `rate_limited` | 429 | too many calls; the `Retry-After` header says how many seconds to wait |

## Limits

| What | Limit |
| --- | --- |
| One key | 120 calls per minute and 25 times that per hour |
| One IP address | 240 calls per minute |
| Changing calls of an organization | 1000 per day — all keys together |

For some organizations the per-minute limit may differ. A `429` response carries `Retry-After`: wait that many seconds and repeat the request with the same `Idempotency-Key`.

## If it didn't work

- **`401 key_required`.** Add the header `Authorization: Bearer zr_live_…` — the word `Bearer` and a space before the key.
- **`401 key_unknown` or `key_invalid`.** Check that the key was copied in full, without a trailing space. If you lost the key, issue a new one: the old one cannot be shown again.
- **`403 right_missing`.** The key lacks the right. Open `GET /v1/api-keys/current`, look at `permissions`, and if needed issue a new key with the right.
- **`403 ip_not_allowed`.** The key has a list of IP addresses and the request came from another. Add the address in the cabinet or issue a new key.
- **`429 rate_limited`.** Slow down and respect `Retry-After`.
- **`400 idempotency_key_required`.** Add the `Idempotency-Key` header to a request that changes data.

Prices for services are on the [prices page](https://zrazu.com/prices/).
