Webhooks
Stripe webhook integration for payment processing, subscription management, and event handling.
QrioTag uses Stripe webhooks to process payments and manage subscriptions. When a payment event occurs, Stripe sends a POST request to your webhook endpoint with event data.
Webhook Endpoint
POST /webhooks/stripe — Auth: Stripe signature verification
This endpoint is not called by your application directly. Stripe sends events to this URL automatically when payment-related actions occur.
Signature verification
Every incoming webhook request is verified using the Stripe webhook signing secret (STRIPE_WEBHOOK_SECRET). Requests with invalid signatures are rejected with 400 Bad Request.
Supported Events
checkout.session.completed
Fired when a customer completes a Stripe Checkout session (one-time purchase or subscription start).
What QrioTag does:
- Marks the order as
COMPLETED - Activates purchased tags
- Sends order confirmation email
- Updates inventory
{
"id": "evt_abc123",
"type": "checkout.session.completed",
"data": {
"object": {
"id": "cs_live_abc123",
"payment_status": "paid",
"customer": "cus_abc123",
"metadata": {
"orderId": "ord_abc123",
"userId": "usr_abc123"
}
}
}
}payment_intent.succeeded
Fired when a payment is successfully processed.
What QrioTag does:
- Records the successful payment
- Updates order payment status
{
"id": "evt_def456",
"type": "payment_intent.succeeded",
"data": {
"object": {
"id": "pi_abc123",
"amount": 2999,
"currency": "usd",
"customer": "cus_abc123"
}
}
}payment_intent.payment_failed
Fired when a payment attempt fails.
What QrioTag does:
- Marks the order payment as failed
- Sends a payment failure notification to the user
{
"id": "evt_ghi789",
"type": "payment_intent.payment_failed",
"data": {
"object": {
"id": "pi_abc123",
"amount": 2999,
"currency": "usd",
"last_payment_error": {
"message": "Your card was declined."
}
}
}
}customer.subscription.created
Fired when a new subscription is created.
What QrioTag does:
- Updates the user's subscription tier
- Unlocks premium features
- Sends subscription confirmation email
{
"id": "evt_sub001",
"type": "customer.subscription.created",
"data": {
"object": {
"id": "sub_abc123",
"customer": "cus_abc123",
"status": "active",
"items": {
"data": [
{
"price": {
"id": "price_pro_monthly",
"metadata": { "tier": "PRO" }
}
}
]
}
}
}
}customer.subscription.updated
Fired when a subscription is modified (upgrade, downgrade, or plan change).
What QrioTag does:
- Updates the user's subscription tier
- Adjusts feature access accordingly
{
"id": "evt_sub002",
"type": "customer.subscription.updated",
"data": {
"object": {
"id": "sub_abc123",
"customer": "cus_abc123",
"status": "active",
"items": {
"data": [
{
"price": {
"id": "price_premium_monthly",
"metadata": { "tier": "PREMIUM" }
}
}
]
}
}
}
}customer.subscription.deleted
Fired when a subscription is cancelled and the billing period ends.
What QrioTag does:
- Downgrades the user to the
FREEtier - Removes premium feature access
- Sends subscription ended notification
{
"id": "evt_sub003",
"type": "customer.subscription.deleted",
"data": {
"object": {
"id": "sub_abc123",
"customer": "cus_abc123",
"status": "canceled"
}
}
}Setting Up the Webhook
1. Configure the Stripe Dashboard
- Go to Stripe Dashboard > Webhooks
- Click Add endpoint
- Enter your webhook URL:
https://your-domain.com/api/v1/webhooks/stripe - Select the events listed above
- Click Add endpoint
- Copy the Signing secret (starts with
whsec_)
2. Set the Environment Variable
Add the signing secret to your .env file:
STRIPE_WEBHOOK_SECRET=whsec_abc123...3. Verify It Works
Check the Stripe Dashboard webhook logs for successful deliveries (HTTP 200 responses).
Testing with Stripe CLI
The Stripe CLI lets you forward webhook events to your local development server.
Install the CLI
# macOS
brew install stripe/stripe-cli/stripe
# Windows (scoop)
scoop install stripe
# Linux
curl -s https://packages.stripe.dev/api/security/keypair/stripe-cli-gpg/public | gpg --dearmor | sudo tee /usr/share/keyrings/stripe.gpg
echo "deb [signed-by=/usr/share/keyrings/stripe.gpg] https://packages.stripe.dev/stripe-cli-debian-local stable main" | sudo tee -a /etc/apt/sources.list.d/stripe.list
sudo apt update && sudo apt install stripeForward Events
# Login to Stripe
stripe login stripe listen --forward-to https://api.qriotag.global/api/v1/webhooks/stripeThe CLI will output a webhook signing secret for local testing. Set it as your STRIPE_WEBHOOK_SECRET in .env.
Trigger Test Events
# Trigger a checkout completed event
stripe trigger checkout.session.completed
# Trigger a payment failure
stripe trigger payment_intent.payment_failed
# Trigger a subscription creation
stripe trigger customer.subscription.created
# Trigger a subscription cancellation
stripe trigger customer.subscription.deletedExample Output
2025-06-01 12:00:00 --> checkout.session.completed [evt_abc123]
2025-06-01 12:00:00 <-- [200] POST http://localhost:4000/api/v1/webhooks/stripeWebhook Security
Never skip signature verification
Always verify the Stripe signature header (Stripe-Signature) before processing webhook events. The QrioTag API does this automatically using the STRIPE_WEBHOOK_SECRET environment variable.
Key security practices:
- Verify signatures: Every webhook request includes a
Stripe-Signatureheader. The API verifies this againstSTRIPE_WEBHOOK_SECRET. - Use HTTPS in production: Never expose a plain HTTP webhook URL in production.
- Idempotency: Webhook handlers are idempotent. The same event delivered multiple times produces the same result.
- Respond quickly: The webhook endpoint returns
200immediately and processes the event asynchronously via BullMQ workers. - Retry behavior: Stripe retries failed webhook deliveries (non-2xx responses) for up to 3 days with exponential backoff.
Was this page helpful?