Webhooks for subscription integrations

Use webhooks to keep your subscription state in sync after Checkout, invoice, and payment events. Do not frame this integration around public subscription.* events unless they are exposed in the public API reference for your account.

What this page covers

  • Why subscription integrations need webhooks
  • Required and recommended events
  • How to process events idempotently
  • When to fetch latest state
  • How to grant access, extend access, and handle failed payments
  • How to debug missing or unexpected events

Before you use this page

Configure signature verification before processing any webhook event. See Webhook Signature Verification.

You should also read Invoices and payment collection so your backend treats invoice events as billing-period signals.

Why webhooks matter

Checkout redirects and frontend callbacks are not reliable enough for production access decisions. The customer can close the browser, reload a success page, or arrive before your backend has processed the final state.

Use webhooks so Paypercut can notify your backend when Checkout completes, invoices are paid, and payment collection fails.

Required events

Handle these events for the beginner Checkout subscription path:

Event What it tells you What your backend should do
checkout_session.completed The customer completed Checkout. Retrieve or store the Checkout Session and linked subscription details. Do not rely on this alone for paid-period access.
invoice.paid An invoice for a billing period was paid. Grant or extend access idempotently.
invoice.payment_failed Payment collection failed for an invoice attempt. Start recovery UX and fetch latest invoice or subscription state.

Payment and PaymentIntent events can be useful for support and reconciliation:

Event Use
payment.succeeded Reconcile payment-level success or support questions.
payment_intent.authorized Track authorization-level state when your integration uses PaymentIntents directly.
payment_intent.captured Track capture-level state when your integration uses capture flows.

Do not use these payment-level events as the primary subscription lifecycle contract. Use invoice events for billing-period access decisions.

Event handling flow

  1. Receive the webhook request.
  2. Verify the Paypercut signature using the raw request body.
  3. Store or check the event ID or delivery ID for idempotency.
  4. Switch on the event type.
  5. For checkout_session.completed, store the Checkout Session and linked subscription.
  6. For invoice.paid, grant or extend access for the paid billing period.
  7. For invoice.payment_failed, start recovery and fetch latest state before making customer-visible changes.
  8. Return a successful response only after your handler has safely recorded the event or action.

Idempotency

Webhook events can be delivered more than once. Your handler should be safe to run repeatedly.

Store one of these before performing customer-visible work:

  • webhook event ID;
  • delivery ID;
  • invoice ID plus event type;
  • subscription ID plus billing period, when your own schema tracks access by period.

For example, if the same invoice.paid event arrives twice, your backend should not grant duplicate credits, extend access twice, or send duplicate fulfillment.

Fetch latest state when needed

The webhook payload gives you the object that changed. If your access decision depends on current subscription or invoice state, retrieve the latest object from the API before updating your product.

This is especially useful when:

  • an event was delayed;
  • your webhook handler was offline and caught up later;
  • a failed payment was followed by a recovery action;
  • your support tools need the current subscription status.

Granting and extending access

Use invoice.paid for paid billing periods.

Your access handler should:

  1. Find the linked subscription from the invoice.
  2. Map the subscription to your internal user or account.
  3. Determine the billing period or entitlement window.
  4. Grant or extend access idempotently.
  5. Store the invoice ID and processing result.

Handling failed payments

Use invoice.payment_failed to start recovery.

Your recovery handler should:

  1. Find the linked subscription and customer.
  2. Notify the customer or show payment recovery UI.
  3. Fetch latest state if you need to decide whether access should continue.
  4. Record the failed invoice attempt for support and reporting.

Do not ignore failed payment events. Renewal failures are part of the normal subscription lifecycle.

Debugging missing events

Problem Check
No events arrive Confirm the webhook endpoint is configured, active, and subscribed to the required event types.
Signature verification fails Verify you are using the raw request body and the correct endpoint secret.
Access is not granted Confirm invoice.paid was received, processed once, and mapped to the correct subscription and internal account.
Checkout completed but no paid access exists Retrieve the Checkout Session and invoice state. Do not assume Checkout completion and paid-period confirmation are the same signal.
Handler processes duplicates Store event or delivery IDs and make each action idempotent.

Current public event model

The beginner subscription path relies on Checkout, invoice, and payment events. Do not search for or build against public subscription.created, subscription.updated, or subscription.canceled events unless they appear in the public API reference for your account.

Next