Appearance
API overview
Everything you can do in the dashboard, you can do with the Fjordrun API. The dashboard and the CLI use the same API.
- Base URL:
https://api.fjordrun.com/api/v1 - Format: JSON request and response bodies (
Content-Type: application/json) - OpenAPI document: docs.fjordrun.com/openapi.json. Import it into Postman, Insomnia or a client generator. The live document is at
https://api.fjordrun.com/openapi.json. - Reference: every endpoint, grouped by resource, in the sidebar. Start with Teams, Projects and Services.
Authentication
Send a token in the Authorization header:
bash
curl -H "Authorization: Bearer $FJORDRUN_TOKEN" https://api.fjordrun.com/api/v1/teamsTwo kinds of tokens work (see API tokens):
| Token | Prefix | Acts as | Use it for |
|---|---|---|---|
| Team API token | fjr_ | its creator's role, in one team (optionally one project) | CI, deploy scripts, automation |
| Personal access token | fjr_pat_ | you, in all your teams | the CLI, your own scripts |
Create team tokens in Team settings → API tokens. A request without a valid token gets 401.
A few endpoints only work from a dashboard session (for example changing your password). Called with a token, they answer 403.
Roles
Each team member has a role: viewer (read only), member (create and deploy), admin (members, tokens, billing) or owner. A request that needs more than the token's role gets 403. A project-scoped team token gets 404 for anything outside its project.
IDs and environments
Resources are identified by UUIDs. A project has one or more environments (the first is production), and a service exists in every environment of its project, with its own configuration, variables, domains and deployments.
Service endpoints take an optional environment_id query parameter. Without it, they act on the production environment.
Errors
Errors use the HTTP status code and a JSON body with a detail message:
json
{ "detail": "Your plan allows up to 2 vCPU per service" }| Status | Meaning |
|---|---|
400 | The request can't be carried out as sent (for example a template without the variables it needs) |
401 | Missing, invalid or expired token |
402 | The team has no credit left, or its plan doesn't allow this |
403 | Your role (or token) doesn't allow this |
404 | Not found, or not visible to your token |
409 | Conflicts with the current state (for example a hostname already in use, or the team is suspended) |
410 | Gone (for example an expired invite) |
422 | Validation error. FastAPI validation errors have detail as a list of {loc, msg, type} objects |
429 | Too many requests. Wait and retry |
502, 503 | A provider Fjordrun depends on (payments, GitHub) failed or is not available. Retry later |
Streaming endpoints
Live logs (/deployments/{id}/logs/stream), live metrics (/services/{id}/metrics/live) and workflow runs (/runs/{id}/stream) are Server-Sent Events. Browsers can't set headers on an EventSource, so these endpoints also accept the token as a token query parameter. Prefer the header everywhere else, because URLs end up in logs.
bash
curl -N -H "Authorization: Bearer $FJORDRUN_TOKEN" \
"https://api.fjordrun.com/api/v1/deployments/$DEPLOYMENT_ID/logs/stream?type=build"Walkthrough: deploy a container image
This walkthrough creates a project, deploys a public image, changes a variable and adds a domain. It uses curl and jq.
bash
export FJORDRUN_TOKEN=fjr_... # Team settings → API tokens
export API=https://api.fjordrun.com/api/v1
auth=(-H "Authorization: Bearer $FJORDRUN_TOKEN" -H "Content-Type: application/json")1. Find your team. A team token sees only its own team.
bash
TEAM_ID=$(curl -s "${auth[@]}" $API/teams | jq -r '.[0].id')2. Create a project. Pick a region (nbg1 Nuremberg, fsn1 Falkenstein or hel1 Helsinki). The response includes the project's environments; the first is production.
bash
PROJECT=$(curl -s "${auth[@]}" -X POST $API/teams/$TEAM_ID/projects \
-d '{"name": "hello", "region": "nbg1"}')
PROJECT_ID=$(echo "$PROJECT" | jq -r .id)
ENV_ID=$(echo "$PROJECT" | jq -r '.environments[0].id')3. Create a service. A service with a source deploys right away. config only needs the settings you change; see ServiceConfig for all of them.
bash
SERVICE=$(curl -s "${auth[@]}" -X POST $API/projects/$PROJECT_ID/services -d '{
"environment_id": "'"$ENV_ID"'",
"name": "web",
"kind": "web",
"source": {"type": "image", "image": "nginxdemos/hello:latest"},
"config": {"deploy": {"port": 80}},
"variables": {"GREETING": "hej"}
}')
SERVICE_ID=$(echo "$SERVICE" | jq -r .id)
DEPLOYMENT_ID=$(echo "$SERVICE" | jq -r .latest_deployment.id)To build from GitHub instead, use "source": {"type": "github", "repo": "owner/repo", "branch": "main"}. Someone in the team must have linked their GitHub account (in the dashboard) with access to the repository. Fjordrun then adds a push webhook, so pushes to the branch deploy automatically. See How builds work.
4. Wait for the deployment. A deployment goes through queued, building (GitHub sources), deploying and ends as success, failed, crashed or cancelled. Later, it becomes removed when a newer deployment replaces it.
bash
until s=$(curl -s "${auth[@]}" $API/deployments/$DEPLOYMENT_ID | jq -r .status); \
[[ $s =~ ^(success|failed|crashed|cancelled)$ ]]; do sleep 5; done; echo $s
curl -s "${auth[@]}" "$API/deployments/$DEPLOYMENT_ID/logs?type=deploy" | jq -r '.[].message'5. Give it a public URL. Services are private until they have a domain. An empty body creates a generated *.fjordrun.app domain with HTTPS:
bash
curl -s "${auth[@]}" -X POST $API/services/$SERVICE_ID/domains -d '{}' | jq -r .url6. Change a variable. PATCH merges: keys you send are set, null removes a key, others stay. PUT replaces all of them. A running service is redeployed with the new values.
bash
curl -s "${auth[@]}" -X PATCH $API/services/$SERVICE_ID/variables \
-d '{"variables": {"GREETING": "hallo"}}' | jq .variables7. Deploy a new version. Point the service at another image (or change any setting) and a running service is redeployed. POST /services/{id}/deploy deploys the current settings again.
bash
curl -s "${auth[@]}" -X PATCH $API/services/$SERVICE_ID/config \
-d '{"source": {"image": "nginxdemos/hello:plain-text"}}' | jq .latest_deployment.status8. Add a custom domain (Hobby plan or higher). Create the DNS records from the response at your DNS provider, then verify. The status changes from pending_dns to active, and the HTTPS certificate is issued automatically.
bash
DOMAIN=$(curl -s "${auth[@]}" -X POST $API/services/$SERVICE_ID/domains -d '{"hostname": "hello.example.com"}')
echo "$DOMAIN" | jq -r '.dns_records[] | "\(.type) \(.name) \(.value)"'
curl -s "${auth[@]}" -X POST $API/domains/$(echo "$DOMAIN" | jq -r .id)/verify | jq .status9. Clean up. Deleting the project removes its services, volumes and domains. It needs the admin role (the other steps need member).
bash
curl -s "${auth[@]}" -X DELETE $API/projects/$PROJECT_IDCI/CD
For GitHub Actions, see CI/CD with GitHub Actions. Elsewhere, the CLI (fjordrun deploy --wait) or the two calls above (PATCH /services/{id}/config with the new image, then poll the deployment) do the same.