--- title: API Overview description: Authenticate, route requests to nodes, and integrate Sencho into your CI/CD pipelines. --- Sencho exposes a REST API for automating stack deployments, managing webhooks, monitoring fleet health, and integrating with CI/CD pipelines. Since Sencho is self-hosted, the API base URL is your own instance. ## Base URL ``` https://your-sencho-instance:1852/api ``` Replace with your actual Sencho host and port. All API paths are prefixed with `/api`. ## Authentication Authenticated endpoints require a **Bearer token** in the `Authorization` header. Generate API tokens from **Settings > API Tokens** in the Sencho dashboard. ```bash curl -H "Authorization: Bearer YOUR_API_TOKEN" \ https://your-sencho-instance:1852/api/stacks ``` API tokens are 56-character opaque strings that begin with `sen_sk_`, for example `sen_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`. The prefix makes them easy to identify in logs and is recognized by secret-scanning tools (GitHub, TruffleHog, GitGuardian). ### Token scopes Every token is created with one of three permission levels: | Scope | Allowed actions | |-------|----------------| | **Read Only** | `GET` requests only — view stacks, containers, and fleet status | | **Deploy Only** | Everything in Read Only, plus stack operations: deploy, down, restart, stop, start, update | | **Full Admin** | Full stack, container, and node management — all read and write operations | Regardless of scope, all API tokens are blocked from managing other tokens, users, licenses, and SSO configuration. ## Node routing Sencho manages multiple nodes (local and remote). To target a specific node, include one of: - **Header:** `x-node-id: 1` - **Query parameter:** `?nodeId=1` If omitted, the request targets the default node. ```bash # Target node ID 2 curl -H "Authorization: Bearer TOKEN" \ -H "x-node-id: 2" \ https://your-sencho-instance:1852/api/stacks ``` ## Error format All error responses follow the same shape: ```json { "error": "Human-readable error message", "code": "MACHINE_READABLE_CODE" } ``` The `code` field is present for specific error types: | Code | Meaning | |------|---------| | `PAID_REQUIRED` | Endpoint requires an Admiral license | | `SCOPE_DENIED` | API token scope does not allow this operation | ## Input validation All endpoints that accept a `stackName` path parameter validate it against the pattern `^[a-zA-Z0-9_-]+$`. Stack names may only contain **alphanumeric characters, hyphens, and underscores**. Requests with invalid stack names are rejected immediately: ```json // 400 Bad Request { "error": "Invalid stack name" } ``` This applies to all stack endpoints: read, write, deploy, down, restart, stop, start, update, rollback, backup, delete, and container listing. ## Rate limiting Sencho uses a tiered rate limiting system that balances security with usability: | Tier | Limit | Applies to | Keyed by | |------|-------|------------|----------| | **Polling** | 300/min | Dashboard status endpoints (`/stats`, `/system/stats`, `/stacks/statuses`, etc.) | User session or API token | | **Standard** | 200/min | All other API endpoints | User session or API token | | **Webhooks** | 500/min | `POST /webhooks/:id/trigger` | IP address | | **Auth** | 5-10/15min | Login, setup, SSO endpoints | IP address | Authenticated requests are rate-limited per credential (per user session, or per API token). This prevents teams behind shared NAT or VPN from pooling rate limit budgets, and lets two API-token-driven automations under the same account run on independent budgets. Unauthenticated requests fall back to IP-based limiting. Internal node-to-node traffic (requests authenticated with node proxy tokens) bypasses rate limiting entirely. When exceeded, the server responds with `429 Too Many Requests`: ```json { "error": "Too many requests. Please try again shortly." } ``` Standard rate limit headers (`RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset`) are included in all API responses, so clients can self-throttle accordingly. The default limits can be tuned via environment variables (`API_RATE_LIMIT`, `API_POLLING_RATE_LIMIT`). See [Self-Hosting](/operations/self-hosting) for details. ## License tier requirements Some endpoints are gated by license tier: | Tier | Gated features | |------|---------------| | **Admiral** | Private registries (AWS ECR) | Requests to gated endpoints on Community return `403` with the `PAID_REQUIRED` error code. ## WebSocket endpoints Sencho also provides real-time streaming via WebSocket connections. These are not part of the OpenAPI spec (OpenAPI does not support WebSocket protocols) but are documented here for completeness. ### Stack log streaming Stream live logs from a stack's containers. **URL:** `wss://your-sencho-instance:1852/api/stacks/{stackName}/logs?nodeId={nodeId}` **Authentication:** Pass the token as a cookie (`sencho_token`) or Bearer token. For WebSocket connections, authentication is verified during the upgrade handshake. ```javascript Node.js import WebSocket from "ws"; const ws = new WebSocket( "wss://your-sencho-instance:1852/api/stacks/my-app/logs", { headers: { Cookie: "sencho_token=YOUR_JWT" } } ); ws.on("message", (data) => { console.log(data.toString()); }); ``` ```bash cURL (upgrade check) curl -i -N \ -H "Connection: Upgrade" \ -H "Upgrade: websocket" \ -H "Cookie: sencho_token=YOUR_JWT" \ https://your-sencho-instance:1852/api/stacks/my-app/logs ``` ### Container exec Open an interactive shell session inside a running container. **URL:** `wss://your-sencho-instance:1852/ws` **Authentication:** Cookie-based JWT only. API tokens with `read-only` or `deploy-only` scope are blocked. ```javascript Node.js import WebSocket from "ws"; const ws = new WebSocket("wss://your-sencho-instance:1852/ws", { headers: { Cookie: "sencho_token=YOUR_JWT" }, }); ws.on("open", () => { // Initiate exec session ws.send( JSON.stringify({ action: "execContainer", containerId: "abc123...", }) ); }); ws.on("message", (data) => { // Terminal output process.stdout.write(data.toString()); }); // Send terminal input ws.send(JSON.stringify({ type: "input", data: "ls -la\n" })); // Resize terminal ws.send(JSON.stringify({ type: "resize", cols: 120, rows: 40 })); ``` Container exec requires an **admin** role. API tokens with `read-only` or `deploy-only` scope are blocked, as are node proxy tokens.