API authentication

Everything the Depllo dashboard does goes through the REST API — and the same API is open to your scripts, CI jobs and agents. The simplest credential for them is a workspace API key.

Base URL

https://depllo.forjio.com/api/v1

Create an API key

  1. Open Dashboard → API Keys in the workspace the key should act in (use the workspace switcher first).
  2. Create key, name it after what will use it (deploy script, Catent, …).
  3. Copy the key from the dialog. It looks like sk_live_ followed by 48 hex characters, and this is the only time it is shown — store it like a password (a secret manager, a CI variable marked masked).

Keys are also available over the API (POST /api/v1/api-keys) — but only to a signed-in person: a request authenticated by a key cannot create, list or revoke keys (403 FORBIDDEN), so a leaked key cannot mint more.

Send it

Put the key in the Authorization header as a Bearer token, on any /api/v1 route:

Authorization: Bearer sk_live_…

What a key is:

  • Workspace-scoped. Every call acts in the workspace the key was created in — its projects, pipelines, runners, variables, schedules, usage and audit log — as the person who created it. Audit-log entries made through a key are labelled API key "<name>".
  • Shown once, stored hashed. Depllo keeps only a SHA-256 hash and a display prefix (sk_live_ + 4 characters) — the dashboard lists the prefix, when the key was created and when it was last used.
  • Long-lived until revoked. Keys don't expire. Revoking one (dashboard, or DELETE /api/v1/api-keys/:id) takes effect immediately: the next request with it gets 401 INVALID_TOKEN.

A Huudis access token (what depllo auth login stores) is accepted the same way — Authorization: Bearer <access-token> — but it is short-lived; use a key for anything unattended. The runner protocol uses its own runner tokens, not API keys.

Examples

curl

export DEPLLO_TOKEN=sk_live_…

# List projects
curl -H "Authorization: Bearer $DEPLLO_TOKEN" \
  https://depllo.forjio.com/api/v1/projects

# Run a pipeline on main
curl -X POST https://depllo.forjio.com/api/v1/projects/proj_01hx…/pipelines \
  -H "Authorization: Bearer $DEPLLO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: deploy-$(date +%s)" \
  -d '{"ref": "main", "variables": {"DEPLOY_ENV": "staging"}}'

JavaScript / TypeScript

import { DeplloClient } from "@forjio/depllo";

// token defaults to process.env.DEPLLO_TOKEN
const depllo = new DeplloClient({ token: process.env.DEPLLO_TOKEN! });

const { data: projects } = await depllo.projects.list();
await depllo.pipelines.run(projects[0]!.id, { ref: "main" });

// Every route also has a method on depllo.api (generated from the spec):
const usage = await depllo.api.usageList();

Python

from forjio_depllo import DeplloClient

depllo = DeplloClient()  # token= or the DEPLLO_TOKEN env var

projects = depllo.api.projects_list()["data"]
depllo.api.projects_create_pipelines(projects[0]["id"], ref="main")

Go

c := depllo.New(depllo.Config{Token: os.Getenv("DEPLLO_TOKEN")}) // sk_live_…
raw, err := c.API.ProjectsList(ctx)

CLI

The CLI uses DEPLLO_TOKEN when it is set, otherwise what depllo auth login saved — an API key (depllo auth login --api-key - reads it from stdin) or your Huudis session:

export DEPLLO_TOKEN=sk_live_…          # or, once: depllo auth login --api-key - < key.txt
depllo api projects list
depllo api projects create-pipelines proj_01hx… --ref main
depllo pipeline logs job_01hx… --follow

depllo api <area> <action> has a command for every API route — run depllo api --help to browse them.

Response envelope

Every response — success or failure — has the same shape:

{
  "data": { },
  "error": null,
  "meta": { "requestId": "req_01jx…", "timestamp": "2026-09-30T03:00:00.000Z" }
}

On failure data is null, error carries an UPPER_SNAKE_CASE code and a message, and the HTTP status matches:

Code HTTP Meaning
AUTH_REQUIRED 401 No Authorization header (or session)
INVALID_TOKEN 401 Unknown, malformed or revoked API key; invalid access token
FORBIDDEN 403 Authenticated, but not allowed (e.g. a key managing keys)
NOT_FOUND 404 No such resource in this workspace
VALIDATION_ERROR 400 A field is missing or invalid — error.param names it
CONFLICT 409 State conflict
INTERNAL_ERROR 500 Our side — retry, then contact support with meta.requestId

Match on error.code, not the message. Mutating requests accept an Idempotency-Key header; the SDKs and the CLI send one for you.

See also