Reference
View as MarkdownAPI reference
NebulaCtrl's dashboard, CLI and MCP server all use the same REST API under /api/v1. Everything you can click, you can call. The pages below list every operation, grouped by area. They are generated from openapi/openapi.json; a running control plane also serves the spec at /api/v1/openapi.json.
Authentication#
There are two ways to authenticate:
| Method | Use it for |
|---|---|
Authorization: Bearer nct_… |
Scripts, CI and the CLI. Create a token under Settings → API tokens. Tokens are accepted only in this header, never in a query string. |
The nebulactrl_session cookie |
The dashboard. Cross-origin writes are rejected, so a browser page on another site cannot act as you. |
A token's scopes limit what it can do, and its project list can limit where. Scopes are intersected with the creator's role when the token is created and again on every use. See API tokens.
| Scope | Allows |
|---|---|
projects:read |
Read projects, environments, services, deployments and logs |
projects:write |
Create and change projects, environments, services, variables and domains |
deployments:write |
Deploy, restart and stop services |
deployments:rollback |
Roll back a deployment |
servers:read |
Read servers and their metrics |
servers:write |
Enroll, change and revoke servers |
proxy:write |
Publish routes, expose TCP/UDP ports, certificates and tailnet egress |
admin |
Everything the creating member's role allows |
An operation marked Public needs no credentials, for example the first-run setup and sign-in calls.
Errors#
Errors are RFC 9457 application/problem+json with an extra stable code field. Match on code, not on the message.
{
"status": 409,
"code": "deployment_in_progress",
"title": "Conflict",
"detail": "another deployment of this service is active"
}| Status | Meaning |
|---|---|
401 |
No valid credentials: no session, or a missing, revoked or expired token |
403 |
Credentials are valid but lack the scope or role, or the project is not allowed |
404 |
Not found, or not visible to you. NebulaCtrl does not reveal whether a resource in another project exists |
409 |
A conflict, such as deployment_in_progress or a name already taken |
412 |
Stale If-Match: the resource changed since you read it (generation_conflict) |
422 |
Valid JSON that fails validation. errors lists the fields |
Conventions#
- Lists are paginated with
?cursor=and?limit=(default 50, maximum 200). The response carriesnextCursorwhile more items exist. - Idempotency. Mutating calls that create things accept an
Idempotency-Keyheader (up to 255 characters). A retry with the same key replays the original response for 24 hours, so a flaky network cannot create two deployments. - Optimistic concurrency. Updating a service takes
If-Matchwith the generation you read. A mismatch returns412withgeneration_conflict. - Changes are staged. Writing configuration, variables or domains stages the change and returns immediately. Nothing restarts until you call a deploy endpoint.
- Deploy and rollback return
202with the deployment. They run asynchronously and never report success before the agent has finished; poll the deployment, or usenebulactrl services deploy --wait. - Secrets are write-only. A secret variable is returned as
{key, isSecret: true, set: true}, never its value. - Live updates are Server-Sent Events:
GET /eventsfor resource changes, and the log endpoints withfollow=true.
Endpoints by area#
Pick an area below, or use the search.