> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sovseal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# POST /snapshot: Upload Encrypted State Checkpoint

> Upload a base64-encoded AES-256-GCM encrypted state checkpoint for your agent, with sequence enforcement, billing debit, and storage confirmation.

<style>
  {`
      main, article, .prose {
        margin-left: 2.5cm !important;
        margin-right: 2.5cm !important;
      }
      `}
</style>

The `POST /snapshot` endpoint accepts a fully encrypted agent state checkpoint and registers it as the canonical latest sequence in the replication log. You submit the ciphertext blob, its metadata, and a monotonic sequence number; the server validates the sequence chain, handles billing, uploads the ciphertext to object storage, and returns a confirmed transaction receipt. The server never decrypts or inspects the payload.

## Request

```http theme={null}
POST /snapshot
Authorization: Bearer <TOKEN>
Content-Type: application/json
```

## Request Body

<ParamField body="agent_id" type="string" required>
  An identifier for the agent, chosen and supplied by you — the server does not derive or validate its format beyond treating it as an opaque string. A common convention is `sha256(project_id + ":" + some_stable_identifier)`.
</ParamField>

<ParamField body="sequence_number" type="integer" required>
  Monotonically increasing checkpoint index. Must start at `0` for the genesis snapshot and increment by exactly `1` for each subsequent write.
</ParamField>

<ParamField body="parent_snapshot" type="string | null" required>
  The `storage_path` of the immediately preceding snapshot. Must be `null` when `sequence_number` is `0`. Required and non-null for all subsequent sequences.
</ParamField>

<ParamField body="policy_hash" type="string" required>
  64-character SHA-256 hex hash of the security policy. Until policy enforcement is active, use 64 zero characters: `0000000000000000000000000000000000000000000000000000000000000000`.
</ParamField>

<ParamField body="client_payload_hash" type="string" required>
  64-character SHA-256 hex hash of the canonicalized payload. Used for Verified Semantic Recall integrity checks and idempotent retry detection.
</ParamField>

<ParamField body="ciphertext_b64" type="string" required>
  Base64-encoded binary ciphertext in the packed `IV || ciphertext || auth_tag` format produced by AES-256-GCM.
</ParamField>

<ParamField body="byte_size" type="integer" required>
  Byte length of the decoded ciphertext. Must be greater than `0` and no larger than `262,144` (256 KB, `MAX_PAYLOAD_BYTES`).
</ParamField>

<ParamField body="timestamp" type="string" required>
  ISO-8601 timestamp generated by the client at the time of snapshot creation.
</ParamField>

### Example Request Body

```json theme={null}
{
  "agent_id": "4e73b22cf900d744b827e8d7d3d1597f8c159048b65429384f9b4f3b7d1597f8",
  "sequence_number": 0,
  "parent_snapshot": null,
  "policy_hash": "0000000000000000000000000000000000000000000000000000000000000000",
  "client_payload_hash": "84c8a8d11d95e0cce8da70c1a96c14b7454f738f65429384f9b4f3b7d1597f8c",
  "ciphertext_b64": "YmFzZTY0X2NpcGhlcnRleHRfZXhhbXBsZV93aXRoX2l2X2FuZF9hdXRoX3RhZw==",
  "byte_size": 42,
  "timestamp": "2026-06-09T16:45:30.000Z"
}
```

## Processing Flow

<Steps>
  <Step title="JSON & Structural Validation">
    The server verifies that the request body is valid JSON and that all required fields are present and correctly typed.
  </Step>

  <Step title="Sequence Constraints">
    Sequence `0` requires `parent_snapshot` to be `null`. Any sequence greater than `0` requires a non-null `parent_snapshot`. The submitted sequence number must be exactly `latest + 1` — gaps in the sequence chain are rejected with `409 sequence_gap`.
  </Step>

  <Step title="Idempotent Retry Detection">
    If the submitted sequence number matches the current latest sequence and the `client_payload_hash` is identical, the endpoint returns the previously confirmed receipt immediately without re-debiting credits or re-uploading storage.
  </Step>

  <Step title="Billing Debit">
    For paid `sov_live_` keys, the server calculates a debit based on `byte_size` and performs an atomic credit debit. If the balance is insufficient, the request fails with `402 insufficient_credits`.
  </Step>

  <Step title="Storage Upload">
    The ciphertext is uploaded to the `sovseal-rom` bucket at the path: `{agent_id}/seq-{sequence_number}-{client_payload_hash[0:12]}.bin`.
  </Step>

  <Step title="Confirmation & Response">
    On successful upload, the database record status transitions to `confirmed` and the server returns a receipt. If storage is unreachable, the record status is set to `failed`, the credit debit is refunded, and a `503 storage_unavailable` error is returned.
  </Step>
</Steps>

## Response

### 200 OK

<ResponseField name="snapshot_id" type="string">
  UUID of the newly created snapshot record.
</ResponseField>

<ResponseField name="agent_id" type="string">
  The 64-character agent hash submitted in the request.
</ResponseField>

<ResponseField name="sequence_number" type="integer">
  The confirmed sequence number for this checkpoint.
</ResponseField>

<ResponseField name="storage_path" type="string">
  The storage path (object key) where the ciphertext blob was written.
</ResponseField>

<ResponseField name="byte_size" type="integer">
  Byte size of the confirmed ciphertext as recorded by the server.
</ResponseField>

<ResponseField name="cost_milli" type="integer">
  Credits debited for this operation in milli-cents. `0` for free-tier project tokens.
</ResponseField>

<ResponseField name="client_payload_hash" type="string">
  Echo of the `client_payload_hash` submitted in the request.
</ResponseField>

<ResponseField name="status" type="string">
  Confirmation status. Will be `"confirmed"` on a successful response.
</ResponseField>

<ResponseField name="confirmed_at" type="string">
  ISO-8601 timestamp of when the server confirmed the upload.
</ResponseField>

### Example Response

```json theme={null}
{
  "snapshot_id": "a1b2c3d4-e5f6-7a8b-9c0d-e1f2a3b4c5d6",
  "agent_id": "4e73b22cf900d744b827e8d7d3d1597f8c159048b65429384f9b4f3b7d1597f8",
  "sequence_number": 0,
  "storage_path": "4e73b22cf900d744b827e8d7d3d1597f8c159048b65429384f9b4f3b7d1597f8/seq-0-84c8a8d11d95.bin",
  "byte_size": 42,
  "cost_milli": 0,
  "client_payload_hash": "84c8a8d11d95e0cce8da70c1a96c14b7454f738f65429384f9b4f3b7d1597f8c",
  "status": "confirmed",
  "confirmed_at": "2026-06-09T16:45:31.123Z"
}
```

## curl Example

```bash theme={null}
curl -X POST https://ksrlmubaxzwufziwarps.supabase.co/functions/v1/v2-agent-state/snapshot \
  -H "Authorization: Bearer sov_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "4e73b22cf900d744b827e8d7d3d1597f8c159048b65429384f9b4f3b7d1597f8",
    "sequence_number": 0,
    "parent_snapshot": null,
    "policy_hash": "0000000000000000000000000000000000000000000000000000000000000000",
    "client_payload_hash": "84c8a8d11d95e0cce8da70c1a96c14b7454f738f65429384f9b4f3b7d1597f8c",
    "ciphertext_b64": "YmFzZTY0X2NpcGhlcnRleHRfZXhhbXBsZV93aXRoX2l2X2FuZF9hdXRoX3RhZw==",
    "byte_size": 42,
    "timestamp": "2026-06-09T16:45:30.000Z"
  }'
```
