Public API and chat apps
You can drive a Reaver dashboard from a script, n8n, or a chat app (Claude, Cursor, LibreChat, Open WebUI) without using the browser. Those clients start the same backups, restores, and exports as the Run button.
AI clients that speak MCP should use the built-in MCP server at /api/v1/mcp (all paid plans, off until you enable it). The MCP server is the same control plane as this API. Setup and permissions: MCP Server for AI Agents.
There are three ways things talk to a dashboard. Do not mix them.
| Who | How they authenticate | Can start jobs? |
|---|---|---|
| You, in a script or chat app | A token that starts with rv2_ (or sign-in from the chat app) |
Yes — same as the UI |
| Backup agents on WordPress hosts | Agent id + secret | No. They only pick up and report work |
| You, in the browser | Login cookie | Yes |
A full technical spec lives on your install at GET /api/v1/openapi.json (token required). In the dashboard: Security → Guide.
Create a token
Security → API tokens. Name it, pick a permission, optionally set an expiry. Copy the secret immediately — it is shown once. Revoke from the same card.
| Permission | Can do |
|---|---|
read |
Look at sites, jobs, snapshots, schedules, agent status, destination names |
backup |
Everything in read, plus choose storage, start backups, run a schedule now, check the host |
restore |
Everything in backup, plus restore and export. Restore must repeat the site name in confirm_slug. Export queues an archive; it does not return the file |
admin |
Tokens, chat-app toggle, outbound webhooks. Adding destinations and pairing agents stays in the UI |
Each level includes the one above it. A User account can create read or backup tokens, not restore or admin.
Send the token as:
Authorization: Bearer rv2_…
No cookies. Other websites cannot call this API from a browser. Failures look like { "ok": false, "error": { "code", "message" } }. Responses never include destination keys, restic passwords, or agent secrets.
Names used in requests
Use these field names. A display name such as shop.example.com is mapped to the site slug.
site_slug— the sitejob_id— a job numberdest_id— where to store data (local, or an Off-Site destination)snapshot_id— one restic snapshotschedule_id/webhook_id/agent_id
Work started here is labeled api:<token name> on the Jobs page.
What you can call
Everything is under /api/v1. On start-work requests, send an Idempotency-Key header (any unique string) so a retry does not create a second job. dry_run: true checks without starting work.
| Call | What it does |
|---|---|
GET / |
What this install can do |
GET /me |
This token’s name and permission |
GET /sites · GET /sites/{site_slug} |
List or show a site |
GET /sites/{site_slug}/snapshots |
Snapshots |
POST /sites/{site_slug}/repo |
Choose storage and encryption (none or encrypted) |
GET /jobs · GET /jobs/{job_id} |
List or watch a job |
GET /agents · GET /schedules · GET /destinations |
Fleet, schedules, destination names |
POST /backups/validate · POST /backups |
Check, then start a backup |
POST /backups/all |
Start a backup for every site |
POST /schedules/{schedule_id}/run |
Run a schedule now |
POST /preflight |
Ask the agent to check the host (disk, dest, optional MySQL) |
POST /restores |
Restore. Send confirm_slug equal to the site slug |
POST /exports |
Queue an archive |
GET/POST /webhooks |
List or create a webhook (admin) |
POST /mcp |
Chat-app connection (off until you enable it) |
Typical backup
- List sites if you need a slug.
- Check the backup. If the response asks you to pick a destination or set encryption, do that first.
- Optionally run a host check (
POST /preflight) and wait for that job. - Start the backup. Watch
GET /jobs/{job_id}until it is completed or failed. Queued is not finished.
export REAVER_URL="https://reaver.example.com"
export REAVER_TOKEN="rv2_…"
curl -sS -H "Authorization: Bearer $REAVER_TOKEN" "$REAVER_URL/api/v1/sites"
curl -sS -H "Authorization: Bearer $REAVER_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"site_slug":"my-site","dest_id":"local"}' "$REAVER_URL/api/v1/backups"
Restore is the same shape plus snapshot_id and confirm_slug equal to the site slug.
Host check (preflight)
Checking a backup in the API only looks at dashboard records. A preflight job asks the agent to check the real machine: site path, destination reachable, free disk on local/SSH (S3/B2 skip disk), optional MySQL from wp-config.php. It is not a backup and does not send backup emails.
Common errors
| Code | Meaning |
|---|---|
needs_choice |
Pick a destination. The response includes the list |
needs_config |
Choose storage and encryption first |
confirm_required |
Restore is missing a matching confirm_slug |
license |
The plan does not allow this (restore still works when expired) |
agent_offline |
The site’s agent has not checked in |
scope_denied |
This token’s permission is too low |
The API does not download archive files, add destinations, pair agents, or destroy repositories. Use the dashboard for those.
Connect a chat app
Reaver V2 ships a built-in MCP server for AI agents. Full guide: MCP Server for AI Agents.
Security → MCP server (off until you turn it on). Then add this URL in Claude, Cursor, LibreChat, Open WebUI, or LM Studio:
https://your-dashboard.example/api/v1/mcp
The app can then list sites, start backups, and check jobs — limited by the token’s permission. Point the app at this URL, not at /openapi.json.
If the app lets you paste a header instead of signing in:
{
"mcpServers": {
"reaver-backup": {
"url": "https://reaver.example.com/api/v1/mcp",
"headers": {
"Authorization": "Bearer rv2_…"
}
}
}
}
Sign-in from a chat app
Most chat apps open a browser and ask you to sign in. That is expected. You sign in to this Reaver dashboard, pick a permission, and Approve. The app receives a token; a new row appears under Security → API tokens. You do not need a third-party login provider.
LibreChat: it builds the return address from DOMAIN_SERVER (default http://localhost:3080). If you open LibreChat at a LAN IP or hostname, set both DOMAIN_SERVER and DOMAIN_CLIENT to that URL and restart. HTTP on the LAN is fine. The Reaver approve page can also send this one login back to the address you actually use.
After the first approve, LibreChat sometimes opens a second connection without the token. Connect once from that host; Reaver reuses the token from that same IP for the chat-app URL only. Revoke the token row to drop it.
Get notified when a job finishes
Security → Outbound webhooks, or POST /api/v1/webhooks with an admin token.
Public internet URLs must be HTTPS. HTTP is allowed to localhost and your LAN. The signing secret (whsec_…) is shown once. Deliveries are queued so they never slow down agents.
X-Reaver-Event: backup.completed
X-Reaver-Delivery-Id: whd_…
X-Reaver-Timestamp: 1710000000
X-Reaver-Signature: sha256=<hex>
The signature is HMAC-SHA256 of timestamp + '.' + delivery_id + '.' + raw_body. Three HTTP 401 or 410 responses in a row disable the webhook.
Events: backup.queued / started / completed / failed; restore.started / completed / failed; job.completed / job.failed; agent.connected / agent.offline.
Nginx
The installer nginx template already routes /api/v1* and forwards the Authorization header. After you change nginx: sudo nginx -t && sudo systemctl reload nginx.
Agent poll (not for scripts)
Agents authenticate with pairing secrets and call api/jobs.php and related paths. Those URLs can carry restic and destination secrets. Do not use them from n8n or a chat app.
Website APIs (account / license / feedback)
These live on the Reaver marketing site (this website), not on your dashboard. They use a different token than rv2_.
| Endpoint | Purpose |
|---|---|
POST /api/link-license.php |
Link dashboard to website account; returns plan, limits, api_token |
POST /api/verify-license.php |
Re-check plan/limits |
POST /api/encryption-waiver.php |
Record restic encryption waiver accept |
POST /api/feedback.php |
Product feedback |
POST /api/telemetry.php |
Anonymous product stats (default on; opt out anytime) |
License responses include limits.max_sites and limits.max_offsite so the dashboard can enforce quotas locally. Dashboards also send installation_id, optional machine_id, used_sites, and used_offsite so usage is counted across every install on the account.
Encryption waiver
When you accept the restic encryption liability waiver, the linked dashboard posts it here so it is stored on the account. If the website is unreachable, local policy still applies.
POST /api/encryption-waiver.php
Authorization: Bearer <api_token>
Content-Type: application/json
{
"waiver_version": "restic-encryption-v1",
"accepted_by": "admin",
"accepted_at": 1712345678,
"recovery_ack": true,
"recovery_ack_at": 1712345678,
"installation_id": "…",
"machine_id": "…",
"install_label": "backup-host",
"dashboard_version": "0.3.x"
}
Anonymous product stats
Limited, non-identifying heartbeats for product planning. Not license usage. Default on; opt out with anonymous_statistics: false. Prefer schema_version: 2.
Rules: no hostnames, emails, paths, tokens, or error text. Clients fail open — stats never block backups. Details: Configuration and the Privacy Policy.