-
-
Notifications
You must be signed in to change notification settings - Fork 4
API
BBS provides a REST API for automated provisioning of clients, repositories, and backup plans. This enables infrastructure-as-code workflows with tools like Ansible, Terraform, or CI pipelines.
All API requests require a Bearer token in the Authorization header:
Authorization: Bearer bbs_tok_...
Via Web UI: Settings > API tab > Create Token
Via CLI (useful for headless bootstrap):
sudo /var/www/bbs/bin/bbs-token create --name "ansible-provisioner"
# Output: bbs_tok_abc123...
sudo /var/www/bbs/bin/bbs-token list
sudo /var/www/bbs/bin/bbs-token revoke "ansible-provisioner"Tokens have full admin access. The token value is shown once at creation and cannot be retrieved later.
All endpoints accept and return JSON. Base URL: https://your-bbs-server
GET /api/v1/clients
Response:
{
"clients": [
{
"id": 1,
"name": "web-server-01",
"hostname": "web01.example.com",
"ip_address": "10.0.1.5",
"status": "online",
"agent_version": "2.18.7",
"borg_version": "1.4.3",
"last_heartbeat": "2026-03-30 12:00:00",
"created_at": "2026-03-01 10:00:00",
"owner": "admin"
}
]
}POST /api/v1/clients
Request:
{
"name": "web-server-01"
}Response (201):
{
"id": 42,
"name": "web-server-01",
"api_key": "a5b8c9d0e1f2...",
"status": "setup",
"install_command": "curl -s https://your-server/get-agent | sudo bash -s -- --server https://your-server --key a5b8c9d0e1f2..."
}The api_key is the agent install key. Use the install_command to install the agent on the target machine.
GET /api/v1/clients/{id}
Returns client info including repositories and plans arrays.
PUT /api/v1/clients/{id}
Request:
{
"name": "new-client-name"
}DELETE /api/v1/clients/{id}
Removes the client, deprovisions SSH access, and deletes storage.
GET /api/v1/clients/{id}/repositories
POST /api/v1/clients/{id}/repositories
Request:
{
"name": "daily-backup",
"encryption": "repokey-blake2",
"passphrase": "optional-custom-passphrase"
}If passphrase is omitted, one is auto-generated and returned in the response.
Optional fields:
-
storage_location_id- Use a specific storage location (default: server default) -
encryption- One of:none,repokey,repokey-blake2,authenticated,authenticated-blake2(default:repokey-blake2)
Response (201):
{
"id": 15,
"name": "daily-backup",
"path": "ssh://bbs-user@host/./daily-backup",
"encryption": "repokey-blake2",
"storage_type": "local",
"passphrase": "A1B2-C3D4-E5F6-G7H8-I9J0"
}POST /api/v1/clients/{id}/repositories
Request:
{
"name": "offsite-backup",
"encryption": "repokey-blake2",
"storage_type": "remote_ssh",
"remote_ssh_config_id": 3
}Use GET /api/v1/storage to find available remote_ssh_config_id values.
PUT /api/v1/clients/{id}/repositories/{repo_id}
Request:
{
"name": "new-repo-name"
}Only local repos can be renamed. Blocked while jobs are active.
DELETE /api/v1/clients/{id}/repositories/{repo_id}
Blocked if backup plans reference the repo or if jobs are active.
GET /api/v1/clients/{id}/plans
POST /api/v1/clients/{id}/plans
Request:
{
"name": "daily-full",
"repository_id": 15,
"directories": "/home\n/etc\n/var/www",
"excludes": "*.tmp\n*.log",
"advanced_options": "--compression lz4 --exclude-caches --noatime",
"frequency": "daily",
"times": "02:00",
"prune_days": 7,
"prune_weeks": 4,
"prune_months": 6,
"plugins": [
{"plugin_config_id": 5}
]
}Schedule fields:
| Field | Description | Default |
|---|---|---|
frequency |
hourly, daily, weekly, monthly, manual
|
daily |
times |
Time(s) to run, comma-separated (e.g. 02:00,14:00) |
02:00 |
day_of_week |
0-6 (Sun-Sat), required for weekly
|
- |
day_of_month |
1-31 or last, required for monthly
|
- |
Prune retention fields:
| Field | Default |
|---|---|
prune_minutes |
0 |
prune_hours |
0 |
prune_days |
7 |
prune_weeks |
4 |
prune_months |
6 |
prune_years |
0 |
Plugin attachment:
Two formats supported:
"plugins": [{"plugin_config_id": 5}, {"plugin_config_id": 8}]or map format (plugin_id: config_id):
"plugins": {"1": 5, "2": 8}PUT /api/v1/clients/{id}/plans/{plan_id}
All fields are optional — only provided fields are updated:
{
"name": "updated-name",
"directories": "/home\n/etc",
"excludes": "*.tmp",
"advanced_options": "--compression zstd --noatime",
"repository_id": 15,
"frequency": "daily",
"times": "03:00,15:00",
"day_of_week": null,
"day_of_month": null,
"timezone": "America/New_York",
"prune_days": 14,
"prune_weeks": 8,
"plugins": [{"plugin_config_id": 5}]
}DELETE /api/v1/clients/{id}/plans/{plan_id}
POST /api/v1/clients/{id}/plans/{plan_id}/pause
Disables the schedule. The plan can still be triggered manually.
POST /api/v1/clients/{id}/plans/{plan_id}/resume
Re-enables the schedule.
POST /api/v1/clients/{id}/plans/{plan_id}/trigger
Queues an immediate backup. Blocked if a backup is already queued/running for this plan.
Response:
{
"status": "ok",
"job_id": 456,
"message": "Backup queued for plan \"daily-full\""
}GET /api/v1/clients/{id}/jobs
Query parameters:
-
limit— max results (default 50, max 200) -
offset— pagination offset -
status— filter by status:queued,sent,running,completed,failed,cancelled
Response:
{
"jobs": [
{
"id": 123,
"task_type": "backup",
"status": "completed",
"plan_name": "daily-full",
"repository_name": "main-repo",
"files_total": 15000,
"files_processed": 15000,
"bytes_total": 5368709120,
"bytes_processed": 5368709120,
"duration_seconds": 342,
"queued_at": "2026-03-30 02:00:00",
"started_at": "2026-03-30 02:00:05",
"completed_at": "2026-03-30 02:05:47"
}
],
"total": 150,
"limit": 50,
"offset": 0
}GET /api/v1/clients/{id}/jobs/{job_id}
Returns full job record including error_log and status_message.
GET /api/v1/queue
Returns all currently queued, sent, and running jobs across all clients.
GET /api/v1/plugins
Returns all available plugins (mysql_dump, pg_dump, shell_hook, s3_sync).
GET /api/v1/plugins/schema
Returns field definitions for each plugin type, useful for building config forms programmatically.
GET /api/v1/clients/{id}/plugin-configs
Returns named plugin configurations for a client. Sensitive fields (passwords, keys) are masked.
POST /api/v1/clients/{id}/plugin-configs
Request (MySQL example):
{
"plugin": "mysql_dump",
"name": "Production MySQL",
"config": {
"host": "localhost",
"port": 3306,
"user": "bbs_backup",
"password": "secret123",
"databases": "*",
"dump_dir": "/home/bbs/mysql",
"compress": true,
"cleanup_after": true
}
}Response (201):
{
"id": 12,
"plugin": "mysql_dump",
"name": "Production MySQL"
}The plugin is automatically enabled for the client when a config is created.
GET /api/v1/storage
Returns both local storage locations and remote SSH configurations:
{
"local": [
{"id": 1, "name": "Default", "path": "/var/bbs/home", "is_default": 1}
],
"remote_ssh": [
{"id": 3, "name": "rsync.net", "remote_host": "ch-s011.rsync.net", "remote_user": "12345", ...}
]
}# 1. Generate API token (run once after BBS install)
- name: Generate BBS admin API token
command: /var/www/bbs/bin/bbs-token create --name "ansible"
register: bbs_token
delegate_to: backup_server
# 2. Create client
- name: Create BBS client
uri:
url: "https://backup.example.com/api/v1/clients"
method: POST
headers:
Authorization: "Bearer {{ bbs_token.stdout }}"
body_format: json
body:
name: "{{ inventory_hostname }}"
register: bbs_client
# 3. Install agent
- name: Install BBS agent
shell: "{{ bbs_client.json.install_command }}"
args:
creates: /etc/bbs-agent/config.ini
# 4. Create repository
- name: Create repository
uri:
url: "https://backup.example.com/api/v1/clients/{{ bbs_client.json.id }}/repositories"
method: POST
headers:
Authorization: "Bearer {{ bbs_token.stdout }}"
body_format: json
body:
name: "{{ inventory_hostname }}-main"
encryption: repokey-blake2
register: bbs_repo
# 5. Create MySQL plugin config
- name: Configure MySQL backup
uri:
url: "https://backup.example.com/api/v1/clients/{{ bbs_client.json.id }}/plugin-configs"
method: POST
headers:
Authorization: "Bearer {{ bbs_token.stdout }}"
body_format: json
body:
plugin: mysql_dump
name: "Production DB"
config:
host: localhost
user: bbs_backup
password: "{{ mysql_backup_password }}"
databases: "*"
dump_dir: /home/bbs/mysql
register: mysql_config
# 6. Create backup plan with MySQL plugin
- name: Create backup plan
uri:
url: "https://backup.example.com/api/v1/clients/{{ bbs_client.json.id }}/plans"
method: POST
headers:
Authorization: "Bearer {{ bbs_token.stdout }}"
body_format: json
body:
name: daily-backup
repository_id: "{{ bbs_repo.json.id }}"
directories: "/home\n/etc\n/var/www"
excludes: "*.tmp\n*.log\n*.cache"
advanced_options: "--compression lz4 --exclude-caches --noatime"
frequency: daily
times: "02:00"
prune_days: 7
prune_weeks: 4
prune_months: 6
plugins:
- plugin_config_id: "{{ mysql_config.json.id }}"| Code | Meaning |
|---|---|
| 400 | Bad request (missing required fields) |
| 401 | Invalid or missing API token |
| 403 | Token does not belong to an admin user |
| 404 | Resource not found |
| 409 | Conflict (duplicate name/path) |
| 429 | Rate limited (too many failed auth attempts) |
| 500 | Server error |
All errors return:
{"error": "Description of the problem"}📖 User Manual
Getting Started
Using BBS
- Dashboard
- Managing Clients
- Linux Agent Setup
- macOS Agent Setup
- Windows Agent Setup
- Repositories
- Storage Setup
- Backup Plans
- Restoring Files
- Database Backups
- Plugins
- Remote Storage
- S3 Offsite Sync
Monitoring
Administration
Reference