
Polar fires webhooks for billing events in your project: subscriptions created, updated, cancelled, orders placed and refunded, customer changes, benefit grants, and more. They're how your application stays in sync with billing without polling Polar's API.
This guide covers what Polar sends, how to verify it (Standard Webhooks-compatible), and what production reliability requires.
What Polar sends
Polar webhooks are JSON POST requests. A subscription.created event:
{
"type": "subscription.created",
"data": {
"id": "sub_01HM3K8N2P9X4ABCD",
"status": "active",
"customer_id": "cus_01HM3K8N2P9X4ABCD",
"product_id": "prod_01HM3K8N2P9X4ABCD",
"price_id": "price_01HM3K8N2P9X4ABCD",
"current_period_start": "2026-04-25T14:30:00Z",
"current_period_end": "2026-05-25T14:30:00Z",
"cancel_at_period_end": false,
"created_at": "2026-04-25T14:30:00Z"
}
}
Headers (Standard Webhooks spec):
webhook-id: msg_2NxV5y...
webhook-timestamp: 1714000000
webhook-signature: v1,abc123...
content-type: application/json
Common Polar event types:
subscription.created,subscription.updated,subscription.canceled,subscription.uncanceledsubscription.active,subscription.revokedorder.created,order.refunded,order.updatedcustomer.created,customer.updated,customer.deletedcustomer.state_changed(subscription state transitions per customer)benefit.created,benefit_grant.created,benefit_grant.updated,benefit_grant.revokedpledge.created,pledge.updated(for funding model)
The data.id is the Polar resource ID — use the Standard Webhooks webhook-id header for idempotency.
Polar's signature scheme (Standard Webhooks)
Polar follows the Standard Webhooks spec. The signature is HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{raw-body}, base64-encoded, prefixed with v1,:
signature = "v1," + base64(hmac_sha256(secret, webhook_id + "." + webhook_timestamp + "." + raw_body))
Verification:
- Read the raw body before any JSON parsing
- Reject if
now - webhook_timestamp > 300seconds (replay protection) - Recompute the signature; the header may contain multiple space-separated values during secret rotation — accept any match
- Compare constant-time
The standardwebhooks and svix libraries handle this for you in every supported language.
Polar's retry policy
Polar retries failed webhooks (non-2xx, or no response within their delivery infrastructure's timeout) with exponential backoff for several hours. Failed deliveries are visible in the Polar dashboard's webhook log.
This means:
- Acknowledge fast — return 2xx in under one second
- Be idempotent on
webhook-id— duplicates will arrive during retries - Have a recovery story — past Polar's window, manual replay from the dashboard is the only built-in fallback (or backfill from the Polar API)
DIY: minimal Polar webhook handler in Node
import { Webhook } from 'standardwebhooks'
const secret = process.env.POLAR_WEBHOOK_SECRET!
export async function POST(req: Request) {
const headers = {
'webhook-id': req.headers.get('webhook-id')!,
'webhook-timestamp': req.headers.get('webhook-timestamp')!,
'webhook-signature': req.headers.get('webhook-signature')!,
}
const body = await req.text()
let event
try {
event = new Webhook(secret).verify(body, headers)
} catch {
return new Response('Bad signature', { status: 400 })
}
// Idempotency on webhook-id
// ...
queueWork(event)
return new Response('ok', { status: 200 })
}
Production needs more:
- A persistence layer for
webhook-ididempotency - A queue for async work
- Replay path for events past Polar's retry window
- Routing —
subscription.*to your entitlements service,order.*to fulfillment,customer.*to the CRM - Strict ordering for subscription event sequences (created → updated → canceled in order)
Hooksbase: receive Polar webhooks without rebuilding the rest
Polar isn't one of Hooksbase's five pre-verified provider packs (Stripe, GitHub, Clerk, Slack, Resend), and Hooksbase does not forward Polar's original Standard Webhooks headers to your destination. If you need Polar signature verification, verify it in a small pre-ingest forwarder, then post the verified raw body to Hooksbase with the bearer ingest secret.
Setup:
- Create a webhook in Hooksbase with your application URL as the destination
- Add your verification forwarder URL to your Polar project's webhook settings
- In the forwarder, verify the Standard Webhooks signature, then POST the same raw body to the Hooksbase ingest URL with
Authorization: Bearer <ingest secret>
You get:
- Acknowledge in milliseconds to Polar regardless of how slow your downstream is
- Idempotency for your destination — every dispatch includes a unique
webhook-idheader you can dedupe on across retries - Retries with exponential backoff to your endpoint after Hooksbase accepts the event
- Strict FIFO ordering if you turn it on (Pro+) — useful for subscription state sequences that must process in order
- Routing rules by event type — send
subscription.createdto provisioning,order.refundedto support escalation,customer.createdto CRM sync - Payload transforms — flatten Polar's structure to the shape your downstream expects
- Deterministic replay — re-run a failed delivery with the same payload bytes while the payload is retained
- Delivery history and DLQ
Common Polar webhook use cases for AI agents
- Provisioning agent —
subscription.createdevents trigger an agent that provisions resources, sends the welcome email, and schedules onboarding tasks - Failed payment recovery agent —
subscription.updatedevents with status changes trigger an agent that runs your dunning playbook (notify, retry, downgrade, win-back) - Refund triage agent —
order.refundedevents trigger an agent that classifies the refund reason and surfaces patterns to the team - Entitlements sync agent —
subscription.activeandsubscription.revokedevents trigger an agent that updates downstream entitlements (feature flags, API quotas, dashboard access) - Benefit grant agent —
benefit_grant.createdevents trigger an agent that delivers the promised benefit (Discord role, GitHub team add, license key dispatch)
Where to go next
- How to receive Stripe webhooks reliably for the other major billing-events provider
- How to receive Clerk webhooks reliably for another Standard Webhooks example
- Verify provider webhooks for the verification model
- How to build an AI agent for the full agent build path
Start free at app.hooksbase.com.
Frequently asked questions
How do you verify a Polar webhook signature?
Polar follows the Standard Webhooks spec. Read the raw body before parsing, compute HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{raw-body}, base64-encode it, and compare constant-time against the v1,-prefixed signature header, rejecting anything with a timestamp older than 300 seconds. The standardwebhooks and svix libraries implement this in every major language, and the header may contain multiple signatures during rotation — a match on any one is valid.
How long does Polar retry a failed webhook?
Polar retries with exponential backoff for several hours when your endpoint returns a non-2xx or does not respond in time, and failed deliveries are visible in the Polar dashboard's webhook log. Past that window your options are manual replay from the dashboard or a backfill from the Polar API.
What events do Polar webhooks fire on?
Billing lifecycle events in your project: subscriptions created, updated, and cancelled, orders placed and refunded, customer changes, and benefit grants. They are how your application stays in sync with billing without polling Polar's API.
What is Hooksbase?
Hooksbase is event infrastructure for AI agents. It ingests events over four channels — HTTP, email, HTML form, and scheduled cron — verifies them, routes them by rule, runs versioned Automations in the event path, and delivers them to HTTP and cloud destinations (AWS SQS, AWS EventBridge, GCP Pub/Sub, and S3-compatible storage) with retries, strict ordering, Standard Webhooks-compatible signing, deterministic replay, and a dead-letter path. It is a hosted service, runs on Cloudflare Workers, is operated at hooksbase.com, and is not affiliated with — and shares no code or ownership with — other similarly named webhook, hook, or tunnelling tools.