---
title: "Nodea API v1 — introduction: base URL, tokens, scopes, limits | Nodea"
description: "Introduction to the Nodea API v1: base URL /api/v1, Passport (Bearer) tokens, 12 scopes, customer accounts and the X-Account-Id header, a 240/min rate limit, error format, and pagination."
url: "https://nodea.io/en/api-docs/overview"
lang: "en"
updated: "2026-11-13"
---

# Nodea API v1 — introduction: base URL, tokens, scopes, limits | Nodea

> The Nodea v1 REST API gives you programmatic access to monitoring, alerting, infrastructure, and account. Learn the base URL, token authentication, scopes, rate limits, errors, and pagination.

The Nodea API (version **v1**) gives you programmatic access to everything the /app panel offers: website and heartbeat monitoring, alert integrations and escalations, servers, SSH keys, DNS zones, Vault devices, and your account (profile, tickets, billing, domains, hosting, migrations). It is a fully RESTful interface that accepts and returns JSON, and every resource is scoped to the token owner — commercial resources (tickets, billing, domains, DNS, hosting, virtual machines) to the **current customer account** (see “Customer accounts”).

This page is the **introduction** — it covers the base URL, authentication, permission scopes, rate limits, error format, and pagination. Documentation for individual modules (endpoints, fields, examples) lives in separate entries in this collection. To deploy apps from a coding agent (Claude Code, Codex, OpenCode) or from CI, start with [Deploying from AI coding agents](https://nodea.io/en/api-docs/ai-coding-agents).

## Base URL

All API v1 paths are relative to a single prefix:

https://app.nodea.io/api/v1

For example, the token-identity endpoint is GET /api/v1/me, and the list of monitored sites is GET /api/v1/websites. All responses have Content-Type: application/json. When sending data, set the Accept: application/json and Content-Type: application/json headers.

## Authentication

API v1 is protected by the Passport guard (auth:api). You authenticate with a **Personal Access Token** (PAT) — a long-lived OAuth token you generate yourself in the panel.

### How to generate a token

1. Sign in to the panel and go to [account settings](https://app.nodea.io/app/account/api-tokens) → **API tokens** (/app/account/api-tokens).
2. Click **Create token**, give it a name, and select only the **scopes** the integration actually needs.
3. Copy the full token value **immediately** — it is shown only once. Afterwards the panel displays only the token's name and its scopes.

### Authorization header

Attach the token to every request in the Authorization header as a Bearer token:

Authorization: Bearer 1|AbCdEf0123456789...

A request without a valid token — or with a revoked one — returns 401 Unauthorized as JSON if you send the Accept: application/json header; without it the panel answers with a redirect to the sign-in page. A token is valid for one year. You can revoke a token at any time in the panel; revocation takes effect immediately.

## Scopes (permission tiers)

A token does not grant full account access — it carries only the permissions you select when you create it. Scopes are organized into **4 module groups**, each at three tiers: read (listing and reading), write (create, update, and non-destructive actions — e.g. "run now", pause, test notification), and delete (**irreversible** actions — resource removal, VM stop, hosting termination).

That is **12 scopes** (4 groups × 3 tiers) plus one narrow special-purpose scope, dns:acme — 13 in total:

GroupScopesWhat it authorizes **monitoring**monitoring:read  
monitoring:write  
monitoring:deleteWebsites, heartbeats, reports, and status pages. *read* = lists and details; *write* = create/edit, "run now", pause/resume, maintenance windows; *delete* = remove a monitor together with its history. **alerting**alerting:read  
alerting:write  
alerting:deleteNotification integrations, notification groups, escalation policies, and sharing. *write* includes sending a test notification; *delete* = remove an integration/policy/share. **infra**infra:read  
infra:write  
infra:deleteServers, SSH keys, DNS zones, and Vault devices. *write* = create/edit and operational actions; *delete* = destructive actions such as stopping a VM or removing a key/zone. **dns**dns:acmeDNS-01 certificate automation only: look a zone up by name and create or delete \_acme-challenge.\* TXT records. No reading of zones or records, no other record types or names, no access to the rest of the API (except GET /api/v1/me and the MCP whoami tool, available to every token except the nodeaD plugin token, which return the owner's profile and current account) — see [DNS — DNS-01 automation](https://nodea.io/en/api-docs/dns#dns-01). **fleet** (OAuth only)fleet:enrollOne-time server connection via the "Connect to the Nodea panel" button of the nodeaD plugin (DirectAdmin / cPanel / WHM): issues the agent bootstrap for the existing server the user picked on the consent screen. Reserved for the "nodeaD server plugin" OAuth client — **it cannot be granted to a personal access token** and is not one of the 13 above; the token works only on POST /api/v1/fleet/enrollments (every other route, including GET /api/v1/me and the MCP whoami, answers 403 token\_restricted) and is revoked after its first use — see [Connecting servers with the nodeaD plugin](https://nodea.io/en/api-docs/fleet-enrollments). **account**account:read  
account:write  
account:deleteProfile, tickets, billing, service plan changes, domains, hosting, and the migrator. *delete* = irreversible actions such as hosting termination.

The rule is simple: **grant a token the least privilege it needs**. An integration that only reads monitoring status needs just monitoring:read — do not give it :write or :delete. Endpoints also inherit the same feature flags (Pennant) as the panel, so if a module is disabled for your account, no token will unlock it.

A request with a token that lacks the required scope returns 403 Forbidden.

## Customer accounts

Commercial resources — **support tickets, billing (invoices, wallets, transactions), domains, DNS zones, hosting accounts and servers backed by a virtual machine** — belong to a **customer account**, not directly to a user. An account can have several users: one **owner** (owner) and any number of **members** (member) with individually granted permissions. Every user has a personal account and may also belong to other customers' accounts (e.g. the company they work for). An account is billed by Nodea (billing\_source: nodea), by the WHMCS billing system (billing\_source: whmcs) or by Nodea outside the panel with a VAT invoice from wFirma (billing\_source: external).

Monitoring (websites, heartbeats, reports, status pages), alerting, SSH keys, Vault devices and servers **without** a virtual machine stay personal resources of the user — the account context does not affect them.

### Members and permissions

The owner always holds every permission. A member holds only the flags granted by the owner (the names match WHMCS exactly). There are 13 flags:

FlagMeaningWhat it unlocks in API v1 and MCP profileModify account profile— (panel) contactsView and manage contacts— (panel) productsView products and servicesRead hosting (accounts, mailboxes, backups) and servers backed by a virtual machine. manageproductsManage products and services (requires products)Hosting actions (mailboxes, backups, restore, SSL) and actions on a VM-backed server (update, VM start/stop/reboot, WAF, components, clone, SSH test, note). productssoPerform single sign-on for services (requires products)— (SSO is panel-only) domainsView domainsRead domains and DNS zones. managedomainsManage domain settings (requires domains)Nameservers, WHOIS privacy, EPP code request, creating/updating/deleting DNS records. invoicesView and pay invoicesBilling: invoices, wallets, transactions. quotesView and accept quotes— (panel) ticketsView and open support ticketsTickets: list, show, create, reply, close. affiliatesView and manage affiliate account— (panel) emailsView email history— (panel) ordersPlace new orders, upgrades and cancellations— (panel)

**Effective access = token scope AND account permission.** An account:write token belonging to a member who has domains but not managedomains can read domains, but changing nameservers returns 403 account\_permission\_denied with "permission": "managedomains". Conversely, an owner using an account:read-only token still cannot write (403, missing scope). Irreversible actions — hosting termination and deleting a server backed by a virtual machine — are reserved for the owner and no flag grants them (403 account\_owner\_required).

### Account context (the current account)

Every API v1 request (and every request to the MCP server) acts in **one current account**, resolved in this order:

1. **the account the token is pinned to** — a header cannot change it;
2. the X-Account-Id: \<account id\> request header;
3. the user's **default account** (default\_account\_id);
4. the only membership — when the user belongs to exactly one account.

The API echoes the resolved account in the X-Account-Id response header; when the header is missing, the request ran without an account context. A missing context is not an error by itself — endpoints that need an account then answer 403 no\_account\_context. The header is validated on **every** API v1 endpoint: a malformed or foreign X-Account-Id returns 403 account\_forbidden even on e.g. GET /websites.

Lists of commercial resources (/tickets, /domains, /hosting, /dns/zones, /billing/\*) return only the current account's resources, and responses carry an account\_id field. A resource outside the current account — even one belonging to another account of the same user — returns 404. The ids of the accounts you belong to are returned by [GET /api/v1/accounts](https://nodea.io/en/api-docs/accounts).

curl -i https://app.nodea.io/api/v1/domains \\ -H "Authorization: Bearer $NODEA\_TOKEN" \\ -H "X-Account-Id: 17" \\ -H "Accept: application/json" HTTP/2 200 Content-Type: application/json X-Account-Id: 17 ...

### Tokens pinned to an account

When you create a token in the panel (/app/account/api-tokens) you choose the account it acts in — by default the one you are currently working in. A **pinned** token acts only in that account: an X-Account-Id header naming another account returns 403 account\_mismatch, and once you lose access to the account (removed as a member, account closed) every request returns 403 account\_forbidden. The **“Any account (X-Account-Id header)”** option creates an unpinned token — the header selects the account, and without it your default account applies. The token list in the panel shows the pinned account or “Any account”.

**Tokens created before customer accounts were introduced** are unpinned: they behave like “any account”, so without a header they land in your default account (usually your personal account) and keep working as before. An integration that should act in another account should send X-Account-Id or use a new token pinned to that account.

### Account-context error codes

Account errors use the standard {message, code} shape; account\_permission\_denied adds a permission field.

HTTPCode (code)When 403account\_forbiddenThe account named by the X-Account-Id header, or the account the token is pinned to, does not exist, you are not its member, or it is closed or deleted; also a malformed header value (anything other than a positive integer). Every case gets the same answer — the API never confirms that someone else's account exists. 403account\_mismatchThe token is pinned to an account and the X-Account-Id header names a different one. 403no\_account\_contextThe endpoint needs an account and none could be resolved (e.g. you belong to several accounts, have no default account and sent no header). 403account\_permission\_deniedYour membership in the current account lacks a required permission. The response carries an extra permission field naming the missing flag. 403account\_owner\_requiredThe action is reserved for the account owner (hosting termination, deleting a server backed by a virtual machine) — no permission flag grants it. 423termination\_lockedDestructive operations (hosting termination, deleting a VM-backed server) are globally locked. The lock is checked **before** account permissions, so the owner gets it too; the resource is left untouched. 423managed\_by\_whmcsThe resource (a hosting account or a server's VM) is managed by the WHMCS billing panel — terminating or deleting it in Nodea is always refused, regardless of the global lock; the resource is left untouched. 404—The resource does not belong to the current account (also when it belongs to another account of yours) — switch accounts with the X-Account-Id header. HTTP/2 403 Content-Type: application/json { "message": "Your role in this account does not grant the 'managedomains' permission.", "code": "account\_permission\_denied", "permission": "managedomains" }

## Rate limit

API v1 is limited to **240 requests per minute** per token. The counter is keyed by token (tokenless requests fall back to a per-IP limit). Once you exceed the limit you get 429 Too Many Requests; the X-RateLimit-Limit, X-RateLimit-Remaining, and Retry-After headers tell you when to retry. Cache responses and avoid polling in tight loops.

## Error format

Errors are returned as JSON of the shape:

{ "message": "Human-readable description, ready to display.", "code": "optional\_machine\_code" }

On validation errors (422) the response also includes an errors object with per-field messages. The HTTP status codes the API uses:

CodeMeaning 400Bad Request — the request is malformed. 401Unauthorized — missing, invalid, or revoked token. 403Forbidden — the token lacks the required scope, the module is disabled, or the account context denies the request (codes account\_forbidden, account\_mismatch, no\_account\_context, account\_permission\_denied, account\_owner\_required — see “Customer accounts”). 404Not Found — the resource does not exist, does not belong to the token owner, or lies outside the current customer account. 409Conflict — the action conflicts with the resource state (e.g. a duplicate). 422Unprocessable Entity — validation error (details in errors). 423Locked — a resource-destroying operation (hosting termination, deleting a server with a VM) is currently locked globally; code termination\_locked, the resource is left untouched. The lock is checked before account permissions. A resource managed by the WHMCS panel — always code managed\_by\_whmcs. 429Too Many Requests — rate limit exceeded. 502Bad Gateway — an upstream dependency failed (e.g. an infrastructure provider). 503Service Unavailable — temporary outage (e.g. maintenance mode).

## Pagination

List endpoints are paginated. Control the page size with the per\_page parameter (default **20**, maximum **100**) and the page number with page. The response carries a data array plus pagination metadata (current page, page count, total records).

Endpoints that browse very long histories (e.g. individual monitoring runs) use **simplePaginate** — they return only "next/previous page" cursors without counting every record, which is far cheaper at millions of rows. Iterate them by following the next-page link rather than computing the page count up front.

## Example: curl

The simplest way to test a token is the GET /api/v1/me endpoint, which returns the token owner's identity, default account and current customer account (full reference in [Customer accounts — API and MCP](https://nodea.io/en/api-docs/accounts)).

Without a token — 401:

curl -i -H "Accept: application/json" https://app.nodea.io/api/v1/me HTTP/2 401 Content-Type: application/json { "message": "Unauthenticated." }

With a valid token — 200:

curl -s https://app.nodea.io/api/v1/me \\ -H "Authorization: Bearer 1|AbCdEf0123456789..." \\ -H "Accept: application/json" { "data": { "id": 42, "name": "Jane Doe", "email": "jane@example.com", "timezone": "Europe/Warsaw", "currency": "PLN", "default\_account\_id": 17, "current\_account": { "id": 17, "name": "Jane Doe", "role": "owner", "permissions": \["profile", "contacts", "products", "manageproducts", "productsso", "domains", "managedomains", "invoices", "quotes", "tickets", "affiliates", "emails", "orders"\], "billing\_source": "nodea", "is\_default": true, "is\_current": true }, "created\_at": "2025-03-01T10:00:00+00:00" } }

Once this works, move on to the documentation for a specific module — each one describes its endpoints, parameters, and request examples.

### What is the Nodea API base URL?

All API v1 endpoints are relative to the prefix https://app.nodea.io/api/v1 — e.g. GET /api/v1/me or GET /api/v1/websites. Responses are JSON.

### How do I get an API token?

Generate a Personal Access Token in the panel under API tokens (/app/account/api-tokens). Name it, select the scopes you need, and copy the value — it is shown only once.

### How do I pass the token in a request?

Attach the token in the Authorization header as a Bearer token, e.g. Authorization: Bearer 1|AbCd... A request without a valid token returns 401 Unauthorized.

### How many scopes are there and what do they cover?

There are 12 scopes: 4 groups (monitoring, alerting, infra, account) at 3 tiers each (read/write/delete). read = read access, write = create/edit and non-destructive actions, delete = irreversible actions. Grant a token only the scopes it needs.

### What is the rate limit?

240 requests per minute per token. Once exceeded you get 429 Too Many Requests; the Retry-After header tells you when to retry.

### How does pagination work?

Lists are paginated with per\_page (default 20, max 100) and page. Endpoints with very long histories use simplePaginate — iterate them by following the next-page link.

### How do I choose the customer account a token acts in?

A token pinned to an account always acts in it. An unpinned token (including every token created before customer accounts existed) acts in the account named by the X-Account-Id header, and without the header in your default account. GET /api/v1/accounts lists your accounts and their ids; the API echoes the current account in the X-Account-Id response header.

## Related

- [Nodea MCP server — endpoint, authentication, OAuth discovery, tools | Nodea](https://nodea.io/en/api-docs/mcp)
- [Customer accounts — API v1 and MCP | Nodea Documentation](https://nodea.io/en/api-docs/accounts)
- [Deploying from AI coding agents — Claude Code, Codex, OpenCode and CI | Nodea](https://nodea.io/en/api-docs/ai-coding-agents)

---

Languages: [pl](https://nodea.pl/pl/dokumentacja-api/overview.md)  
Site index: [llms.txt](https://nodea.io/en/llms.txt)
