API reference
The panel's HTTP API - base URL, authentication, request style, errors and rate limits. Every action in the panel is available here.
The API is the same set of actions the web app, the command line, the MCP server and the AI assistant use, generated from one definition per action. Anything you can click, you can call. Each action has its own page in the sidebar, grouped by area, with its request and response schema and the permission it needs.
Base URL
Your panel's own address plus /api/v1/ and the action's id:
https://panel.example.com/api/v1/<action id>Before the panel has a domain, that is http://<server-ip>:3000/api/v1/.... There is no hosted API: every panel serves its own.
Authentication
Create an API key in Settings → API keys and MCP (see API keys) and send it as a bearer token:
curl https://panel.example.com/api/v1/projects.list \
-H "Authorization: Bearer $SEYLO_TOKEN"A key acts as the person who made it, narrowed to the actions and projects picked for it, and read-only keys can only call queries. A call outside its scope gets 403 FORBIDDEN.
The web app uses a session cookie (seylo_session) instead. A request with a bearer token ignores the cookie. Requests that change something with only a cookie must come from the panel's own origin.
MCP tokens (seylo_mcp_...) work here too, but only for the actions that are available to AI tools, and actions that delete something return 403 APPROVAL_REQUIRED until a person approves them (see MCP and AI).
Request style
Each action is one path named after its id: projects.list, deployments.deploy, domains.add.
- Queries (they only read) are
GETwith the input as query parameters. - Everything else is
POSTwith the input as a JSON body.
curl -X POST https://panel.example.com/api/v1/deployments.deploy \
-H "Authorization: Bearer $SEYLO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"serviceId": "k3x9q2m7v8w1z0ab"}'Fields an action does not know are dropped. A successful call answers 200 with the action's output as JSON. Ids are 16 characters of lowercase letters and digits; times are ISO 8601 strings. A request body may be up to 4 MiB; a larger one gets 400 BAD_REQUEST. Source archives go through their own upload endpoint, not through an action.
Long-running actions return right away. A deploy, for example, returns the new deployment; follow it with deployments.get and deployments.log.
Errors
Every error has the matching HTTP status and the same JSON body:
{
"error": {
"code": "BAD_REQUEST",
"message": "Invalid serviceId: Expected string to match '^[a-z0-9]{16}$'.",
"details": { "field": "serviceId" }
}
}message is safe to show to people. details is optional and holds strings, such as the field that failed validation or a reason. Branch on code, not on the status:
| Code | Status | Meaning |
|---|---|---|
BAD_REQUEST | 400 | The input failed validation (details.field names the field), or the request makes no sense in this state |
UNAUTHENTICATED | 401 | No credentials, or the key or session is not valid any more |
FORBIDDEN | 403 | The caller may not run this action on this resource. details.reason reauth: a browser session needs a sign-in from the last 15 minutes for this action; confirm with auth.reauth, then repeat the call |
APPROVAL_REQUIRED | 403 | An AI tool called an action that needs a person's approval first |
NOT_FOUND | 404 | No such resource, or the caller can't see it |
CONFLICT | 409 | Conflicts with the current state, for example the protected panel service (details.reason says why) |
RATE_LIMITED | 429 | Too many requests; wait for the seconds in the Retry-After header |
INTERNAL | 500 | Something broke on the panel; the panel's log has the details |
NOT_IMPLEMENTED | 501 | The action, or the node it needs, cannot do this yet (for example an agent too old for a feature) |
UNAVAILABLE | 503 | A node or an outside service needed for this is unreachable (details.reason is offline when the node is) |
Rate limits
Each caller gets a bucket of 120 requests that refills at 20 per second. Sign-in and token checks have a stricter bucket: 10 tries, then one every 6 seconds. Over the limit, the answer is 429 RATE_LIMITED with Retry-After.
Same actions, other doors
- Command line:
seylo login,deploy,logs,envandtunnelcover the everyday tasks. See Command line. - MCP: the actions available to AI tools are MCP tools, read-only by default. See MCP and AI.
- The OpenAPI document behind this reference is
openapi.jsonin the app repository, generated from the same definitions.
CLI reference
Every seylo command and flag, generated from the binary's own help output.
Export the audit log GET
Returns matching entries (newest first, at most 10,000) as a CSV or JSON Lines file for download. truncated is true when more matched. Needs `audit.view`, which owners and admins hold. Not available to MCP clients or the assistant.