API Overview
The dockmesh API is a plain REST + JSON interface served at /api/v1/. The same API powers the SvelteKit UI — everything you can do in the browser, you can do over HTTP.
Base URL
Section titled “Base URL”https://dockmesh.example.com/api/v1/Behind the scenes, Caddy (or your own reverse proxy) terminates TLS and proxies to the Go server. In dev, http://localhost:8080/api/v1/ works.
Authentication
Section titled “Authentication”Three authentication options:
JWT (for users)
Section titled “JWT (for users)”Exchange username+password (or OIDC callback) for a short-lived access token (15 min) and a refresh token (7 days). Send the access token as Authorization: Bearer <token> on every request.
# Logincurl -X POST https://dockmesh.example.com/api/v1/auth/login \ -H 'Content-Type: application/json' \ -d '{"username":"admin","password":"••••"}'
# Response{ "access_token": "eyJhbGci...", "refresh_token": "eyJhbGci...", "expires_in": 900}
# Use itcurl https://dockmesh.example.com/api/v1/stacks \ -H 'Authorization: Bearer eyJhbGci...'Refresh with POST /auth/refresh { "refresh_token": "..." } before expiry.
API tokens (for CI and scripts)
Section titled “API tokens (for CI and scripts)”Settings → API tokens → New token creates a long-lived token scoped to a role. Use it exactly like a JWT — Authorization: Bearer <token> — but without expiry. Revoke from the UI when no longer needed.
mTLS (for agents)
Section titled “mTLS (for agents)”Agents use their certificate on the /agent/ endpoint. Not for general API use.
Request format
Section titled “Request format”All endpoints accept and return JSON. Set Content-Type: application/json on POST/PATCH/PUT.
Pagination
Section titled “Pagination”List endpoints (/stacks, /containers, etc.) accept:
| Param | Default | Description |
|---|---|---|
page | 1 | 1-indexed page number |
per_page | 50 | 1–200 |
sort | varies | e.g. name, -created_at (minus for desc) |
filter[field] | — | e.g. filter[host]=prod-01 |
Response envelope:
{ "data": [ /* items */ ], "meta": { "total": 137, "page": 1, "per_page": 50 }}Errors
Section titled “Errors”Errors use a consistent shape and appropriate HTTP status:
{ "error": { "code": "stack.deploy_failed", "message": "pull access denied for private/image", "details": { "stack": "analytics", "host": "prod-01" } }}| Status | Meaning |
|---|---|
| 400 | Validation error (bad input) |
| 401 | No/invalid auth |
| 403 | Authenticated but forbidden by RBAC |
| 404 | Resource not found |
| 409 | Conflict (e.g. stack already exists) |
| 422 | Unprocessable (e.g. compose.yaml failed to parse) |
| 500 | Server error — report with the request_id header |
Every response carries an X-Request-Id header for log correlation.
Rate limits
Section titled “Rate limits”Defaults:
- Anonymous: 60 req/min
- Authenticated: 600 req/min
- Burst: 20
Override via DOCKMESH_RATE_LIMIT env vars. Hit the limit and you get 429 Too Many Requests with Retry-After header.
WebSockets
Section titled “WebSockets”Several endpoints stream in real time over WebSocket:
| Endpoint | Streams |
|---|---|
/api/v1/containers/{id}/logs/stream | Live container logs |
/api/v1/containers/{id}/stats/stream | Live CPU/mem/net/io |
/api/v1/containers/{id}/exec | Interactive shell |
/api/v1/hosts/{id}/events/stream | Docker daemon events |
Authenticate by setting Authorization header on the HTTP upgrade request (most clients support this).
OpenAPI spec + Swagger UI
Section titled “OpenAPI spec + Swagger UI”The machine-readable OpenAPI 3.1 spec is served at three paths — all public (no Bearer token needed) so consumers can integrate without first getting credentials:
GET /api/v1/openapi.json— JSON, 5-minute cache, ready foropenapi-typescript,oapi-codegen, Swagger Codegen,openapi-generator-cli, etc.GET /api/v1/openapi.yaml— raw YAML — whatspectral/redoclylinters preferGET /api/v1/docs— rendered Swagger UI with “Try it out” wired up against the live server. Log in separately in Swagger UI’s Authorize button (paste any Bearer token you already have).
Point any generator at openapi.json:
# Generate a TypeScript clientnpx openapi-typescript https://dockmesh.example.com/api/v1/openapi.json \ -o ./dockmesh-api.d.ts
# Or a Go clientoapi-codegen -generate client \ -o dockmesh_client.go -package dockmesh \ https://dockmesh.example.com/api/v1/openapi.jsonThe spec is hand-maintained at internal/api/openapi/openapi.yaml in the dockmesh repo. A drift test (TestOpenAPIDriftAgainstRoutes) fails CI if a route is registered without a matching spec entry (or vice versa), so the documentation and the running server never diverge — that’s the mechanical guarantee, not a process promise.
See also
Section titled “See also”- Quick Start — if you’d rather click than curl
- RBAC & Roles — how tokens inherit permissions