{/* Metadata lives in ./layout.tsx */}

# Collect (pixel)

The collect endpoint receives storefront events from the Pluto pixel so orders can be attributed to channels. Events never carry money: revenue comes from your order sync, the pixel only provides the join. {{ className: 'lead' }}

Most integrations should not call this endpoint directly. Use the SDK below, or the script tag from the dashboard.

---

## Authentication

Collect uses a **pixel token** (`pt_plp_` + 64 hex), created at **app.plutoprofit.com/developers**. It is safe to embed in a public page: the token can only append events. It cannot read anything, and it structurally cannot reach any other endpoint, including MCP.

Send it as a bearer header, or as `token` in the body (the header wins if both are present).

---

## POST /v1/collect

<Row>
 <Col>

Batch of 1 to 20 events, at most 64 KB per request. The body is JSON but may be sent as `text/plain` so browsers skip the CORS preflight.

The response is **204 with no body** whenever the request is valid, even if individual events were dropped. Request errors only: 401 (bad token), 400 (malformed body), 413 (too large). Append `?debug=1` during development to get per-event verdicts instead (heavily rate limited).

Event types: `page_view`, `product_view`, `add_to_cart`, `begin_checkout`, `purchase`, `identify`.

Send the raw `url` and `referrer` as-is. The server extracts click IDs and UTM parameters and strips PII query params; clients that pre-clean URLs lose attribution.

`consent` is `"analytics"` or `"analytics+marketing"`. Events without consent must not be sent at all.

 </Col>
 <Col sticky>

 <CodeGroup title="Request">

```sh {{ title: 'curl' }}
curl https://api.plutoprofit.com/v1/collect \
  -H "Content-Type: text/plain;charset=UTF-8" \
  -d '{
    "token": "pt_plp_your_token",
    "events": [{
      "event_id": "9f2c9e1e-8b3a-4d6e-9c1f-2a7b8c9d0e1f",
      "type": "purchase",
      "ts": "2026-07-15T12:00:00.000Z",
      "anon_id": "5e0a7a1c-...",
      "session_hint": "s-...",
      "url": "https://shop.example/thanks?gclid=Cj0K...",
      "referrer": "https://www.google.com/",
      "consent": "analytics+marketing",
      "order_id": "10052",
      "checkout_token": "abc123",
      "sdk": "js-0.1.0",
      "shopify_client_id": ""
    }]
  }'
```

 </CodeGroup>

 </Col>
</Row>

---

## SDK: @plutoprofit/connect

<Row>
 <Col>

One engine, two deliveries.

**Script tag** for themed storefronts: add it once, it auto-initializes from `data-token` and tracks page views, SPA route changes, and consent automatically. Calls made before the script loads are queued by the standard stub.

**npm** for headless storefronts (Hydrogen, Next.js): same engine, typed API.

The SDK is consent-first by construction. Nothing is stored and nothing is sent until consent exists. It reads Shopify `customerPrivacy` and Cookiebot automatically; wire any other CMP through the explicit consent call. With no readable signal it defaults to deny inside the EEA, UK, and Switzerland, and allow elsewhere. Withdrawal deletes stored identifiers immediately.

`identify` hashes the email in the browser (SHA-256 of the trimmed, lowercased address). The raw address never leaves the page. It requires marketing consent; without it the call is dropped.

The script build has a CI-enforced 5 KB gzip budget and transport is fire-and-forget: a lost pageview is acceptable, a slowed storefront is not.

 </Col>
 <Col sticky>

 <CodeGroup title="Install">

```html {{ title: 'Script tag' }}
<script async
  src="https://px.plutoprofit.com/v1/plutoprofit.js"
  data-token="pt_plp_your_token"></script>
```

```ts {{ title: 'npm' }}
import { createPluto } from "@plutoprofit/connect";

const pluto = createPluto({ token: "pt_plp_your_token" });
pluto.start(); // consent adapters + first page view

pluto.purchase("10052", "checkout_token");
await pluto.identify({ email }); // hashed client-side
```

```js {{ title: 'Global' }}
plutoprofit('consent', { analytics: true, marketing: true });
plutoprofit('track', 'add_to_cart', { productId: '88' });
plutoprofit('purchase', '10052', 'checkout_token');
```

 </CodeGroup>

 </Col>
</Row>
