HeroPrompt
Back to docs
API Reference

Webhooks & Callbacks

Event webhooks for payment confirmations and subscription updates.

Updated 2026-02-15

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:

json
{
  "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:

json
{
  "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:

json
{
  "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

text
POST /api/payments/webhook

Configuration:

  1. Go to Stripe Dashboard → Developers → Webhooks
  2. Add endpoint: https://heroprompt.store/api/payments/webhook
  3. Select events:
  • checkout.session.completed
  • customer.subscription.updated
  • customer.subscription.deleted
  1. Copy webhook signing secret to STRIPE_WEBHOOK_SECRET env var

PayPal Webhook

text
POST /api/payments/paypal/webhook

Configuration:

  1. Go to PayPal Developer Dashboard → Applications → Webhooks
  2. Add webhook URL: https://heroprompt.store/api/payments/paypal/webhook
  3. Subscribe to events:
  • PAYMENT.SALE.COMPLETED
  • BILLING.SUBSCRIPTION.ACTIVATED
  • BILLING.SUBSCRIPTION.CANCELLED

Webhook Security

Stripe Signature Verification

Stripe signs webhooks with a secret. HeroPrompt verifies the signature to ensure events are authentic:

python
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

bash
# 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.completed

Using ngrok for PayPal

bash
# 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/webhook

Webhook 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:

python
# Check if event already processed
if Event.objects.filter(stripe_event_id=event.id).exists():
    return  # Skip, already handled

Handling Failures

If webhook processing fails:

  1. Log the error
  2. Return 5xx status code (triggers retry)
  3. 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_SECRET is 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.

Next Steps