Skip to content

Polar setup

Keylight integrates with Polar through Standard Webhooks: every paid order, subscription state change, and successful refund hits Keylight, and Keylight mints, renews, or refunds the matching license. There’s no OAuth and no outbound Polar API call from Keylight — only the signed webhook with a shared HMAC secret.

From your dashboard, go to Settings → Integrations → Polar and click Enable Polar. Keylight reveals the webhook URL:

https://api.keylight.dev/webhooks/polar/<your-tenant-id>

Copy it — you’ll paste it into Polar’s webhook settings in step 3.

In Settings → Integrations → Polar, add one row per product.

Polar Product IDKeylight appKey type
prod_abc…myapppro
prod_xyz…myappteam

Keylight reads data.productId from each event to pick the row. Unmapped products are rejected with 400 unmapped_product instead of being minted against an unknown app.

In the Polar dashboard:

  1. Go to Settings → Webhooks → Add Endpoint.
  2. Paste the Keylight URL from step 1 into URL.
  3. Set Format to Raw.
  4. Subscribe to these events:
    • order.created
    • order.refunded (deliberately skip — Polar fires both this and refund.created; Keylight only acts on the latter to avoid double-counting)
    • subscription.created
    • subscription.updated
    • subscription.active
    • subscription.canceled
    • subscription.revoked
    • refund.created
  5. Save. Polar reveals the signing secret (it starts with whsec_…) — copy the entire string including the prefix.

Back in Keylight (Settings → Integrations → Polar), paste the secret into Webhook signing secret and save.

Polar’s webhook page has a Send test event action.

  • A 200 OK from Keylight with a fresh license record in Dashboard → Licenses means signature + product map are correct.
  • 400 invalid_signature → either the secret is wrong, or the webhook-id / webhook-timestamp headers were stripped by a proxy in front of Keylight.
  • 400 unmapped_product → the test event’s Product ID isn’t in your map.

When a customer checks out, Polar fires order.created with data.status === 'paid'. Keylight verifies the Standard Webhooks signature, looks up the app+key-type from data.productId, mints a license, and records the payment. Subscription renewals arrive as subscription.updated with data.status === 'active' and re-extend the license. subscription.canceled and subscription.revoked flip it to cancelled. A successful refund.created (where data.status === 'succeeded') flips the license to refunded.

To send a customer to a Polar checkout that upgrades their existing license, append customer_metadata[keylight_upgrade_key]=<license-key> to the Upgrade checkout URL you set on the key type. Polar echoes the metadata back in the order event and Keylight links the new order to the existing license.

Settings → Integrations → Polar → Disconnect clears the signing secret and the product map. Existing licenses are untouched — only new webhook deliveries stop minting.