API reference
Everything the dashboard does goes through the DevLyft public API. You can call it too, with an API key, from scripts and CI.
Base URL#
https://api.devlyft.io/v1
Routes are resource-first, such as /v1/projects/{project_id}/builds, with no per-service prefix. Request and response bodies are JSON.
Authentication#
Send an API key as a bearer token on every request.
curl https://api.devlyft.io/v1/organizations \
-H "Authorization: Bearer $DEVLYFT_TOKEN"
Create an API key#
Open API Keys
Settings→API Keys.
Choose the scope
Personal keys act as you. Organisation keys (the tab with your organisation's name) belong to the organisation. Creating or viewing organisation keys needs the Admin or Manager role.
Name it and copy the token
Give it a name such as
CI/CD pipeline. Copy your new token now — it won't be shown again. Store it in your CI's secret store.
The key list shows when each key was last used and when it expires, if it has an expiry. Choose Revoke to disable a key. Revoked keys are marked Revoked.
Errors#
Errors use RFC 7807 problem details (application/problem+json).
{
"title": "Forbidden",
"status": 403,
"detail": "…",
"code": "…"
}
Show detail to people, and branch on status and code. A 204 response has no body.
Endpoints#
These are the endpoints the dashboard uses today.
| Area | Method and path |
|---|---|
| Users and keys | GET /users · PUT /users/{user_id} · GET /users/{user_id}/memberships · GET|POST /users/{user_id}/tokens · DELETE /tokens/{token_id} · GET|POST /organizations/{org_id}/tokens |
| Organisations and members | GET|POST /organizations · PUT|DELETE /organizations/{org_id} · GET|POST /organizations/{org_id}/memberships · PUT|DELETE /organizations/{org_id}/memberships/{user_id} |
| Projects | GET|POST /organizations/{org_id}/projects · PUT|DELETE /projects/{project_id} |
| Environments | GET|POST /projects/{project_id}/environments · PUT|DELETE /environments/{environment_id} |
| Secrets | GET /projects/{project_id}/environments/{environment_id}/secrets (keys only) · POST|DELETE …/secrets/{name} |
| Builds | GET|POST /projects/{project_id}/builds · PUT|DELETE /builds/{build_id} |
| Deploys | GET|POST /projects/{project_id}/environments/{environment_id}/deploys · PUT|DELETE /deploys/{deploy_id} |
| Domains | GET|POST /organizations/{org_id}/domains · POST /organizations/{org_id}/domains/{domain}/verify · DELETE /organizations/{org_id}/domains/{domain} |
| Routes | GET|POST /deploys/{deploy_id}/routes · DELETE /deploys/{deploy_id}/routes/{route_id} |
| Catalog | GET /locations · GET /instance-types |
| Billing | GET /organizations/{org_id}/billing · POST /organizations/{org_id}/billing/setup · POST …/billing/setup/confirm |
| Nodes and pods | GET /nodes · GET /projects/{project_id}/nodes · GET /projects/{project_id}/pods |
| Logs | GET /deploys/{deploy_id}/logs · WebSocket /deploys/{deploy_id}/logs/stream |
| Metrics | GET /metric-types · GET /metric-types/nodes · GET /deploys/{deploy_id}/metrics · GET /pods/{pod}/metrics · GET /nodes/{node_id}/metrics · GET /organizations/{org_id}/metrics |
Paths are relative to /v1.
Examples#
curl -X POST https://api.devlyft.io/v1/projects/$PROJECT_ID/builds \
-H "Authorization: Bearer $DEVLYFT_TOKEN" -H "Content-Type: application/json" \
-d '{"name":"api","image":"ghcr.io/acme/api","tag":"1.4.2","container_port":8080,"cpu_request":"0.5","memory_request":"512Mi"}'
curl -X PUT https://api.devlyft.io/v1/deploys/$DEPLOY_ID \
-H "Authorization: Bearer $DEVLYFT_TOKEN" -H "Content-Type: application/json" \
-d '{"build_id":"'$BUILD_ID'","name":"api","location_id":"'$LOCATION'","replicas":2,"tenancy_type":"INHERIT","expose":true,"env":[{"kind":"env","key":"LOG_LEVEL","value":"info"},{"kind":"secret","key":"DATABASE_URL"}]}'
PUT replaces the deploy's configuration, so send every field you want to keep, including env and the autoscaling fields (enable_hpa, hpa_min_replicas, hpa_max_replicas, hpa_target_cpu) if they're set. Environment entries use kind: "env" with a value, or kind: "secret" with just the key.
Authenticating the logs stream#
Browsers can't set headers on a WebSocket handshake, so the logs stream takes the token as the subprotocol pair ["bearer", "<token>"].
new WebSocket(`wss://api.devlyft.io/v1/deploys/${deployId}/logs/stream`, ['bearer', token]);