REST API¶
Everything the Web UI and fallbck-ctl do goes through /api/v1 on the server's public URL. It's plain JSON over HTTPS. There's no OpenAPI spec yet, so this page is the map.
Auth¶
Create an API key under API Keys in the Web UI and send it as a bearer token:
curl -H "Authorization: Bearer fbk_..." https://backup.example.com/api/v1/agents
Keys are hashed at rest, and you only see the raw one once, when you create it. Browser sessions work too, but then state-changing requests need X-Requested-With: fallbck. That's CSRF protection, so scripts should just use a key.
Errors come back as {"error": "<message>"} with a sensible status code.
Health¶
| Method | Path | Notes |
|---|---|---|
GET |
/health |
No auth. Use it for load balancer checks. |
GET |
/auth/me |
Who you're authenticated as: kind, subject, email, name. |
Enrollment tokens¶
| Method | Path | Notes |
|---|---|---|
POST |
/tokens |
Create one. Returns raw_token exactly once. |
GET |
/tokens |
List. |
GET |
/tokens/{id} |
|
DELETE |
/tokens/{id} |
POST /api/v1/tokens
{ "name": "web-01", "max_uses": 1, "expires_at": "2026-12-31T00:00:00Z" }
max_uses: 0 means unlimited, and it defaults to 1.
API keys¶
| Method | Path | Notes |
|---|---|---|
POST |
/apikeys |
{"name": "...", "expires_at": "..."} (expiry optional). Returns raw_key once. |
GET |
/apikeys |
|
DELETE |
/apikeys/{id} |
Revokes the key. |
Agents¶
| Method | Path | Notes |
|---|---|---|
GET |
/agents |
|
GET |
/agents/{id} |
|
DELETE |
/agents/{id} |
|
POST |
/agents/{id}/debug |
{"enabled": true} turns on live debug logging. |
POST |
/agents/{id}/auto-update |
{"enabled": true} opts the agent into self-update. |
POST |
/agents/{id}/update |
Update to the server's version on the next heartbeat. |
POST |
/agents/{id}/merge |
{"into": "<agent id>"}. Moves jobs and runs, then deletes this agent. |
POST |
/agents/{id}/logs |
Fetches the agent's buffered log lines. The agent has to be online. |
POST |
/agents/{id}/inventory |
Asks for the full inventory. The agent has to be online. |
PBS targets¶
| Method | Path | Notes |
|---|---|---|
POST |
/targets |
Create. |
GET |
/targets |
|
GET |
/targets/{id} |
|
PUT |
/targets/{id} |
Same body as create. |
DELETE |
/targets/{id} |
|
POST |
/targets/{id}/clone |
{"name", "namespace", "pxar_format"}. Copies the token server-side. |
GET |
/targets/{id}/credentials |
PBS_* exports for proxmox-backup-client. Logged. |
POST /api/v1/targets
{
"name": "pbs-main",
"target_type": "pbs",
"endpoint": "https://pbs.example.com:8007",
"datastore": "store1",
"namespace": "prod",
"auth_token": "backup@pbs!fallbck:xxxxxxxx-xxxx-...",
"fingerprint": "AA:BB:...",
"tls_verify": true,
"pxar_format": "v2",
"encryption_mode": "none"
}
The token is stored sealed and is never returned. Pin a self-signed PBS with fingerprint, or use tls_verify with a proper chain.
Encryption¶
| Method | Path | Notes |
|---|---|---|
GET |
/targets/{id}/encryption |
Mode, fingerprint, master key status. |
PUT |
/targets/{id}/encryption |
{"mode": "encrypt" \| "none", "master_public_key": "<PEM or empty>"} |
POST |
/targets/{id}/encryption/rotate |
New key. The old one gets retired, not deleted. |
POST |
/targets/{id}/encryption/export |
{"passphrase", "hint", "key_id"}. Returns a proxmox-backup-client key file. Leave key_id empty for the active key. |
POST |
/targets/{id}/encryption/import |
{"keyfile", "passphrase"} |
See Encryption for what all of this means.
Microsoft 365 tenants¶
| Method | Path | Notes |
|---|---|---|
POST |
/m365/tenants |
Create. |
GET |
/m365/tenants |
|
GET |
/m365/tenants/{id} |
|
PUT |
/m365/tenants/{id} |
|
DELETE |
/m365/tenants/{id} |
Refused while jobs still use it. |
POST |
/m365/tenants/{id}/test |
Gets a token and reads /organization. |
{
"name": "contoso",
"tenant_id": "00000000-0000-0000-0000-000000000000",
"client_id": "11111111-1111-1111-1111-111111111111",
"auth_method": "secret",
"secret": "..."
}
For certificate auth, use "auth_method": "certificate" with certificate_pem and key_pem. Secrets are write-only.
Jobs¶
| Method | Path | Notes |
|---|---|---|
POST |
/jobs |
Create. |
GET |
/jobs |
|
GET |
/jobs/{id} |
Passwords are never returned (has_password tells you one is set). |
PUT |
/jobs/{id} |
|
DELETE |
/jobs/{id} |
Removes its schedule too. |
POST |
/jobs/{id}/run |
Run now. |
Common fields:
{
"name": "web-01 etc",
"agent_id": "<uuid>",
"target_id": "<uuid>",
"job_type": "filesystem",
"schedule_cron": "0 2 * * *",
"enabled": true,
"direct_pbs": false,
"backup_paths": ["/etc", "/srv"],
"exclude_paths": ["*.tmp"]
}
job_type is one of filesystem, database, kubernetes, pve, docker or m365. Every type besides filesystem takes its settings in a matching object: db_config, k8s_config, pve_config, docker_config or m365_config. A database job, for example:
{
"job_type": "database",
"db_config": {
"engine": "postgres",
"host": "localhost",
"user": "",
"profile": "",
"databases": [],
"postgres": { "mode": "dump" }
}
}
Easiest way to get a type-specific body right
Set one job up in the Web UI, GET /jobs/{id} it, and use that as your template. The per-type specs have quite a few knobs, and they map one-to-one to the job form.
Runs¶
| Method | Path | Notes |
|---|---|---|
GET |
/runs |
Recent runs. |
GET |
/runs/{id} |
Includes the type-specific detail blob. |
POST |
/runs/{id}/cancel |
Agent-only endpoints¶
These are what agents call, authenticated with their own bearer token. You won't need them unless you're writing an agent, but they're listed here so nothing's a mystery:
POST /agents/enroll (enrollment token), POST /agents/heartbeat, POST /agents/token/rotate, POST /agents/token/worker, POST /agents/ticket/refresh, POST /agents/sub-ticket, POST /agents/volume-ticket, POST /agents/run-progress, GET /agents/pbs-credentials, GET /agents/encryption-key, GET /agents/db-credentials, GET /agents/m365-credentials, GET /agents/update/{os}/{arch}.
The credential endpoints also need a valid backup ticket in X-Fallbck-Backup-Ticket. The Architecture page explains the flow.