Integration guide

Agent Attribution

Tell Pickrate when an AI agent drove a visitor who later converted — which agent, tied to the hard signals, connected to your Pick Rate. This is the bottom of your Agent Funnel.

The model: three events, one join

Attribution is three events that chain through a visitor and an identity:

touch(visitorToken)  →  identify(visitorToken → user)  →  convert(user)

First touch wins: the earliest touch we can tie to the converting identity gets the credit.

1. Get a key

Mint keys in Settings → Agent Attribution keys (you'll need a verified company claim). Two kinds:

2. Install the SDK

npm i @pickrate/attribution

Node 18+ (uses global fetch). Zero dependencies.

import { createClient } from "@pickrate/attribution";

const pr = createClient({ secretKey: process.env.PICKRATE_SECRET_KEY });

// An agent-adjacent touch (server-side). Pass whatever signals you have.
await pr.touch({
  visitorToken: cookies.pr_vt,           // your first-party browser id
  signals: { via: "mcp", agent: "Claude", referrer: req.headers.referer },
});

// When the human signs in, bind the anonymous visitor to a stable identity.
await pr.identify({ visitorToken: cookies.pr_vt, email: user.email });

// The conversion.
await pr.convert({ email: user.email, kind: "signup", value: 0 });

Identity

Send email and we hash it on ingest — the raw email is never stored. Or send your own opaque userRef (a stable user id). Either works; email-hash is the default. If you'd rather hash yourself, send a userRef you've already prefixed (eh:<sha256>). Sending your own userRef is what makes every exported row join 1:1 to your user table.

3. Browser helper (optional)

For client-side funnels, drop the hosted helper on your pages with a publishable key:

<script src="https://pickrate.io/pr.js" data-key="pk_live_…" async></script>

It mints a first-party pr_vt visitor cookie, fires a touch automatically when a visitor lands with a ?via= tag or an AI referrer, and exposes:

// Bridge the anonymous visitor to a known user the moment they sign in.
window.pickrate.identify("user@acme.com");   // or { userRef: "your-user-id" }
window.pickrate.touch({ via: "mcp" });       // record a touch manually

A publishable key can only send touch / identify — the convert money event is server-side only. That keeps a key that ships in your HTML from forging revenue.

Raw HTTP

The SDK is sugar over one endpoint. Any language can speak it:

POST https://pickrate.io/api/collect
Authorization: Bearer sk_live_…
Content-Type: application/json

{ "type": "convert", "email": "user@acme.com", "kind": "signup", "value": 0 }

Send a single event, an array, or { "events": [ … ] } (max 100 per request). Response: { "accepted": 1, "rejected": 0 }. A publishable key that tries to send convert is rejected.

Get your data out

Attribution is most useful next to your existing data. Two ways out, both keyed to the identity you sent.

Webhook (push)

Register a destination in Settings and we POST each attributed conversion the moment it resolves:

{
  "type": "attribution.convert",
  "tenant": "your-slug",
  "userRef": "id:cust-777",
  "kind": "paid",
  "convertedAt": "2026-06-28T09:02:00.000Z",
  "value": 150,
  "channel": "agent",
  "confidence": "confirmed",
  "agent": "ChatGPT",
  "firstTouchAt": "2026-06-28T09:00:00.000Z"
}

Every request carries X-Pickrate-Signature: sha256=<hmac>. Verify it with your signing secret:

import { createHmac, timingSafeEqual } from "crypto";

function verify(rawBody, header, secret) {
  const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
  return timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}

Point it anywhere — your backend, a queue, or a Zapier/Make webhook to fan it into other tools.

Export API (pull)

GET https://pickrate.io/api/attribution/export?type=attributions&format=csv
Authorization: Bearer sk_live_…

Secret key only. Built for warehouse loads, reverse-ETL, and BI.

Confidence & honesty

Every conversion is labeled by how sure we are an agent drove it. We lead with what we can prove:

A cold server-side agent read with no link and no token can't be tied to a later human — that edge is dropped, not guessed.

Questions

Do you store my users' email addresses?

No. Send an email and we hash it (SHA-256) at ingest — the raw email is never stored. Or send your own opaque userRef instead. Either works; email-hash is the default.

How is this different from GA4 or a brand-monitoring tool?

GA4's new AI channel and brand tools tell you an AI assistant referred a session. We tie a specific agent to a specific conversion through a deterministic link or identity bridge, label it by confidence, and connect it to your Pick Rate — selection and revenue in one place.

What's the difference between a publishable and a secret key?

A secret key (sk_) is server-side and can send every event, including the convert money event. A publishable key (pk_) ships in your browser HTML and can only send touch and identify — never convert — so a key that's visible in your page source can't forge revenue.

What happens to a touch that never connects to a person?

It's dropped, not guessed. A cold server-side agent read with no link and no identity bridge can't honestly be tied to a later human, so we don't. We only credit conversions we can actually walk back to a first touch.

Can I get the data into my warehouse?

Yes — two ways, both keyed to the identity you sent. A signed webhook pushes each attributed conversion as it resolves, and the export API pulls JSON or CSV for warehouse loads, reverse-ETL, and BI.

← All docs · Pick Rate API →