Skip to content

REST API

Base URL: https://api.surfra.io. Every route takes Authorization: Bearer $SURFRA_API_KEY. Request and response bodies are JSON.

{app} is an app’s name or its sfa_ id, except on the monitoring routes, which take the id.

Method and path What it does
GET /v1/apps List apps: {"apps": [...]}
GET /v1/apps/{app} Read one app
PUT /v1/apps/{app} Update the app. A name that does not exist yet creates it
POST /v1/apps Create an app from a body with a name
POST /v1/apps/{app}/run Queue one request: {"input": {...}}. Returns the transaction

App body:

{
"image": "ghcr.io/acme/model:1",
"entrypoint": "app.py",
"runtime": {"engine": "python"},
"env": {"MODEL_ID": "Qwen/Qwen3-0.6B"},
"registry": {"docker_secret_id": "ghcr"},
"autoscale": {"max_replicas": 2, "providers": [{"provider": "salad", "gpu": "rtx3090", "priority": 1}]}
}

See Autoscale fields for autoscale.

Method and path What it does
POST /v1/transactions Queue one or more steps
GET /v1/transactions/{id} Status and each step’s output
{
"stages": [
{"name": "transcribe", "app_name": "transcribe", "depends_on": [], "input": {"url": "..."}},
{"name": "summarize", "app_name": "summarize", "depends_on": ["transcribe"]}
],
"metadata": {"source": "nightly"}
}

A transaction’s status is running, succeeded, or failed. Each step has status, progress, and output. A failed step’s output is {"error": "..."}.

Path What it does
/openai/{app}/{path} Queue a request to an HTTP app’s OpenAI-compatible server, wait, and return its response
/http/{app}/{path} The same for any path on an HTTP app’s server
/v1/apps/{app}/http/{path} Forward straight to a running replica. Needs http_ports

Gateways accept GET, POST, PUT, PATCH, and DELETE. Queued gateways take JSON bodies up to 8 MB and wait up to execution_timeout_sec.

Method and path What it does
GET /v1/workflows List workflows
GET /v1/workflows/{name} Read one
PUT /v1/workflows/{name} Save {"stages": [{"name", "app", "depends"}]}
DELETE /v1/workflows/{name} Delete
GET /v1/workflows/{name}/estimate Hourly rate of the apps in the workflow
Request What it does
POST /v1/jobs Submit a job. Body: image, entrypoint, args, providers, env, secret, docker_secret, deadline_sec, liveness_sec, grace_sec, call_apps, deny_apps, spec, name, submission_id
GET /v1/jobs?limit=50&offset=0&status= Recent jobs: {"total", "jobs": [...]}
GET /v1/jobs/{id} One job. env_keys maps each variable name to spec or submit, without values
POST /v1/jobs/{id}/stop Stop it: SIGTERM, then SIGKILL after grace_sec
GET /v1/jobs/{id}/logs?after=&before=&q=&stream=&limit=200&order=desc Log lines: {"lines": [{"t", "s", "m"}]}. order=asc reads oldest first
GET /v1/job-specs Saved job specs: {"specs": [...]}
GET /v1/job-specs/{name} One spec
PUT /v1/job-specs/{name} Save a spec with the same fields as a submit
DELETE /v1/job-specs/{name} Delete a spec
Method and path What it does
GET /v1/apps/{id}/observe Workers, replicas, and logs
GET /v1/apps/{id}/metrics?window=24h&bucket=900 Chart data. bucket is seconds
GET /v1/apps/{id}/requests?limit=20&offset=0 Recent requests
GET /v1/apps/{id}/requests/{request_id} One request with input and output
GET /v1/apps/{id}/logs Log lines, newest first: {"lines": [{"t", "s", "m", "r", "replica"}], "more"}

/logs takes these query parameters:

Parameter Meaning
after, before ISO 8601 times. Default: the last 24 hours, which is everything kept
q Words that every line must contain
request A request id
replica A replica id
stream out, err, or sys
limit Lines to return, up to 1000. Default 200
Method and path What it does
GET /v1/org The organization, its members, invites, and active invite links
POST /v1/org/invites Invite an email address
POST /v1/org/links Create an invite link: {"role": "member", "days": 7, "max_uses": null}. Returns the token once. Owners and admins
DELETE /v1/org/links/{id} Revoke an invite link
GET /v1/join/{token} The organization and role a link joins. No API key needed
POST /v1/join/{token} Join the organization as the signed-in user
Method and path What it does
GET /v1/secrets List stored credentials, without their values
POST /v1/secrets Store a credential
DELETE /v1/secrets/{id} Delete one
GET /v1/clouds List connected cloud accounts, without their keys
PUT /v1/clouds/{provider} Connect or replace a cloud account. Body: {"values": {...}}. Owners and admins
DELETE /v1/clouds/{provider} Remove a cloud account. 409 while replicas run on it
GET /v1/keys List API keys by prefix
POST /v1/keys Create an API key. The token is shown once

Errors return {"detail": "..."}.

Status Meaning
400 The body is invalid. detail names the field
401 Missing or invalid API key
404 Unknown app, workflow, or transaction
409 The name belongs to another resource, the app does not expose HTTP, or a cloud still has running replicas
413 Gateway body larger than 8 MB
504 Gateway call waited longer than execution_timeout_sec