---
title: "Create Workspace Restore Api"
method: POST
path: "/workspace/restore"
tags: ["Workspace backup"]
---

# Create Workspace Restore Api

`POST /workspace/restore`

## Request

- Base URL: `https://be.graph8.com/api/v1`
- URL: `https://be.graph8.com/api/v1/workspace/restore`
- Auth: HTTP bearer

Restore a completed backup of this workspace as this key (its write grants apply): a dry run unless
``dry_run`` is false.

## Headers

- `Authorization` string, nullable
- `X-Target-Org-Id` string, nullable

## Request body

- RestoreCreate: Restore one completed backup of THIS workspace, by id. A record or report that is missing is added; one that exists is UPDATED to the backup's values where they differ, through the same checks as an edit (an archived record the backup holds live is unarchived). Objects, fields, relationships, process lists, grants and links are only added. Nothing that exists is ever deleted or archived. ``dry_run`` defaults to true: every step and check runs and is rolled back, and the counts say exactly what a restore would add, update and leave unchanged. A real restore must send ``dry_run: false``.
  - `backup_id` string, uuid, required
  - `dry_run` boolean: True (the default) writes nothing; send false to restore.

## Response `202`

Successful Response

- ApiResponseRestoreJobResponse
  - `data` RestoreJobResponse, required
    - `id` string, uuid, required
    - `backup_id` string, uuid, nullable
    - `status` 'pending' | 'running' | 'completed' | 'failed' | 'expired', required
    - `dry_run` boolean, required
    - `scope` 'complete' | 'restricted', nullable
    - `counts` object: Per archive section. A dry run's counts are what the restore would do now.
    - `conflicts` RestoreConflict[]: One page of the receipt.
      - `section` string, required
      - `id` string, nullable
      - `code` string, required
      - `field` string, nullable
      - `why` string
      - `fix` string
    - `conflict_count` integer
    - `conflict_offset` integer
    - `conflicts_truncated` boolean: More conflicts happened than the receipt keeps (the first 5,000); conflict_count is exact.
    - `error_code` string, nullable
    - `created_at` string, date-time, required
    - `started_at` string, date-time, nullable
    - `completed_at` string, date-time, nullable
    - `heartbeat_at` string, date-time, nullable: The run's last sign of life; while running, ``counts`` are its progress at that moment.
    - `totals` SectionCounts: What a restore did (or, for a dry run, would do) with one archive section. Every row of the section is counted exactly once: ``created + updated + unchanged + conflicts + skipped`` is the section's rows in the backup.
      - `created` integer: Not in the workspace by id: added.
      - `updated` integer: In the workspace by id with other values: written back to the backup's values (records and reports only; every other section is only added, so this stays 0 there).
      - `unchanged` integer: In the workspace by id and left exactly as it is: it already holds the backup's values, or its section is only added.
      - `conflicts` integer
      - `skipped` integer: Not restored by design (e.g. schema from a restricted archive).
    - `requested_by` BackupRequester: Who asked. ``name`` and ``kind`` are shown to a workspace administrator only (anyone else lists only their own jobs and reads ``is_you``); ``name`` is the member's display name, None for an API key or an unknown member.
      - `is_you` boolean, required
      - `name` string, nullable
      - `kind` 'member' | 'api_key', nullable
    - `note` string: What a restore adds, updates and never touches, in one sentence.
  - `pagination` PaginationMeta
    - `page` integer, required: Current page number (1-indexed)
    - `limit` integer, required: Items per page
    - `total` integer, required: Total number of items
    - `has_next` boolean, required: Whether there are more pages
    - `next_cursor` string, nullable: Opaque cursor for the next page; null when there are no more items. Pass it back as the `cursor` query param to fetch the following page without computing page numbers.
    - `total_available` integer, nullable: Search endpoints only: how many records really match, when known. Can be larger than `total`, which is capped at the 10,000 results that can be paged. For company search this is a distinct-company estimate. Null when unknown; absent outside search.
    - `total_is_lower_bound` boolean, nullable: Search endpoints only: true when more records match than `total` shows (the result set is larger than the 10,000 results that can be paged). Absent outside search.
    - `notes` string[], nullable: Search endpoints only: plain-language notes about the result, e.g. that more records match than can be paged, or that a reversed `between` range was put in order.

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/graph8/apis/graph8-developer-api.md) · [All operations](https://skmtc.dev/graph8/apis/graph8-developer-api/llms.txt) · [OpenAPI document](https://skmtc.dev/graph8/apis/graph8-developer-api/revisions/2e7cfa0ca921?raw)
