No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.
403
The account is not an admin. This prefix requires ADMIN in every method, reading included.
403
The installation is in demo mode, where backup, storage and accounts are off the air.
SENT means the file went to the bucket, which is why /api/backup/file refuses in that state.
POST/api/backup/job
Role: Admin
Schedules the generation of a backup.
Request body
Field
Type
Description
destination
enum
LOCAL writes in the container; S3 sends it to the bucket. Absent uses whatever is configured.LOCAL · S3When absent: o destino configurado
Request
curl-s-X POST http://localhost:3000/api/backup/job \-H"Authorization: Bearer $TOKEN"\-H"Content-Type: application/json"\-d'{ "destination": "S3" }'
// The backup is a JOB: the file only exists once status reaches READY.awaitfetch("http://localhost:3000/api/backup/job",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${token}`,},body: JSON.stringify({destination:"LOCAL"}),});let job;
do {awaitnewPromise((resolve)=>setTimeout(resolve,2000));const response =awaitfetch("http://localhost:3000/api/backup/job",{headers:{Authorization:`Bearer ${token}`},});
job =await response.json();}while(job.status ==="PENDING"|| job.status ==="RUNNING");
No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.
403
The account is not an admin. This prefix requires ADMIN in every method, reading included.
403
The installation is in demo mode, where backup, storage and accounts are off the air.
409
An export is already under way.
422
Destination S3 was asked for, but no bucket is configured for backups.
The .zip that stays in the container has a fixed name, one copy and an expiry; the one that goes to the bucket has a timestamped name, accumulates and never expires.
DELETE/api/backup/job
Role: Admin
Cancels the export under way, or discards the file already made.
No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.
403
The account is not an admin. This prefix requires ADMIN in every method, reading included.
403
The installation is in demo mode, where backup, storage and accounts are off the air.
409
The configured bucket does not keep backups: the scope in effect sends the .zip to disk.
name comes without the prefix: it is exactly what you send back in the remote field of inspection and restore.
POST/api/backup/inspect
Role: Adminmultipart/form-data
Reads a backup and answers what the restore WOULD do. It writes no byte.
It returns the format version, one block per workspace with the count of each scope, the attachments that would not be recreated and how the file's accounts compare to today's.
Request body
Field
Type
Description
file
arquivo (.zip)
The .zip sent in the multipart.
remote
string
The name of a backup in the bucket, downloaded on the SERVER.
Request
# from disk…curl-s-X POST http://localhost:3000/api/backup/inspect \-H"Authorization: Bearer $TOKEN"\-F"[email protected]"# …or from one already in the bucket. Never both: that is 400.curl-s-X POST http://localhost:3000/api/backup/inspect \-H"Authorization: Bearer $TOKEN"\-F"remote=notebugs-backup-2026-09-08T22-39-26.zip"
Both file and remote came in the same request. It is one or the other, never both.
401
No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.
403
The account is not an admin. This prefix requires ADMIN in every method, reading included.
403
The installation is in demo mode, where backup, storage and accounts are off the air.
422
The .zip is not a NoteBugs backup, is corrupted, or comes from a version this installation cannot read.
file and remote never come together: both is 400. A remote source loosens no validation: from there down there are only bytes.
POST/api/backup/import
Role: Adminmultipart/form-data
Restores a backup, whole or sliced per workspace.
Request body
Field
Type
Description
file
arquivo (.zip)
remote
string
selection
JSON
JSON with the scopes PER workspace of the file, plus settings and users. This is what the interface sends.
scopes
JSON (forma antiga)
The old shape: a flat list of scopes applied to every workspace in the file. Still accepted.
Request
# restores everything: no selection, no scopescurl-s-X POST http://localhost:3000/api/backup/import \-H"Authorization: Bearer $TOKEN"\-F"[email protected]"# per-workspace selection: this is what the interface sendscurl-s-X POST http://localhost:3000/api/backup/import \-H"Authorization: Bearer $TOKEN"\-F"remote=notebugs-backup-2026-09-08T22-39-26.zip"\-F'selection={
"tenants": {
"cmsp4djx60002p801o7ybpkv7": ["projects", "cards", "comments"]
},
"settings": false,
"users": false
}'
Both file and remote came in the same request. It is one or the other, never both.
401
No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.
403
The account is not an admin. This prefix requires ADMIN in every method, reading included.
403
The installation is in demo mode, where backup, storage and accounts are off the air.
422
The .zip is not a NoteBugs backup, is corrupted, or comes from a version this installation cannot read.
422
The selection asks for a scope without the one it depends on: epics without projects, comments without cards.
With neither selection nor scopes, it restores everything, except accounts, which take an explicit ask (users: true): restoring accounts changes who reaches the installation.