Prood
Guides

Webhook Setup

Configure payment provider webhooks for async payment confirmation and order reconciliation.

Payment webhooks are essential for async payment methods (Multibanco, MB WAY) and as a safety net for card payments (3DS failures, browser closes). This guide covers webhook configuration for all supported providers.

Webhook architecture

Drag to pan · Scroll to zoom

Why webhooks matter

ScenarioWithout webhookWith webhook
Customer closes browser during 3DSOrder stuck as pendingWebhook confirms payment
Multibanco payment (async)No way to detect paymentWebhook fires when customer pays at ATM
MB WAY timeoutOrder stuckWebhook on phone confirmation
Network error on confirmOrder stuckWebhook as safety net

Stripe webhooks

1. Create webhook endpoint

In Stripe Dashboard → Developers → Webhooks → Add endpoint:

Endpoint URL: https://checkout.example.com/api/webhooks/stripe/{orgId}

Replace {orgId} with the merchant's organization ID (e.g. org_demo).

2. Select events

Checkout Session events (primary — required for Checkout Sessions API):

EventPurpose
checkout.session.completedPayment captured (primary success signal)
checkout.session.expiredSession timed out before payment
checkout.session.async_payment_succeededDelayed payment confirmed (bank transfers, Boleto, etc.)
checkout.session.async_payment_failedDelayed payment failed

PaymentIntent events (Stripe fires these alongside Checkout Session events):

EventPurpose
payment_intent.succeededPayment captured
payment_intent.payment_failedPayment declined
payment_intent.canceledPayment canceled
payment_intent.processingPayment processing
payment_intent.amount_capturable_updatedFunds available for manual capture

Charge / Refund events:

EventPurpose
charge.refundedRefund processed
refund.createdRefund initiated

You can configure all events at once using the provided setup script:

./scripts/stripe-webhook-setup.sh

3. Copy signing secret

After creating the endpoint, copy the Signing secret (whsec_...).

4. Configure in dashboard

Dashboard → Integrations → Stripe → Webhook secret: whsec_...

Or set globally: STRIPE_WEBHOOK_SECRET=whsec_...

5. Test locally

Use Stripe CLI for local webhook testing:

stripe listen --forward-to localhost:3004/api/webhooks/stripe/org_demo
stripe trigger checkout.session.completed
stripe trigger payment_intent.succeeded

Easypay webhooks

1. Configure in Easypay panel

Log in to Easypay merchant panel → Settings → Notifications:

Notification URL: https://checkout.example.com/api/webhooks/easypay/{orgId}

2. Events

Easypay sends notifications for:

  • Payment received (Multibanco, MB WAY, card)
  • Payment expired
  • Refund processed

3. Sandbox testing

Use EASYPAY_BASE_URL=https://api.test.easypay.pt and configure test webhook URL similarly.

Ifthenpay webhooks

1. Configure in backoffice

Log in to Ifthenpay backoffice → Configurações → Callback URL:

Callback URL: https://checkout.example.com/api/webhooks/ifthenpay/{orgId}

2. Anti-phishing verification

Ifthenpay includes an anti-phishing key in webhook payloads. The provider verifies this against IFTHENPAY_ANTIPHISHING_KEY (or tenant config).

Per-tenant webhook URLs

Each merchant gets their own webhook URL with their org ID:

https://checkout.example.com/api/webhooks/stripe/org_merchant_a
https://checkout.example.com/api/webhooks/stripe/org_merchant_b
https://checkout.example.com/api/webhooks/easypay/org_merchant_a

This ensures webhook verification uses the correct tenant's stored secret.

For platform-wide (env-only) webhooks, use _ as the org:

https://checkout.example.com/api/webhooks/stripe/_

Webhook verification flow

Drag to pan · Scroll to zoom

Direct API webhooks

Alternatively, route webhooks directly to the API (bypassing checkout):

POST https://api.example.com/v1/webhooks/payments/stripe?org={orgId}
Header: x-checkout-secret: {CHECKOUT_API_SECRET}

This is useful if you prefer a single webhook ingress point.

Troubleshooting

IssueCheck
401 on webhookx-checkout-secret mismatch between checkout and API
Signature verification failsWebhook secret in dashboard doesn't match provider dashboard
Order not updatingCheck API logs for webhook processing errors
Wrong tenant updatedVerify org ID in webhook URL matches the merchant
Webhook not receivedCheck provider dashboard for delivery logs and retry

On this page