Updated: September 30, 2026

Site content export & import

Site Migration
Data Export
Data Import

P1 APIs provides export and import endpoints that let operators migrate sites between environments without requiring database access on either side. Bundles are portable ZIP files containing all site content — branches, documents, version history, and publish state.

What is included

- Content from all workstreams with parent relationships

- All documents (excluding _registry/ which rebuilds automatically)

- For Live workstream: every published version plus the current unpublished version

- For other workstreams: the latest version

- Users list (informational — must be configured manually on target)

What is NOT included

- Collaborative editing history — the editor initialises from the latest snapshot on first open

- Users and agent roles — see requiresSetup in the import response

- Site API tokens — must be regenerated on the target

- Allowed origins — must be configured on the target

Prerequisites

- A sat_ token with read:all scope on the source site

- A sat_ token with write:create scope on the target site

- An empty Target site (no documents, no non-main branches)

Generating a sat_ token

You can generate an access token from the P1 admin, or the P1 API as follows:

1. Authenticate to the P1 backend for the site

2. POST /api/sites/{siteId}/tokens with body: {"name": "migration", "scopes": ["write:create"]}

3. Store the returned token value — it is only shown once

Step 1 — Export from the source site

GET /api/admin/sites/{siteId}/export
Authorization: Bearer sat_<read:all or write:create token>

Response:

{
  "downloadUrl": "https://...",
  "bundleKey": "{siteId}/{timestamp}.zip",
  "bundleSignature": "<hmac-sha256-hex>",
  "exportedAt": "2026-05-28T...",
  "documentCount": 21,
  "branchCount": 5
}

Download the ZIP from downloadUrl and save the bundleSignature — you will need it for the import step.

Step 2 — Import into the target site

POST /api/admin/sites/{targetSiteId}/import
Authorization: Bearer sat_<write:create token>
Content-Type: multipart/form-data

Form fields:

- file: the ZIP bundle downloaded in Step 1

- bundleSignature: the HMAC signature from the export response (strongly recommended)

Response:

{
  "importKey": "import:{siteId}:{exportedAt}",
  "completedPhases": ["site", "branches", "document:home", ...],
  "documentCount": 21,
  "sourceSiteId": "03499be6-...",
  "crossSiteImport": true,
  "requiresSetup": {
    "collaborators": {
      "users": [{"email": "chris@example.com", "role": "admin"}],
      "agents": [{"name": "Zappy AI Assistant", "role": "editor"}]
    }
  }
}

Step 3 — Configure collaborators

The requiresSetup.collaborators field lists every user and agent that had a role on the source site. Add them to the target site manually using the site collaborator management UI or API.

Resuming a failed import

If the import is interrupted, re-run the same POST request with the same ZIP file and bundleSignature. The import tracks progress keyed to the bundle's exportedAt timestamp. Already-completed phases are skipped automatically. The target site does not need to be empty for a resume — only for a first-time import.

Bundle integrity

The bundle contains a SHA-256 manifest (bundle.json) covering every file. The bundleSignature provides an additional HMAC layer: if either the bundle files or bundle.json itself are modified after export, the import will reject the bundle with a 422 Signature verification failed error.

Complete Curl example

# Export
EXPORT=$(curl -s -X GET "https://{P1-API-URL}/api/admin/sites/{siteId}/export" \
  -H "Authorization: Bearer sat_...")

DOWNLOAD_URL=$(echo $EXPORT | jq -r .downloadUrl)
SIGNATURE=$(echo $EXPORT | jq -r .bundleSignature)

curl -o bundle.zip "$DOWNLOAD_URL"

# Import
curl -X POST "https://{P1-API-URL}/api/admin/sites/{targetSiteId}/import" \
  -H "Authorization: Bearer sat_..." \
  -F "file=@bundle.zip" \
  -F "bundleSignature=$SIGNATURE"

Site Migration
Data Export
Data Import