In Standalone mode the SDK sends to an HTTP collector you run. This page is what that collector receives and how it should answer. Pathrule Local and Pathrule Cloud speak the same protocol, so nothing here changes when you switch destinations.

## The envelope

The protocol is version 1. The SDK sends one envelope per `POST` as `application/json`; the beacon sent while a page unloads uses `text/plain`. An envelope is at most 32,768 bytes and carries at most 50 items.

| Field | What it is |
| --- | --- |
| `schemaVersion` | The protocol version. |
| `id` | Up to 64 letters, digits, `_` or `-`. The same on every retry, so a collector can store an envelope once. |
| `key` | The project key. Cloud only. |
| `environment` | `development`, `preview` or `production`. |
| `release` | The release identity, up to 120 characters. |
| `connection` | How the SDK is connected. |
| `items` | The signals and declarations in this envelope. |

Each item has `type` (`signal` or `declaration`), `kind` (`error` or `event`), `fingerprint`, `countDelta`, `node` (the code path), `flow`, `label`, `message` and `metadata`. Repeated occurrences are summed into `countDelta`, so a collector counts with it rather than counting items.

## Responses and retries

| Response | What the SDK does |
| --- | --- |
| `2xx` | Delivered. |
| `401`, `403` | Stops sending for good. |
| `408`, `429`, `5xx` | Retries. |
| Any other `4xx` | Drops the batch. |

Retries happen after 1, 5 and 15 minutes, at most 4 attempts, and the SDK keeps at most 20 envelopes waiting. A `Retry-After` header is read as a number of seconds.

## Running your own collector

A collector does three things: authenticate the request, validate the envelope, and store or forward it.

```ts
import { normalizeEnvelope } from "@pathrule/signals/protocol";

// In your POST handler, after checking your own Authorization header:
const envelope = normalizeEnvelope(body, { requireKey: false, bytes: rawBody.length });
```

Pass `requireKey: false` when you authenticate another way, such as the bearer header in the [quickstart](/docs/signals/setup), and pass the raw size so the size limit is enforced. Then:

- Store an envelope once per `id`; retries reuse it.
- Group items by environment, kind and fingerprint, the same way Pathrule does.
- Answer `2xx` as soon as the envelope is safe, and `401` or `403` only when the client should stop.
