Workspace Backup API
The workspace backup API lets workspace owners and administrators periodically download the portable business data stored in Keito. It is a read-only API surface separate from the normal integration endpoints, so it does not change the request or response formats used by desktop, CLI, Zapier, or other API clients.
A backup consists of a manifest followed by every page of every resource listed in that manifest. File bytes are downloaded separately using the authenticated URLs included in expense and invoice records.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v2/backup |
Get the versioned manifest, resource list, and record counts |
GET |
/api/v2/backup/:resource |
Download one paginated resource |
GET |
/api/v2/backup/files/invoice_expense_receipts/:id |
Download an invoice’s immutable copy of an expense receipt |
All three endpoints are new. They do not accept a request body.
Authentication and Permissions
Send the same two headers used by the rest of API v2:
Authorization: Bearer kto_xxxxx
Keito-Account-Id: your_company_id
The API key’s user must be an owner or administrator of the selected workspace. A key belonging to a member, manager, or client user receives 403 Forbidden even if that user has elevated permissions in another workspace.
Create and revoke keys under Settings -> API & Developers. See Authentication for setup and security guidance.
1. Get the Backup Manifest
GET /api/v2/backup
The manifest describes the backup contract, identifies the selected workspace, and gives the current count and first-page endpoint for each resource.
curl --fail --silent --show-error \
"https://app.keito.ai/api/v2/backup" \
-H "Authorization: Bearer $KEITO_API_KEY" \
-H "Keito-Account-Id: $KEITO_ACCOUNT_ID"
Example response:
{
"backup_schema_version": 1,
"generated_at": "2026-08-07T09:30:00.000Z",
"workspace": {
"id": "workspace_id_here",
"name": "Example Workspace"
},
"resources": [
{
"name": "time_entries",
"description": "Time entries, including approval, billing, timer, and source metadata",
"total_entries": 2480,
"endpoint": "/api/v2/backup/time_entries?page=1&per_page=100"
}
],
"excluded": [
"authentication credentials, sessions, API keys, and access tokens"
],
"notes": [
"Download every page of every resource for a complete portable workspace backup."
]
}
Store the manifest with the downloaded data. backup_schema_version identifies the shape of the backup contract and should be checked before processing records.
2. Download Resource Pages
GET /api/v2/backup/:resource
Path Parameter
| Parameter | Type | Required | Description |
|---|---|---|---|
resource |
string | Yes | One of the resource names returned by the manifest |
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
page |
integer | No | 1 |
Page number, starting at 1 |
per_page |
integer | No | 100 |
Parent records per page, from 1 to 500 |
Backup pages are capped at 500 parent records because resources such as invoices, projects, and members can contain nested records.
curl --fail --silent --show-error \
"https://app.keito.ai/api/v2/backup/time_entries?page=1&per_page=500" \
-H "Authorization: Bearer $KEITO_API_KEY" \
-H "Keito-Account-Id: $KEITO_ACCOUNT_ID"
Example response shape:
{
"backup_schema_version": 1,
"resource": "time_entries",
"records": [
{
"id": "time_entry_id_here",
"user_id": "user_id_here",
"project_id": "project_id_here",
"task_id": "task_id_here",
"spent_date": "2026-08-06T00:00:00.000Z",
"hours": "7.5",
"billable": true
}
],
"per_page": 500,
"total_pages": 5,
"total_entries": 2480,
"page": 1,
"links": {
"first": "/api/v2/backup/time_entries?page=1&per_page=500",
"next": "/api/v2/backup/time_entries?page=2&per_page=500",
"previous": null,
"last": "/api/v2/backup/time_entries?page=5&per_page=500"
}
}
Follow links.next until it is null. Links are relative to https://app.keito.ai and must be requested with the same authorization and account headers.
All record keys use snake_case. Dates and timestamps use ISO 8601 strings. Decimal and bigint fields are JSON strings so hours, rates, money, and imported identifiers do not lose precision. Resource-specific records may contain nested arrays; preserve fields you do not currently consume so a backup remains useful as the schema evolves.
Available Resources
The manifest is the source of truth for the resources available in its schema version.
| Resource | Included data |
|---|---|
workspace |
Portable workspace settings and feature configuration |
members |
Members, permissions, roles, rates, and notification preferences |
roles |
Custom reporting roles and member assignments |
teammate_assignments |
Manager-to-teammate reporting relationships |
clients |
Clients and nested contacts |
projects |
Projects, project members, rates, and task assignments |
tasks |
Workspace and project-scoped tasks |
time_entries |
Time, approval, billing, timer, source, and reference metadata |
expense_categories |
Expense category configuration |
expenses |
Expenses and authenticated receipt links |
invoice_settings |
Invoice and estimate document settings |
bank_accounts |
Bank accounts shown on invoice documents |
invoice_item_categories |
Invoice item categories |
invoices |
Invoices, line items, payments, messages, attachments, and receipt copies |
estimates |
Estimates, line items, and message history |
retainers |
Retainers and retainer activity |
recurring_invoices |
Schedules, templates, generated invoice IDs, and project links |
planning_assignments |
Planning assignments, including soft-deleted assignments |
planning_placeholders |
Planning placeholder records |
planning_time_off |
Planning time-off records |
planning_working_patterns |
Planning working patterns |
saved_reports |
Saved reports and sharing assignments |
invitations |
Pending and historical invitations, without invitation tokens |
webhook_endpoints |
Webhook configuration, without signing secrets or delivery history |
audit_logs |
Workspace audit log entries |
3. Download Receipts and Attachments
File bytes are not embedded in resource JSON.
- Expense records with a receipt contain
receipt_download_url, using/api/v2/expenses/:expense_id/receipt. - Invoice attachment records contain
download_url, using/api/v2/invoices/:invoice_id/attachments/:attachment_id/download. - Invoice expense-receipt copies contain
download_url, using/api/v2/backup/files/invoice_expense_receipts/:id.
Request each URL with the same Authorization and Keito-Account-Id headers. The response contains the original file bytes and content type rather than JSON.
curl --fail --silent --show-error \
"https://app.keito.ai/api/v2/backup/files/invoice_expense_receipts/receipt_id_here" \
-H "Authorization: Bearer $KEITO_API_KEY" \
-H "Keito-Account-Id: $KEITO_ACCOUNT_ID" \
--output receipt.pdf
Creating a Complete Backup
For each scheduled backup:
- Create a new timestamped directory in encrypted storage.
- Download and retain the manifest.
- For every manifest resource, download page 1 and follow
links.nextthrough the final page. - Download every receipt and attachment URL present in the records.
- Confirm that the sum of downloaded parent records matches the resource count you observed.
- Encrypt the backup, restrict access, and test that your process can read it before applying retention rules.
Respect 429 Too Many Requests responses and wait for the number of seconds in the Retry-After header before continuing.
Consistency and Restore Limits
A backup crawl uses multiple API requests. It is not a point-in-time database snapshot, so records can change between pages. Run backups during a quiet period and avoid large workspace changes while a crawl is in progress. Periodic full backups are recommended because deleted records cannot be reconstructed by a later incremental download.
This API creates a portable customer-controlled export, not a database dump. There is currently no public bulk-restore/import endpoint for these files. Keep record IDs and relationships intact and contact Keito support if you need help recovering data from a backup.
Excluded Data
The API deliberately excludes authentication credentials, passwords, sessions, API keys, access and refresh tokens, webhook signing secrets, encrypted integration credentials, storage keys, payment processor identifiers, subscription/platform billing state, queues, caches, background jobs, and internal delivery logs.
Financial data, bank-account display details, billing rates, cost rates, member email addresses, notes, and audit activity are included because this is an explicit administrator-level backup. Store backup files with the same care as production business data.
Errors
| Status | Meaning |
|---|---|
401 Unauthorized |
The API key or token is missing or invalid |
403 Forbidden |
The selected workspace membership is not owner or administrator |
404 Not Found |
The resource name, file record, or file does not exist in the selected workspace |
429 Too Many Requests |
The API rate limit was reached; use Retry-After before retrying |
500 Internal Server Error |
Keito could not generate the requested backup page or file |
Error responses use the normal API v2 format described in Error Handling.