PricingDocsAccount

HTTP API

[object Object]

danio's own interface, the command line, the Blender add-on, plugins, and the devices that join a workspace all call the same HTTP API. Your own scripts can use it too.

Every endpoint is under /api/v1/ and speaks JSON. The parameters, responses and required permission of each endpoint are in the OpenAPI description; this page covers the conventions and the most-used endpoints.

Addresses

AddressWho uses itToken
http://127.0.0.1:7421Programs on this computer. When the port is taken, danio moves up; the real address is shown under Settings → APIThe local token
The host's workspace address, port 7420 by defaultDevices and scripts on other computers. The host must have opened this port to other devices firstA workspace token

For setting the port, see Configuration.

Tokens and permissions

Send the token with the request:

Authorization: Bearer <token>
TokenWhat it can doWhere it comes from
Local tokenEverything this computer's engine can do, including the endpoints that exist only locallyShown under Settings → Local token; can be fixed with DANIO_TOKEN
Integration tokenOnly the access level you choseThe Plugins and integrations page in the workspace details, or danio workspace token add <name> --access <level> --integration
Device tokenUsed by a device to join the workspace and render; also carries an access levelMade when you add a device, see Tokens

An integration token is shown only once, when it is made. Use Rotate to replace it; the old one stops working at once.

There are 9 workspace permissions, and an access level is a combination of them:

PermissionWhat it allows
workspace.viewView projects, tasks, progress, previews, devices and usage
output.downloadDownload films and the fragments of shots
job.submitSubmit tasks; update, pause, resume, cancel, re-render and delete the tasks you submitted
job.manageControl everyone's tasks, reorder the queue and change shot assignments
project.editCreate, change and delete projects
device.manageAdd devices, approve join requests, change devices' access and settings, block
storage.manageStores, resource packs, cleanup
plugin.managePlugins and integration tokens
workspace.manageWorkspace settings, backups, takeover

The level None has no permissions, Viewer has the first two, Workstation adds job.submit and project.edit, and Admin has all of them.

In the OpenAPI description, each endpoint's x-required-permission names the one it needs. Besides the 9 above, there are four other values:

ValueMeaning
publicNo token needed; used when a device joins
tokenAny request with a valid token
deviceOnly a device token
localOnly the local token

When the permission is not enough, the answer is 403 with the error code forbidden, naming what is missing. GET /api/v1/me returns the identity and permissions of the current token.

Errors

On an error the answer is application/problem+json:

{
  "type": "urn:danio:error:version-conflict",
  "title": "Conflict",
  "status": 409,
  "detail": "…"
}

type is a stable error code for programs to act on; detail is for people, in the language of the request's Accept-Language: Chinese when the header is missing or starts with zh, English otherwise. Fields that failed validation are listed in errors; when a submission's checks fail, the reasons are listed in checks.

Error codeStatusWhen
invalid-request400The request itself is wrong
unauthorized401No token, or an invalid one
forbidden403Not enough permission, or this origin isn't allowed
not-found404Not found
conflict409Conflicts with the current state
version-conflict409Someone updated the task first
precondition-failed412If-Match didn't match
validation-failed422A field failed validation
check-failed422The submission's checks failed
too-many-requests429Too many requests
render-limit403As many devices are rendering as the workspace allows
lease-ended409The chunk the device took has ended
lease-taken409The chunk the device took went to another device
internal500An error inside danio

Retries and concurrency

  • Submitting a task (POST /api/v1/jobs), updating a task (POST /api/v1/jobs/{id}/versions) and comparing a draft (POST /api/v1/jobs/{id}/versions/draft) can carry an Idempotency-Key, a value you choose. Retrying with the same key within 24 hours returns the first result and doesn't register the task twice. Only successful results are remembered; a retry after a failure runs again.
  • The same three endpoints can carry X-Danio-Request, an ID you choose. The submit.progress events carry it, so you can tell which ones are yours.
  • When updating a task, send baseVersion. If a newer version exists, the answer is 409 with the error code version-conflict; compare again against the newest version.
  • Reading a project returns an ETag. When changing it (PATCH /api/v1/projects/{id}), send it back in If-Match. If someone changed it first, the answer is 412.

Lists

GET /api/v1/jobs and GET /api/v1/projects are paged: limit says how many items a page has, and the next in the answer goes into the next request's cursor. An empty next means the last page. The task list can also be filtered with project (a project ID), name (a task name, unique only within a project) and blend (a Blend file ID).

The {id} in a path accepts only IDs. To look something up by name, use a query parameter.

Event stream

GET /api/v1/events is a long-lived Server-Sent Events connection. It needs workspace.view:

curl -N -H "Authorization: Bearer $TOKEN" http://127.0.0.1:7421/api/v1/events

Each event has an id, an event (its type) and data (JSON). The id is a string; don't compare it as a number. The connection sends a : ping comment line every 15 seconds to keep itself alive.

