Overview
Webhooks allow you to receive HTTP notifications when events occur in your Polar account, such as completed checkouts, new subscriptions, or updated orders.
The Webhook Endpoint Object
Webhook URL to receive events
Secret for verifying webhook signatures
Array of event types to receive
List Webhook Endpoints
curl -X GET "https://api.polar.sh/v1/webhooks/endpoints" \
-H "Authorization: Bearer polar_pat_..."
Query Parameters
Get Webhook Endpoint
curl -X GET "https://api.polar.sh/v1/webhooks/endpoints/{id}" \
-H "Authorization: Bearer polar_pat_..."
Path Parameters
Create Webhook Endpoint
curl -X POST "https://api.polar.sh/v1/webhooks/endpoints" \
-H "Authorization: Bearer polar_pat_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks/polar",
"events": [
"checkout.confirmed",
"subscription.created",
"order.created"
],
"organization_id": "org_123"
}'
Request Body
HTTPS URL to receive webhook events
Event types to subscribe to
Organization ID (required unless using org token)
Response
Returns the webhook endpoint object including the secret for signature verification.
Update Webhook Endpoint
curl -X PATCH "https://api.polar.sh/v1/webhooks/endpoints/{id}" \
-H "Authorization: Bearer polar_pat_..." \
-H "Content-Type: application/json" \
-d '{
"events": [
"checkout.confirmed",
"subscription.created",
"subscription.updated",
"order.created"
]
}'
Path Parameters
Request Body
Delete Webhook Endpoint
curl -X DELETE "https://api.polar.sh/v1/webhooks/endpoints/{id}" \
-H "Authorization: Bearer polar_pat_..."
Path Parameters
List Deliveries
curl -X GET "https://api.polar.sh/v1/webhooks/endpoints/{id}/deliveries" \
-H "Authorization: Bearer polar_pat_..."
View delivery history for a webhook endpoint.
Path Parameters
Query Parameters
Filter by delivery status
Filter deliveries after this timestamp
Filter deliveries before this timestamp
Redeliver Webhook
curl -X POST "https://api.polar.sh/v1/webhooks/deliveries/{id}/redeliver" \
-H "Authorization: Bearer polar_pat_..."
Retry a failed webhook delivery.
Path Parameters
Event Types
Checkout Events
A new checkout session was created
A checkout session was updated
A checkout was confirmed and payment succeeded
Order Events
Subscription Events
A new subscription was created
A subscription was updated
A subscription was canceled
A subscription was revoked
Customer Events
A new customer was created
Benefit Events
A benefit was granted to a customer
A benefit was revoked from a customer
Webhook Payload
All webhooks include:
{
"type": "checkout.confirmed",
"data": {
// Event-specific data
},
"timestamp": "2024-01-15T10:30:00Z",
"id": "evt_123"
}
Signature Verification
Verify webhook authenticity using the Polar-Signature header:
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
import crypto from 'crypto';
function verifyWebhook(
payload: string,
signature: string,
secret: string
): boolean {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
Examples
Create Webhook for All Events
curl -X POST "https://api.polar.sh/v1/webhooks/endpoints" \
-H "Authorization: Bearer polar_pat_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://myapp.com/webhooks/polar",
"events": [
"checkout.confirmed",
"order.created",
"subscription.created",
"subscription.updated",
"subscription.canceled",
"customer.created"
],
"organization_id": "org_xyz"
}'
Handle Webhook in Express.js
app.post('/webhooks/polar', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['polar-signature'] as string;
const payload = req.body;
if (!verifyWebhook(payload.toString(), signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(payload.toString());
switch (event.type) {
case 'checkout.confirmed':
// Handle confirmed checkout
break;
case 'subscription.created':
// Handle new subscription
break;
}
res.sendStatus(200);
});