API
API overview
Authentication, errors, pagination, rate limits and long-running operations in the Ankra Cloud API, and where to find every operation.
Everything in Ankra Cloud is an HTTP JSON API under https://cloud.ankra.app/v1. The console, the CLI, the Terraform
provider and the MCP server all use it. The machine-readable contract is an OpenAPI 3.1 document with every route; the
API reference on this site is generated from it at build time.
Authentication#
Create an API token under Settings → API tokens and send it as a bearer token:
curl https://cloud.ankra.app/v1/servers \
-H "Authorization: Bearer $ANKRA_CLOUD_TOKEN"
A token acts as the user who created it, with that user's current role, limited by the token's scope (read,
read_write or a list of permissions). See Security.
The console itself uses a session cookie (ankracloud_session) instead; with a session, unsafe requests (POST, PUT,
PATCH, DELETE) must also send X-CSRF-Token equal to the ankracloud_csrf cookie. API tokens need no CSRF header.
Some routes are session-only and refuse API tokens with 403, whatever their scope: signing in (/v1/auth/*),
managing API tokens and members, support consents and unlinking sign-in identities. The reference marks every
operation with the credentials it accepts and the permission its caller needs.
Requests and responses#
- JSON everywhere, with
snake_casefield names. - Timestamps are RFC 3339 strings in UTC.
- Money is in euro minor units:
*_cents(1/100 €) and*_millicents(1/100 000 €). - Sizes use binary units in the field name:
memory_mebibytes,size_gibibytes. - Every response carries an
X-Request-Idheader; audit entries caused by the request carry the same id, so quote it when you contact support.
Errors#
Errors are RFC 7807 problem documents with the content type application/problem+json:
{
"type": "about:blank",
"title": "Conflict",
"status": 409,
"detail": "the server must be stopped to change its plan"
}
detail is written for people and is safe to show to your users.
| Status | Meaning |
|---|---|
| 400 | The request is invalid; detail says why. |
| 401 | Not signed in, or the token is invalid, revoked or expired. |
| 403 | The role or token scope lacks the permission, the CSRF header is missing, or the route is session-only. |
| 404 | No such resource in your account. Another account's resources are always 404. |
| 409 | The resource's state does not allow this now (for example the server is not stopped, or another operation runs). |
| 422 | The account would exceed a quota; detail names the limit. Refused coupon redemptions also answer 422. |
| 429 | Rate limited; wait for Retry-After seconds. |
| 503 | No capacity or free address in the zone right now, or a host did not answer; try again later. |
Pagination#
List endpoints return one page:
{ "items": [ … ], "next_cursor": "eyJpZCI6…" }
Pass next_cursor back as ?cursor= to get the next page; it is null on the last page. Cursors are opaque and
keyset-based, so pages stay consistent while items are added. Where an endpoint takes ?limit=, the server applies
its own default and maximum.
cursor=""
while :; do
page=$(curl -s "https://cloud.ankra.app/v1/servers?cursor=$cursor" -H "Authorization: Bearer $ANKRA_CLOUD_TOKEN")
echo "$page" | jq -r '.items[].hostname'
cursor=$(echo "$page" | jq -r '.next_cursor // empty')
[ -z "$cursor" ] && break
done
Operations#
Anything that changes infrastructure (creating, starting, stopping or deleting servers, storages, routers, edges,
load balancers, databases) runs as an operation. The API answers 202 Accepted at once with the resource and the
operation that carries out the change:
{
"server": { "id": "…", "state": "creating", … },
"operation": { "id": "…", "kind": "server.create", "status": "pending", "step": "ensure_template_image", "step_index": 0, "step_count": 5 }
}
Follow it with GET /v1/operations/{id} until status is succeeded, failed (with error) or cancelled.
step, step_index and step_count show progress. While a resource has an operation running, it also shows it as
active_operation, and conflicting changes answer 409.
Operations are durable: a step that fails temporarily is retried with backoff until the operation's deadline, and an
operation survives control plane restarts. Clients should poll every few seconds; the CLI's --wait, Terraform and
the MCP tool wait_for_operation do this for you.
Quick changes that need no operation answer 200 or 201 directly: renaming, labels, firewall reads, SSH keys, init
scripts and load balancer configuration, for example.
Rate limits#
Sign-in, sign-up and invitation routes are rate limited per client network and per email address. Rate-limited
requests answer 429 with Retry-After. The server console accepts at most 50 inputs per second per server.
OpenAPI and clients#
- The OpenAPI 3.1 document is
docs/openapi.yamlin the Ankra Cloud repository. Each operation has a stable snake_caseoperationId(list_servers,create_edge) that names the CLI'sankra-cloud api <operation_id>, the MCP tools and the generated Go client's methods, so renaming one is a breaking change. - Its
x-ankra-permissionextension names the permission an operation needs;x-ankra-credential-readmarks reads that reveal a credential or a live view into a server. - A typed Go client is generated from it (
api/pkg/client/openapi), and a curated client (api/pkg/client) backs the CLI and Terraform provider.
Continue with the API reference.