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

# Collect API

> Review the Collect API endpoints the Foil browser SDK uses to open transport sessions, stream encrypted observation batches, and mint sealed handoffs.

These endpoints power the protocol that `t.js` and the iOS and Android SDKs use. In most integrations, you should not call them directly from application code. They live under `/v2/collect/`, separately from the `/v1/` REST API.

<Note>
  The request bodies for batch and result endpoints use encrypted binary payloads and session-bound integrity checks. The supported public integration surface is the browser SDK, not manual construction of these transport messages.
</Note>

## Endpoint summary

| Method | Path | Purpose |
| - | - | - |
| `GET` | `/v2/collect/pings/:pingId` | Round-trip timing probe used during session setup |
| `POST` | `/v2/collect/sessions` | Create or resume an encrypted unified browser session and document |
| `POST` | `/v2/collect/sessions/:sessionId/documents/:documentId/batches` | Submit encrypted snapshot or behavioral batches |
| `POST` | `/v2/collect/sessions/:sessionId/documents/:documentId/results` | Mint a sealed session handoff for the current unified session state |
| `POST` | `/v2/collect/network-checks` | Compare HTTP and WebSocket network identity |

## `GET /v2/collect/pings/:pingId`

Used for timing measurement during session setup.

* Authentication: none
* Path parameter: `pingId`
* Response: `204 No Content`

## `POST /v2/collect/sessions`

Creates or resumes a short-lived unified session and creates a document for the current page lifecycle.

* Authentication: `Authorization: Bearer pk_*`
* Content type: JSON

Example response:

```json theme={"dark"}
{
  "sessionId": "sid_7m2k9x4v8q1n5t3w6r0p2c4y8h",
  "documentId": "doc_4h8y2c6p0r3w7n1t5m9k2x6v8q",
  "resumeToken": "eyJ...",
  "continuityScope": "4f7m2k9x8q1n5t3w",
  "sharedPostVersion": 1,
  "resumed": false,
  "challenge": "d7b3...",
  "serverPublicKey": "BGrH...",
  "nonce": "6e18...",
  "timingNonce": "4f95b4f4cafe1d44",
  "canvasChallenge": {
    "ops": [],
    "width": 1,
    "height": 1
  }
}
```

| Field | Meaning |
| - | - |
| `sessionId` | The session ID. |
| `documentId` | The ID of the document created for the current page lifecycle. |
| `resumeToken` | The token the client presents to resume the session on a later page. |
| `continuityScope` | An organization-stable namespace that the browser bundle uses for its continuity carriers. |
| `sharedPostVersion` | The version of the shared session URL that batches and results use. |
| `resumed` | `true` when the call resumed an existing session, and `false` when it created one. |
| `challenge`, `serverPublicKey`, `nonce`, `timingNonce`, `canvasChallenge` | Setup material for the encrypted transport, the timing probe, and the text-measurement challenge. In real responses, `canvasChallenge.ops` lists the fonts and text to measure. |
| `probe` | Optional. A network probe plan. It appears only when the call created a new session and your organization has the network probe enabled. |

Implementation notes:

* The default server sets an HTTP-only `__Host-sid` cookie on this call.
* A session can span page lifecycles; each creation response identifies the new active document.
* Treat `sessionId` as an opaque identifier. New sessions use the `sid_...` format, while legacy hex IDs are still accepted.
* Native publishable keys are accepted on this endpoint only from the matching iOS or Android SDK. See [Authentication](/docs/api-reference/authentication#native-publishable-keys).

## `POST /v2/collect/sessions/:sessionId/documents/:documentId/batches`

Submits encrypted observation batches for the current session.

* Authentication: `Authorization: Bearer pk_*`
* Required headers:
  * `X-Client-Key`
  * `X-Batch-Seq`
  * `Content-Type: application/octet-stream`

Example response:

```json theme={"dark"}
{
  "ack": true,
  "nonce": "d014...",
  "seq": 3,
  "fingerprint": {
    "ready": true,
    "timestamp": 1710000000000,
    "sessionId": "sid_7m2k9x4v8q1n5t3w6r0p2c4y8h",
    "state": {
      "id": "1.0123456789abcdefghjkmnpqrs..."
    },
    "integrity": {
      "responseHmac": "4f1a..."
    }
  },
  "next": {
    "intervalMs": 1000
  }
}
```

For the first snapshot batch, the response also includes the fingerprint-ready payload shown above under `fingerprint`.

Possible failure cases include invalid sequence numbers (`session.sequence_mismatch`), invalid sessions (`session.invalid_or_expired`), and `transport.session_reset_required`. The last is a `409` with `retryable` set to `true`, and the client recovers by starting a new session.

Example transport error:

```json theme={"dark"}
{
  "error": {
    "code": "request.invalid_content_type",
    "message": "Invalid Content-Type. Observe batch requests must use application/octet-stream. Received \"application/json\" instead.",
    "status": 415,
    "retryable": false,
    "request_id": "req_0123456789abcdef0123456789abcdef",
    "docs_url": "https://usefoil.com/docs/api-reference/introduction",
    "details": {
      "fields": [
        {
          "name": "Content-Type",
          "issue": "invalid_value",
          "expected": "application/octet-stream",
          "received": "application/json"
        }
      ]
    }
  }
}
```

## `POST /v2/collect/sessions/:sessionId/documents/:documentId/results`

Requests a fresh sealed handoff for the accumulated session data.

* Authentication: `Authorization: Bearer pk_*`
* Required headers:
  * `X-Client-Key`
  * `Content-Type: application/octet-stream`

Responses include:

```json theme={"dark"}
{
  "sessionId": "sid_7m2k9x4v8q1n5t3w6r0p2c4y8h",
  "sealedToken": "AQAA...",
  "nonce": "4c6f...",
  "integrity": {
    "responseHmac": "4f1a..."
  }
}
```

The public browser transport never returns verdicts, scores, phases, categories, or visitor IDs. Verify the sealed token locally on your backend or use `GET /v1/sessions/:sessionId` as the secondary integration method.

## `POST /v2/collect/network-checks`

Compares the HTTP request path with the WebSocket probe path used during VPN and proxy detection.

* Authentication: none
* Content type: JSON


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.