API Authentication
Every REST endpoint lives under /api/v1. Scripts, CI jobs and integrations authenticate with an API key; the dashboard uses a cookie session.
API Keys
An API key is the only credential meant for programs. Create one per tool, so you can revoke a single integration without touching the others:
- In the dashboard, open Settings → API Keys and click Create API Key.
- Give it a name that says what uses it, for example "CI pipeline".
- Choose its access level and, if you want, an expiration date.
- Copy the key immediately: it is shown only once and stored hashed. If you lose it, delete it and create a new one.
Keys start with sh0_. A key can never do more than the account that created it, and a key cannot create other keys.
Access Levels
Each key carries one of three access levels, enforced by the server on every request. Through the API, the level is the scopes field: read, deploy or admin.
| Level | Can | Cannot |
|---|---|---|
Read-onlyread | View apps, deployments, logs, metrics and configuration, including environment variables, database credentials, backups and files inside containers. | Cannot change anything: no deploy, restart, creation or deletion. No terminal, no host access. |
Deploymentdeploy | Everything read-only allows, plus deploy, roll back, restart, start, stop and scale existing apps, and upload a new archive for them: the key runs the code it uploads. | Cannot create or delete apps, change their settings, domains or environment variables, or manage nodes, users, keys or server settings. No terminal. |
Administrationadmin | Everything your account can do, including creating and deleting resources, the terminal and host access. | Never more than your own role. Cannot create other API keys, manage sign-in identities or the two-factor requirement. |
Using a Key
Send the key in the Authorization: Bearer header of every request:
export SH0_TOKEN="sh0_..."
curl https://panel.example.com/api/v1/apps \
-H "Authorization: Bearer $SH0_TOKEN"X-API-Key header is not read. A request that only carries it is treated as anonymous and answers 401 "No authentication token provided".Dashboard Sessions
The dashboard signs in with POST /api/v1/auth/login. On success the server sets HttpOnly cookies (sh0_access and sh0_refresh) and returns a csrf_token in the response body; no token is returned in the body. This flow is meant for browsers: for scripts, use an API key.
The access session lasts 24 hours. The dashboard renews it through POST /api/v1/auth/refresh, which also issues a new 30-day refresh session; a session left unused for 30 days ends.
Changing your password signs out every other session. Login attempts are limited to 5 failures per 15 minutes; a correct password does not count against the limit.
Two-Factor Login
When the account has two-factor authentication, the login answers requires_totp with a short-lived totp_nonce instead of opening the session. The client then sends the nonce and the 6-digit code (or a backup code) to POST /api/v1/auth/totp/verify. Verification is limited to 5 attempts per 5 minutes.
CSRF Protection
Requests authenticated by the session cookie must repeat the CSRF token in the X-CSRF-Token header on every state-changing call. Requests authenticated by an API key in the Authorization header do not need it.
Authentication Errors
Errors use the standard error envelope. For example, an unknown or revoked key:
{"error":{"code":"UNAUTHORIZED","message":"Invalid API key"}}| HTTP | Code | Meaning |
|---|---|---|
| 401 | UNAUTHORIZED | No credential, an unknown, expired or revoked key, an expired session, or wrong email or password at login |
| 403 | FORBIDDEN | Authenticated, but the key’s access level or the account’s role does not allow this action |
| 429 | RATE_LIMITED | Too many attempts: 5 failed logins per 15 minutes, or 5 two-factor checks per 5 minutes |