# Polar

Attribute Polar orders created through the Checkout API.

## 1. Connect Polar

1. In VisitTrack, open **Settings → Revenue** and pick **Polar**.
2. Copy the webhook URL shown there. It looks like `https://visitrack.app/api/polar-webhook/YOUR_SITE_ID`.
3. In Polar: Settings → Webhooks → **Add endpoint**. Paste the URL and subscribe to `order.paid` and `refund.created`.
4. Copy the webhook secret Polar gives you back into VisitTrack and press **Connect**. It's stored encrypted and only used to verify signatures.

## 2. Pass the visitor id

Put it in the checkout's `metadata`. Polar copies checkout metadata onto the order it creates.

Node.js:
```
import { Polar } from "@polar-sh/sdk";

const polar = new Polar({ accessToken: process.env.POLAR_ACCESS_TOKEN });

const checkout = await polar.checkouts.create({
  products: [productId],
  successUrl: "https://example.com/thanks?checkout_id={CHECKOUT_ID}",
  metadata: { visitrack_visitor_id: visitorId ?? "" },
});

return Response.json({ url: checkout.url });
```

cURL:
```
curl -X POST https://api.polar.sh/v1/checkouts/ \
  -H "Authorization: Bearer $POLAR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "products": ["PRODUCT_ID"],
    "metadata": { "visitrack_visitor_id": "VISITOR_ID" }
  }'
```

> **Fallback: customer external id** — If the order carries no metadata, VisitTrack falls back to the customer's `external_id`. That only helps if you create Polar customers with the visitor id as their external id. Most apps use their own user id there, so prefer metadata.

## Events

| Event | What VisitTrack does |
| --- | --- |
| `order.paid` | Records the order (`total_amount`, `currency`, customer email) against the visitor in `metadata.visitrack_visitor_id`. |
| `order.created` | Also recorded, but only when the order is already paid. |
| `refund.created` | Subtracts the refunded amount from the original order. |
| anything else | Acknowledged with `200` and ignored. |

Signatures follow the Standard Webhooks spec. Deliveries more than 5 minutes old are rejected.

## Test it

1. Open your site in a normal browser tab so the tracker records a visit (localhost is ignored unless the script tag has `data-allow-local`).
2. Complete a checkout in test mode.
3. Open **Revenue** in the dashboard. The payment shows up within a few seconds, with the referrer, campaign and landing page that brought that visitor in.

> **Nothing showed up?** — See [Missing or unattributed payments](https://visitrack.app/docs/revenue-troubleshooting). The webhook response body always says why a payment was skipped.
