This guide explains how to set up and test Creem.io webhooks following their official documentation.
- Location:
/api/webhook/creem/route.ts - Method: POST only
- Framework: Next.js App Router
- Status: ✅ Implemented
- Body Parsing: ✅
await request.text()→JSON.parse() - Schema Validation: ✅ Zod schemas for all event types
- Error Handling: ✅ Proper HTTP status codes
// Success response
return NextResponse.json({ received: true, processed: true }, { status: 200 });// HMAC-SHA256 verification as per Creem docs
const computedSignature = crypto.createHmac('sha256', secret).update(payload).digest('hex');- Development: Signature verification optional
- Production: Signature verification required
- Secret:
CREEM_WEBHOOK_SECRETenvironment variable
https://your-ngrok-domain.ngrok.io/api/webhook/creem
https://your-production-domain.com/api/webhook/creem
| Event Type | Status | Description |
|---|---|---|
checkout.completed |
✅ | Creates active subscription |
subscription.active |
✅ | Activates subscription |
subscription.paid |
✅ | Payment received |
subscription.canceled |
✅ | Subscription cancelled |
subscription.expired |
✅ | Subscription expired |
subscription.update |
✅ | Subscription updated |
subscription.trialing |
✅ | Trial period started |
refund.created |
✅ | Refund processed |
dispute.created |
✅ | Dispute opened |
Creem automatically retries failed webhooks with this schedule:
- 30 seconds → First retry
- 1 minute → Second retry
- 5 minutes → Third retry
- 1 hour → Final retry
Important: Return HTTP 200 OK to stop retries!
# .env.local
CREEM_WEBHOOK_SECRET=your_webhook_secret_here
NODE_ENV=development# Install ngrok
npm install -g ngrok
# Start your Next.js app
bun dev
# In another terminal, expose your local server
ngrok http 3000
# Use the ngrok URL in Creem dashboard
https://abc123.ngrok.io/api/webhook/creem- Go to Developers → Webhooks
- Add your webhook URL
- Select events to receive
- Save webhook secret
# Test signature verification
bun test apps/web/app/tests/creem-webhook-signature.test.ts
# Test webhook integration
bun test apps/web/app/tests/creem-webhook-integration.test.ts# Test with curl
curl -X POST https://your-domain.com/api/webhook/creem \
-H "Content-Type: application/json" \
-H "creem-signature: your_signature_here" \
-d '{
"id": "evt_test_123",
"eventType": "subscription.expired",
"created_at": 1234567890,
"object": {
"id": "sub_123",
"status": "expired",
"customer": {
"id": "cus_123",
"email": "test@example.com"
},
"product": {
"id": "prod_123",
"name": "VT+ Monthly"
},
"current_period_start_date": "2024-01-01T00:00:00Z",
"current_period_end_date": "2024-01-31T23:59:59Z"
}
}'# Development logs
bun dev
# Look for webhook events
[Creem Webhook] Received webhook request at /api/webhook/creem
[Creem Webhook] Event processed successfully❌ Issue: 401 Unauthorized
✅ Solution: Check CREEM_WEBHOOK_SECRET and signature
❌ Issue: 400 Bad Request
✅ Solution: Verify JSON payload format
❌ Issue: 500 Internal Server Error ✅ Solution: Check database connection and user exists
# Deploy to production
./deploy-fly.sh
# Verify endpoint is accessible
curl https://your-production-domain.com/api/webhook/creem- Go to Live environment in Creem
- Update webhook URL to production
- Test with a live payment
- Check application logs
- Monitor webhook delivery in Creem dashboard
- Set up alerts for failed webhooks
sequenceDiagram
participant C as Creem.io
participant W as Webhook Endpoint
participant D as Database
participant U as User Interface
C->>W: POST /api/webhook/creem
Note over C,W: Event: subscription.expired
W->>W: Verify signature
W->>W: Validate payload
W->>D: Update subscription status
W->>W: Invalidate caches
W->>C: 200 OK
Note over D,U: User sees updated status
U->>D: Check subscription
D->>U: Status: expired
Before going live, verify:
- Webhook URL is publicly accessible
- HTTPS is enabled (required by Creem)
- Signature verification works in production
- All event types are handled correctly
- Database updates work properly
- Cache invalidation occurs
- Error handling returns appropriate HTTP codes
- Logs are properly configured
If you encounter issues:
- Check the test files for working examples
- Review Creem.io webhook documentation
- Verify environment variables are set correctly
- Test signature verification independently
- Check application logs for detailed error messages