QrioTagQrioTag Docs
API Reference

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 FREE tier
  • 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

  1. Go to Stripe Dashboard > Webhooks
  2. Click Add endpoint
  3. Enter your webhook URL: https://your-domain.com/api/v1/webhooks/stripe
  4. Select the events listed above
  5. Click Add endpoint
  6. 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 stripe

Forward Events

# Login to Stripe
stripe login
  stripe listen --forward-to https://api.qriotag.global/api/v1/webhooks/stripe

The 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.deleted

Example 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/stripe

Webhook 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-Signature header. The API verifies this against STRIPE_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 200 immediately 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?

Webhooks | QrioTag Docs