Overview
ZapDev integrates with Polar.sh to process subscription and payment events. The webhook endpoint handles subscription lifecycle events, customer synchronization, and payment status updates.Endpoint URL
Configuration
Environment Variables
Add these to your.env.local file:
Polar Dashboard Setup
- Go to your Polar.sh dashboard
- Navigate to Settings → Webhooks
- Add webhook URL:
https://yourdomain.com/api/webhooks/polar - Copy the webhook secret to your environment variables
- Select the events you want to receive (see supported events below)
Webhook Verification
All incoming webhooks are verified using the Polar SDK:src/app/api/webhooks/polar/route.ts:136-147.
Supported Events
Subscription Events
subscription.created
Fired when a new subscription is created.
subscription.updated
Fired when subscription details change (plan upgrade/downgrade, payment method, etc.).
Payload: Same structure as subscription.created.
Processing: Updates existing subscription record with new status and billing period.
subscription.active
Fired when a subscription becomes active (e.g., after trial period).
Payload: Same structure as subscription.created.
Processing: Ensures subscription status is set to active.
subscription.canceled
Fired when a user cancels their subscription.
api.subscriptions.markSubscriptionForCancellation.
See implementation in src/app/api/webhooks/polar/route.ts:273-294.
subscription.revoked
Fired when a subscription is immediately revoked (e.g., payment failure, refund).
Processing: Immediately revokes access via api.subscriptions.revokeSubscription.
See implementation in src/app/api/webhooks/polar/route.ts:296-317.
subscription.uncanceled
Fired when a previously canceled subscription is reactivated.
Processing: Reactivates subscription via api.subscriptions.reactivateSubscription.
See implementation in src/app/api/webhooks/polar/route.ts:319-340.
Checkout Events
checkout.created
Fired when a checkout session is initiated.
checkout.updated
Fired when checkout status changes (completed, expired, etc.).
succeeded or confirmed, syncs customer record and processes pending subscriptions.
See implementation in src/app/api/webhooks/polar/route.ts:171-198.
Order Events
order.created
Fired when a one-time purchase order is created.
src/app/api/webhooks/polar/route.ts:342-369.
Status Mapping
Polar subscription statuses are mapped to ZapDev’s internal status types:src/app/api/webhooks/polar/route.ts:17-27.
Pending Subscription Handling
If a webhook arrives before the user completes authentication, the subscription is saved as pending:- A
checkout.updatedevent arrives with userId metadata - An
order.createdevent links the customer to a user - The user completes sign-up and the system reconciles pending records
src/app/api/webhooks/polar/route.ts:228-246.
Event Logging
All webhook events are logged to thewebhookEvents table in Convex:
received- Event logged but not yet processedprocessed- Successfully handledfailed- Processing error occurredretrying- Automatic retry in progress
convex/webhooks.ts:4-31.
Health Check
Test webhook configuration:src/app/api/webhooks/polar/route.ts:403-427.
Testing
Use Polar’s webhook testing tool to send test events:- Go to Settings → Webhooks in Polar dashboard
- Click Send test event
- Select event type (e.g.,
subscription.created) - Verify event appears in your Convex
webhookEventstable
Error Handling
Webhook processing errors are logged but return200 OK to prevent Polar from retrying:
convex/webhooks.ts:77-88.
Related Files
- Webhook handler:
src/app/api/webhooks/polar/route.ts - Event logging:
convex/webhooks.ts - Customer sync:
convex/polar.ts - Subscription management:
convex/subscriptions.ts