API reference
For what the API is for and how to manage keys and webhooks, see Integration API. This page is the short technical pointer.
OpenAPI description
Section titled “OpenAPI description”The REST API lives under /api/v1; its OpenAPI description is generated from the same Zod schemas the API validates requests against, and served at:
GET /api/v1/openapi.jsonPoint any OpenAPI-aware tool (Swagger UI, Postman, an SDK generator, …) at that URL against your own installation to get the full, exact, endpoint-by-endpoint contract. This documentation site does not duplicate it by hand, since a hand-copied contract would drift from the running server.
info.version of that document is the version of the contract (1.7.0 since 0.4.7; 1.6.0 came with 0.4.5 and 1.5.0 with 0.4.2, see Integration API), and x-restow-build the running build. Since 0.4.7 the status orphaned of an object also covers objects that are still at the source but no longer backed up (disabled or unlicensed account, locked by Microsoft), told apart by the new statusReason; check it before you treat orphaned as a deleted account.
Authentication
Section titled “Authentication”- API keys and provider keys (see Integration API):
Authorization: Bearer <key>, rate-limited to 600 requests per 10 minutes per key. - The web interface itself authenticates with a session cookie (better-auth); that session mechanism is not meant for third-party integrations, use an API key instead.
Live progress
Section titled “Live progress”Job progress is available as a server-sent-events stream: GET /api/v1/jobs/{id}/events.
Servers, clients, file shares and versions
Section titled “Servers, clients, file shares and versions”GET /api/v1/endpoints lists the servers and clients backed up by the Restow agent. GET /api/v1/status carries counts of them, counts of Proxmox VE guests (guests) and, since 0.4.0 (contract 1.4.0), of file shares (fileShares), and the version object (running, commit, latest, updateAvailable, channel, latestTag, publishedAt, checkError, maintenance and more). Both need the scope status:read. The fields are described under Integration API and File shares and stored bytes. physicalBytes of GET /api/v1/status and GET /api/v1/storage include the restic repositories since 0.4.1. Since 0.4.5 (contract 1.6.0) lastSuccess.groups of the status is the newest restorable backup of a Microsoft 365 group mailbox, the object kind group is a value of ObjectKind, and version.releasedAt is the release date of the running build (Contract 1.6.0). Since 0.4.7 (contract 1.7.0) the status reports Proxmox VE guests that an administrator excluded from backup as guests.excluded, and the readiness summary of the status and of GET /api/v1/verify/latest carries toConfirm, the objects that are no longer backed up and wait for a confirmation (Contract 1.7.0).
Protected mailboxes
Section titled “Protected mailboxes”GET /api/v1/usage returns the protected mailboxes of the installation, in total and per tenant (a OneDrive does not count twice, imported mailboxes, SharePoint sites and, since 0.4.5, Microsoft 365 group mailboxes do not count). It is for provider administrators signed in to the web interface, and it is what the card Protected mailboxes on the Status tab of Overview shows. Nothing limits these figures; they are there for your own overview and billing. Since 0.4.7 the card Price per month of a tenant’s overview multiplies the tenant’s figure with the prices an owner entered under Installation → Prices (Multi-tenancy). See License and editions.
Routes of the web interface (since 0.4.2)
Section titled “Routes of the web interface (since 0.4.2)”The web interface calls more routes under /api/v1 than the integration API describes. These are not part of the contract: they need a signed-in session (a provider user names the tenant with X-Restow-Tenant), an API key does not reach them, they are not in openapi.json, and they may change with the interface. They are listed because the buttons call them and the audit log records what they do. Those added since 0.4.2:
| Route | What it does | Who |
|---|---|---|
GET /api/v1/storage/destination |
Names the effective primary repository of the tenant: its own primary (name, kind, path or bucket) or the installation default (its path for provider administrators only). It is the line “Backups land in” and tells whether the server’s own disk is the target (Where backups land). | Tenant administrators |
POST /api/v1/pve/guests/:id/repository/reset |
Reset repository of a container. Body { "confirmName": "<guest name>" }; needs a recent sign-in. Every restore point of the container becomes unavailable, the next backup begins a new chain. Audited as pve.repository.reset. |
Tenant administrators |
POST /api/v1/pve/guests/:id/verify |
Check now for the newest restore point of a guest. Answers 202. | Tenant administrators |
POST /api/v1/pve/verify-unverified |
Check all unverified: the newest restore point of every guest that no check has read and none waits for. Answers 202 with how many were queued. | Tenant administrators |
GET /api/v1/settings/pve, PUT /api/v1/settings/pve |
The installation’s Proxmox VE settings, today verifyAfterBackup (check every new restore point right after the backup, on by default). Read by every provider administrator, changed by an owner. Audited as settings.pve.updated. |
Provider |
GET /api/v1/snapshots/:id/calendar |
The calendar of a mailbox restore point in a window (from and to, at most 3660 days apart; path defaults to calendar; entryId opens one series), every series expanded into its occurrences. Audited as snapshot.calendar.read. |
Tenant users, for what they may see |
GET /api/v1/snapshots/people |
One page of the Restore explorer’s left column: section (people or sites), q (names, addresses and account ids), kind (mailbox, onedrive, imap or site), limit (50 by default, up to 200) and after (the next cursor of the previous page), the signed-in person’s own entry first. The snapshot objects carry ownerKey and ownerName. |
Tenant users, for what they may see |
The stop and update buttons use routes of their own: POST /api/v1/pve/guests/:id/cancel, POST /api/v1/pve/nodes/:id/queue/pause, .../queue/resume and .../queue/cancel, POST /api/v1/pve/queue/cancel and POST /api/v1/pve/nodes/:id/update for Proxmox VE, PUT /api/v1/pve/guests/:id/restow-server for marking the Restow server’s own VM, POST /api/v1/endpoints/:id/cancel and POST /api/v1/endpoints/:id/update for machines, and PUT /api/v1/settings/time-zone for the installation’s time zone. Since 0.4.3, Update nodes and agents now calls POST /api/v1/updates/fleet/update-now (an administrator with every tenant; audited as update.fleet_started with manual: true), and the Proxmox VE inventory GET /api/v1/pve reports for every node, next to its helperVersion, the offeredVersion (the restow-pve release the server offers) and outdated. A guest’s lastVerify.state can be yellow since 0.4.3, with notChecked saying why the restore check could not run.
Archive capture (since 0.4.4)
Section titled “Archive capture (since 0.4.4)”The archive capture since 0.4.4 (Graph, IMAP archiving, forwarded copies; see Archiving) adds routes and fields of the same kind: for the web interface, not part of the contract (1.5.0 is unchanged), not in openapi.json, not reached by an API key. They need a signed-in tenant administrator and a Business or Service Provider license where the capture needs one.
| Route or field | What it does |
|---|---|
GET /api/v1/archive/capture |
The state of each capture way: whether the edition includes it, the streams by status (pending, backfilling, live, paused, disabled, error), how mail is noticed (notified or checked at intervals, with the reason such as graph.notification_url_unavailable or imap.idle_budget), the counts of 24 hours and 7 days and the progress of the takeover. jobs lists the mail jobs whose IMAP or Google Workspace accounts wait for a capture way. |
GET /api/v1/archive/capture/mailboxes |
The capture per mailbox, filtered by way and status, a page at a time. |
POST /api/v1/archive/capture/mailboxes/:objectId/resync |
Catch up: reads the mailbox again completely on the next pass. Answers 202; audited as archive.capture.resync_requested. |
GET /api/v1/archive/capture/holds |
Per Microsoft 365 source whether a hold is confirmed, and checks: the read-only Exchange Online and Security & Compliance PowerShell commands that check holds and retention policies. |
PUT /api/v1/archive/capture/holds/:sourceId |
Body { "status": "confirmed" } or { "status": "unknown" }: the administrator’s confirmation that a retention policy or litigation hold keeps deleted mail in the tenant, or its withdrawal. Audited as archive.hold.confirmed and archive.hold.unconfirmed. Restow cannot check it. |
GET /api/v1/archive/forwarding |
The IMAP accounts whose job chose forwarding, their archive addresses and the forwarded copies of the last 7 days. It issues nothing. |
POST /api/v1/archive/forwarding/:objectId/address |
Issues the account’s archive address, once. Audited as archive.forward.address_created. |
POST /api/v1/archive/forwarding/:objectId/rotate |
Replaces the address; the old one is refused at once. Audited as archive.forward.address_rotated, with a fingerprint only. |
GET /api/v1/archive/journal |
Now also names firstReportAt, the first journal report that arrived. |
GET /api/v1/archive/search |
includeSuperseded=true also lists the captures that a stronger one replaced; without it they are hidden. The item detail links both ways (supersededBy, captures). The export of the current search carries it as includeSuperseded in the search filter. |
archiveCapture of a mail job |
The capture ways per kind of mailbox (m365: graph, journal; imap and google: sync, forward), on create, change and read of /api/v1/backup-jobs. A job that archives without a way for a kind it covers is refused with 422 archive_capture_no_way. See How mail reaches the archive. |
captureKind of a member or candidate |
m365, google, imap or imap_microsoft: the kind of mailbox, which decides the ways the editor offers. |
mailSourceKinds of GET /api/v1/backup-jobs/defaults?kind=mail |
The kinds of the tenant’s active mail objects. |
archiveIdle of PATCH /api/v1/sources/:id |
auto (the default) or off for an IMAP source: off is Check at intervals only, no connection stays open. |
Public hooks. Two routes are open to the internet without a session, for Microsoft Graph only: POST /api/v1/hooks/graph/notifications and POST /api/v1/hooks/graph/lifecycle. The validation token of a new subscription is echoed back, everything else is answered 202, only a notification whose clientState matches the subscription’s stored SHA-256 counts, and a notification carries no mail, only the fact that one arrived. The body is limited to 1 MiB and the routes answer 404 while the edition does not include capture from the mailbox. They are not for integrations; see Network and ports.
Routes of the web interface (since 0.4.5)
Section titled “Routes of the web interface (since 0.4.5)”Like those since 0.4.2, the routes behind the buttons that came with 0.4.5 are not part of the contract: they need a signed-in session (a provider user names the tenant with X-Restow-Tenant), an API key does not reach them, they are not in openapi.json, and they may change with the interface.
| Route | What it does | Who |
|---|---|---|
POST /api/v1/backup-jobs/:id/cancel |
Stop on a job of the list Mail & SaaS or Servers & clients: withdraws every queued backup of a mail, machine, share or copy job and asks every running one to stop, in one request. Audited as backup_job.run_cancelled on the job and, for machines, per machine (endpoint.backup.cancelled). |
Tenant administrators and provider roles that may operate; closed in the public demo |
POST /api/v1/pve/jobs/:id/run |
Start now on a Proxmox VE job: queues a backup of every guest the job covers, as its schedule would, without moving the schedule. Guests that already have a backup waiting, are on a node without restow-pve or are the unconfirmed Restow server VM are skipped and counted. Audited as pve.job.run_requested. |
Same |
POST /api/v1/pve/jobs/:id/cancel |
Stop on a Proxmox VE job: withdraws its queued backups and asks its running ones to stop. Audited as pve.job.cancelled. |
Same |
POST /api/v1/endpoints/:id/remove |
Remove from Restow for a revoked machine. Body { "mode": "delete" | "expire", "confirmHostname": "<hostname>" }; needs a recent sign-in. Audited as endpoint.removed. See Uninstall and re-enroll for the answers (409 endpoint-not-revoked, endpoint-removal-legal-hold, endpoint-removal-suspicion-hold, endpoint-removal-never-expires; 422 endpoint-confirm-hostname). |
Tenant administrators |
GET /api/v1/endpoints/removals |
The removed machines whose backups are not deleted yet, with the date, the hold or the storage lock. It is the list below Inventory. | Tenant administrators |
Since 0.4.6 the routes that read a machine’s backups (GET /api/v1/endpoints/:id, /snapshots, /browse, /downloads and POST .../repository-password) also answer for a removed machine until its backups are deleted, audited as for a revoked one. Restoring onto the machine and every other action on it answer 404; once the backups are deleted, it is gone for every reader.
Routes of the web interface (since 0.4.7)
Section titled “Routes of the web interface (since 0.4.7)”Like those since 0.4.2 and 0.4.5, the routes behind the buttons that are new since 0.4.7 are not part of the contract (1.7.0 adds only fields and values, see Integration API): they need a signed-in session (a provider user names the tenant with X-Restow-Tenant), an API key does not reach them, they are not in openapi.json, and they may change with the interface.
| Route | What it does | Who |
|---|---|---|
POST /api/v1/directory/objects/:id/inactive/confirm |
Yes, intended for one object that is no longer backed up (see Objects that are no longer backed up). The body may carry a note (1 to 1000 characters) for the audit log; the interface does not ask for one. Audited as directory.inactive.confirmed. |
Tenant administrators and provider roles that may configure |
POST /api/v1/directory/objects/inactive/confirm |
The same for several objects of the tenant: { "objectIds": [...] } or { "filter": {...} } (the filter of the list), at most 1000, with the same optional note. Only objects that still wait for a confirmation are confirmed. Audited as directory.inactive.bulk_confirmed. |
Same |
GET /api/v1/directory/objects |
Also takes the filters to_confirm and confirmed for the status of objects no longer backed up, and returns statusReason, inactiveSince, statusConfirmedAt and statusConfirmedBy (an address, api-key:<id>, migration or excluded). |
Tenant administrators and provider roles that may view |
PATCH /api/v1/sources/:id/own-app/expiry |
Notes, changes or removes ({ "secretExpiresAt": "2027-03-01" } or null) the expiry date of the client secret of a source’s own app without entering the secret again. Audited as source.own_app.expiry_updated. A certificate has its own date. |
Tenant administrators and provider roles that may configure |
PUT /api/v1/pve/guests/:id/excluded |
Exclude from backup or Include again for a Proxmox VE guest: body { "excluded": true } or false, answer 204. Audited as pve.guest.excluded with the number of queued backups withdrawn. Excluding twice changes nothing. GET /api/v1/pve reports excludedAt and excludedBy per guest. A backup or a job assignment of an excluded guest is refused with 409 urn:restow:problem:pve-guest-excluded. |
Tenant administrators and provider roles that may configure |
GET /api/v1/settings/pricing, PUT /api/v1/settings/pricing |
The monthly prices behind the price card: currency (EUR, CHF, USD or GBP), mailboxPrice, storagePrice and storageUnit (GB or TB), each price at most four decimals or null. Read by every provider administrator with every tenant, changed by the owner. Audited as settings.pricing.updated with the values before and after. Tenant users never see them. |
Provider |
Operational endpoints (outside /api/v1)
Section titled “Operational endpoints (outside /api/v1)”| Endpoint | Purpose |
|---|---|
GET /healthz |
Process is up. |
GET /readyz |
Process is ready to serve (dependencies such as the database are reachable). |
These are unauthenticated and unversioned on purpose, so a load balancer or container orchestrator can probe them without credentials.
Endpoints for the agent (outside /api/v1)
Section titled “Endpoints for the agent (outside /api/v1)”| Endpoint | Purpose |
|---|---|
/agent/v1/* |
The API of the Restow agent: enrollment, configuration, heartbeat, runs, agent update. Enrollment uses a one-time token, every other call the agent’s own per-endpoint secret; no API key is involved. |
/agent/restic/<endpoint id>/ |
The restic repository of one endpoint. It is append-only for the agent. |
/install/* |
The install scripts and the agent and restic binaries with their SHA256SUMS, for the install command. |
They are served on the same public address as the web interface and are used by the agent and the install command, not by integrations. The runners of file share backups use paths under /internal/ instead, which the web edge never forwards: they are reachable only on the internal Docker network runners. For machine data, use GET /api/v1/endpoints. See Endpoint backup.