MenuPolar

Revenue attribution

Polar

Connect Polar with an organization access token and a Standard Webhooks endpoint so ProductLense records orders, refunds and the platform fee.

ProductLense reads your Polar customers, subscriptions and orders, including refunds. Polar is a merchant of record. ProductLense only reads: it never writes to your Polar organization, never refunds, cancels or changes anything.

What you need

FieldSecretWhere to find it
Organization access tokenYesSettings → Developers → New token.
Organization IDNoThe UUID shown in Settings → General.
Webhook secretYesThe secret generated when you add the webhook endpoint pointing at ProductLense.

Every plan includes one billing connection per site, Free too; Growth and Scale allow any number. See plans and limits.

Permissions

Create the organization access token with these scopes, all read-only:

  • customers:read
  • subscriptions:read
  • orders:read
  • organizations:read

ProductLense calls GET /v1/organizations/{id}, /v1/customers, /v1/subscriptions and /v1/orders.

Set up

  1. In Polar, open Settings → Developers → New token and select the four read scopes. Copy your organization id from Settings → General.
  2. In ProductLense, open your site's Settings → Billing connections → Polar, paste the token and organization id, and click Connect and import history.
  3. Copy the webhook URL from the connection card.
  4. In Polar, open Settings → Webhooks → Add endpoint, paste the URL and select the events below.
  5. Copy the generated secret into the connection in ProductLense.

Webhook

URL: https://api.productlense.app/api/webhooks/polar/<connection-id> (ProductLense shows the exact URL after you save).

Events ProductLense uses:

  • order.created, order.paid, order.updated, order.refunded
  • subscription.created, subscription.updated, subscription.active, subscription.canceled, subscription.uncanceled, subscription.revoked, subscription.past_due
  • customer.created, customer.updated, customer.state_changed

Verification: Standard Webhooks headers (webhook-id, webhook-timestamp, webhook-signature). Deliveries older than 5 minutes are rejected.

What ProductLense reads

  • Customers: email, name, external id and metadata.
  • Subscriptions: status, interval and amount.
  • Payments: orders, at the amount the customer paid including tax.
  • Refunds: the refunded amount on each order, plus the refunded tax.
  • History: the last 12 months on first connect, then a nightly reconcile at 03:00 UTC from the last sync minus 48 hours.

How fees are derived

The fee is the order's platform_fee_amount when Polar includes it. Older payloads omit it, and those orders are recorded with a fee of 0.

A fee estimate can be set under Processor fees on the connection card (percent, fixed amount per payment, and its currency). It starts at 0 and is applied only to charges that arrive with a zero fee. Estimated fees are flagged, and the dashboard shows the share of fees in a period that is estimated. An estimate is only as accurate as the rate you enter.

Match payments to visitors

ProductLense uses the Polar customer's external id as the user id. When it is empty, ProductLense reads the customer metadata keys pl_user_id, user_id, userId or uid. Use the same id you pass to identify. A ProductLense visitor id in pl_visitor_id or visitor_id is also accepted. Without either, ProductLense falls back to the customer email, matched to the email trait sent with identify, or to a user id that is that email.

Polar checkout (Node SDK)
const checkout = await polar.checkouts.create({
  products: ['PRODUCT_ID'],
  externalCustomerId: user.id,
  customerEmail: user.email,
});

See how payments are attributed.

    ↑ ↓ to move, Enter to open