When you reconnect, send the last Last-Event-ID you received and danio replays what you missed. It keeps the last 1024 events. When it can't replay (danio restarted, or you were away too long), it sends a reset event first; read the state again then.

The events listed in the OpenAPI description:

EventWhen
submit.progressProgress of a submission. The request field is the ID you gave in X-Danio-Request
render.progressProgress and state changes of rendering on this computer
queue.changedThe queue changed: a task joined, or the order changed
device.roomA device is low on disk space, full, or has recovered
workspace.devicesThe device list changed: a device joined or left, or its settings, name, access or block changed
workspace.join-requestA device on the local network asked to join
workspace.licenseA license was imported or removed
noticeA notice for this device's window program to show
window.showThe danio window should open a page
resetThe missed events can't be replayed; read the state again

The stream carries other events too. Ignore any event type you don't know.

The OpenAPI description

The full description of the API is OpenAPI 3.1 JSON. You can get it in two ways:

# from the command line, in Chinese by default
danio openapi > openapi.json

# in English
danio openapi --lang en > openapi.json

# from a running danio, with any valid token
curl -H "Authorization: Bearer $TOKEN" \
  "http://127.0.0.1:7421/api/openapi.json?lang=en" -o openapi.json

lang can be zh-CN or en. When it is missing, danio picks by Accept-Language, by the same rule as error messages.

In the command-line output, info.version is dev; a running danio gives its own version.

Under Settings → API, API reference opens the same description in the interface, where you can browse it.

Generic OpenAPI tools can generate a client from it, such as openapi-typescript and openapi-python-client.

Common endpoints

The permissions in the tables are the ones needed when you call with a workspace token. The local token has no limit. For the full list and the parameters, see the OpenAPI description.

Status and identity

EndpointPermissionWhat it does
GET /api/v1/healthtokenWhether the engine is running; returns the version and start time
GET /api/v1/metokenThe identity and permissions of the current token
GET /api/v1/workspaceworkspace.viewThe workspace this computer hosts: name, settings, addresses it listens on

Projects and tasks

EndpointPermissionWhat it does
GET /api/v1/projectsworkspace.viewList projects
POST /api/v1/projectsproject.editCreate a project
GET /api/v1/projects/{id}workspace.viewOne project; returns an ETag
PATCH /api/v1/projects/{id}project.editChange a project's settings, with If-Match
GET /api/v1/jobsworkspace.viewList tasks, newest first
POST /api/v1/jobsjob.submitSubmit a task, one task per scene
GET /api/v1/jobs/{id}workspace.viewTask details
DELETE /api/v1/jobs/{id}job.submitDelete a task
POST /api/v1/jobs/{id}/pausejob.submitPause; rendered frames are kept
POST /api/v1/jobs/{id}/resumejob.submitResume
POST /api/v1/jobs/{id}/canceljob.submitCancel
POST /api/v1/jobs/{id}/versions/draftjob.submitCompare against the newest version and make an update draft
POST /api/v1/jobs/{id}/versionsjob.submitUpdate the task, making a new version
GET /api/v1/jobs/{id}/previewworkspace.viewThe preview of one frame, a JPEG; without frame, the newest frame
GET /api/v1/jobs/{id}/filmsworkspace.viewThe films of each version
GET /api/v1/jobs/{id}/filmoutput.downloadDownload a film; without version, the current version; 404 when it isn't made yet

Devices and tokens

EndpointPermissionWhat it does
GET /api/v1/devicesworkspace.viewList devices
PATCH /api/v1/devices/{id}device.manageChange the name or access, block or unblock
DELETE /api/v1/devices/{id}device.manageRemove a device
GET /api/v1/tokensdevice.manageList tokens
POST /api/v1/tokensdevice.manageMake a token; the full token is returned only this once
POST /api/v1/tokens/{id}/rotatedevice.manageRotate an integration token
DELETE /api/v1/tokens/{id}device.manageRevoke a token

Plugins

EndpointPermissionWhat it does
GET /api/v1/pluginsplugin.manageList plugins
POST /api/v1/pluginsplugin.manageInstall a plugin; it is disabled after installing
POST /api/v1/plugins/{id}/enableplugin.manageEnable, sending the permissions it declares
POST /api/v1/plugins/{id}/disableplugin.manageDisable
PUT /api/v1/plugins/{id}/settingsplugin.manageChange settings
GET /api/v1/jobs/{id}/handoversworkspace.viewHow the film was handed to plugins
POST /api/v1/jobs/{id}/handovers/{plugin}/retryjob.submitHand it to a plugin again

Example

List tasks, then pause one:

curl -H "Authorization: Bearer $TOKEN" "http://192.168.1.20:7420/api/v1/jobs?limit=20"

curl -X POST -H "Authorization: Bearer $TOKEN" \
  http://192.168.1.20:7420/api/v1/jobs/<task ID>/pause

Replace 192.168.1.20:7420 with your host's workspace address.