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:

  1. Create a new timestamped directory in encrypted storage.
  2. Download and retain the manifest.
  3. For every manifest resource, download page 1 and follow links.next through the final page.
  4. Download every receipt and attachment URL present in the records.
  5. Confirm that the sum of downloaded parent records matches the resource count you observed.
  6. 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.