Webhooks & Callbacks
HeroPrompt uses webhooks to notify your application of important events like subscription changes and payment completions.
Webhook Events
Stripe Events
HeroPrompt listens for these Stripe webhook events:
1. checkout.session.completed
Triggered when a user completes a checkout session (subscription or one-time payment).
Payload example:
{
"type": "checkout.session.completed",
"data": {
"object": {
"id": "cs_test_...",
"customer": "cus_...",
"subscription": "sub_...",
"metadata": {
"user_id": "user-abc-123",
"tier": "pro"
}
}
}
}What happens:
- User's subscription is created/updated in database
- Tier is upgraded to purchased level
- Access is granted immediately
2. customer.subscription.updated
Triggered when subscription details change (renewal, cancellation, tier change).
Payload example:
{
"type": "customer.subscription.updated",
"data": {
"object": {
"id": "sub_...",
"customer": "cus_...",
"status": "active",
"current_period_end": 1704067200,
"cancel_at_period_end": false
}
}
}What happens:
- Subscription status updated
- Period end date updated
- Cancellation status updated
3. customer.subscription.deleted
Triggered when a subscription is cancelled and the period ends.
Payload example:
{
"type": "customer.subscription.deleted",
"data": {
"object": {
"id": "sub_...",
"customer": "cus_..."
}
}
}What happens:
- User tier downgraded to FREE
- Subscription marked as cancelled
- Access revoked to PRO features
PayPal Events
HeroPrompt processes PayPal webhooks for:
1. PAYMENT.SALE.COMPLETED
One-time payment (Lifetime tier) completed.
What happens:
- User upgraded to LIFETIME tier
- Payment recorded in database
- Confirmation email sent
2. BILLING.SUBSCRIPTION.ACTIVATED
Recurring subscription (Starter/Pro) activated.
What happens:
- User upgraded to purchased tier
- Subscription ID stored
- Access granted
3. BILLING.SUBSCRIPTION.CANCELLED
User cancelled recurring subscription.
What happens:
- Subscription marked as cancelled
- Access continues until period end
- User notified
Webhook Endpoints
Stripe Webhook
POST /api/payments/webhookConfiguration:
- Go to Stripe Dashboard → Developers → Webhooks
- Add endpoint:
https://heroprompt.store/api/payments/webhook - Select events:
checkout.session.completedcustomer.subscription.updatedcustomer.subscription.deleted
- Copy webhook signing secret to
STRIPE_WEBHOOK_SECRETenv var
PayPal Webhook
POST /api/payments/paypal/webhookConfiguration:
- Go to PayPal Developer Dashboard → Applications → Webhooks
- Add webhook URL:
https://heroprompt.store/api/payments/paypal/webhook - Subscribe to events:
PAYMENT.SALE.COMPLETEDBILLING.SUBSCRIPTION.ACTIVATEDBILLING.SUBSCRIPTION.CANCELLED
Webhook Security
Stripe Signature Verification
Stripe signs webhooks with a secret. HeroPrompt verifies the signature to ensure events are authentic:
import stripe
def verify_stripe_webhook(payload, sig_header, secret):
try:
event = stripe.Webhook.construct_event(
payload, sig_header, secret
)
return event
except stripe.error.SignatureVerificationError:
raise ValueError("Invalid signature")❌ Don't skip verification — unsigned webhooks could be forged.
PayPal Verification
PayPal webhooks include verification headers. HeroPrompt validates events using PayPal's SDK.
Testing Webhooks Locally
Using Stripe CLI
# Install Stripe CLI
brew install stripe/stripe-cli/stripe
# Login
stripe login
# Forward webhooks to localhost
stripe listen --forward-to localhost:8000/api/payments/webhook
# Trigger test events
stripe trigger checkout.session.completedUsing ngrok for PayPal
# Install ngrok
brew install ngrok
# Start ngrok tunnel
ngrok http 8000
# Update PayPal webhook URL to ngrok URL
# e.g., https://abc123.ngrok.io/api/payments/paypal/webhookWebhook Reliability
Retries
- Stripe: Retries failed webhooks automatically (up to 3 days)
- PayPal: Retries failed webhooks for 10 days
Idempotency
Webhook handlers are idempotent — processing the same event multiple times has no side effects.
Example:
# Check if event already processed
if Event.objects.filter(stripe_event_id=event.id).exists():
return # Skip, already handledHandling Failures
If webhook processing fails:
- Log the error
- Return 5xx status code (triggers retry)
- Alert developers if critical
Monitoring Webhooks
Stripe Dashboard
View webhook delivery attempts:
- Stripe Dashboard → Developers → Webhooks → [Your Endpoint]
- See success/failure rates
- Inspect individual events
PayPal Dashboard
View webhook history:
- PayPal Developer Dashboard → Applications → Webhooks → [Your URL]
- See delivery status
- Retry failed events manually
Custom Webhooks (Coming Soon)
Future versions will support user-defined webhooks for:
- Subscription upgrades/downgrades
- Usage limit warnings
- Content updates (new prompts, skills)
Stay tuned!
Troubleshooting
Webhook not received
Checklist:
- ✅ Webhook URL is publicly accessible (not localhost)
- ✅ HTTPS is enabled (required by Stripe and PayPal)
- ✅ Firewall allows incoming requests
- ✅ Webhook endpoint returns 2xx status
Signature verification fails
Stripe:
- Verify
STRIPE_WEBHOOK_SECRETis correct - Check that secret matches the endpoint in Stripe Dashboard
PayPal:
- Ensure PayPal SDK is up to date
- Verify webhook is configured in correct PayPal app
Events arrive out of order
Solution: Use event timestamps and database transactions to handle out-of-order events correctly.