Create subscriptions with Checkout

Use Checkout when the customer needs a hosted or embedded signup flow that collects the first payment and saves a reusable payment method for renewal billing.

This is the recommended beginner path for subscription integrations.

What this page covers

  • When to use Checkout for subscription signup
  • Which actor owns each step
  • How to create the Checkout Session
  • What to store
  • Which events to handle
  • Common mistakes and troubleshooting

When to use this

Use Checkout-created subscriptions when:

  • the customer signs up from your website or app;
  • Paypercut should collect payment details;
  • you want hosted or embedded Checkout;
  • the plan is represented by a recurring Price-backed line item;
  • your backend can receive webhooks and grant access from server-side state.

When not to use this

Do not use this path when:

  • your backend already has a reusable payment method and should create the subscription server-side;
  • you need a phase-based schedule as the primary object;
  • you need to collect only a one-time payment;
  • you are trying to use send_invoice, which is not part of this beginner Checkout path.

Before you start

Prepare:

  1. An internal account or user record that will receive access.
  2. A Paypercut Customer, or a flow that creates or identifies one before Checkout.
  3. A recurring Price for the plan.
  4. A webhook endpoint that verifies signatures.
  5. Database columns or tables for the Paypercut IDs you will store.

For a new test account, first create a Customer, Product, and recurring Price. The Quickstart shows the setup calls. Do not leave the example IDs in place; replace them with IDs returned by your API calls.

Actor ownership

Actor Owns
Your backend Creates Checkout Sessions, stores IDs, receives webhooks, retrieves latest state, grants access.
Your frontend Sends the customer to Checkout or embeds Checkout.
Customer Enters or confirms payment details in Checkout.
Paypercut Hosts Checkout, collects payment, links the subscription, creates invoices, sends events.

Flow overview

Moment What it means Access decision
Checkout Session created Your backend started a signup flow. Do not grant access.
Customer completed Checkout checkout_session.completed can be delivered. Retrieve/store the session and subscription; do not rely on this alone for paid-period access.
Subscription linked The Checkout Session can include a subscription ID. Store it for reconciliation.
Invoice paid invoice.paid confirms a paid billing period. Grant or extend access.
Invoice payment failed invoice.payment_failed confirms collection failed. Start recovery and reconcile state.

Create the Checkout Session

Create the session from your backend. The line item should reference a recurring Price.

curl https://api.paypercut.io/v1/checkouts \
  -X POST \
  -H "Authorization: Bearer $PAYPERCUT_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: checkout-subscription-user-123-pro" \
  -d '{
    "mode": "subscription",
    "ui_mode": "hosted",
    "currency": "EUR",
    "customer": "01HD7M6DRKZ4Q4QEVWJB0RC1S6",
    "line_items": [
      {
        "price": "01HFRECURRINGPRICE000000000",
        "quantity": 1
      }
    ],
    "success_url": "https://example.com/billing/success",
    "cancel_url": "https://example.com/billing/cancel",
    "client_reference_id": "user_123",
    "metadata": {
      "internal_account_id": "acct_123"
    }
  }'

After creation, send the customer to the Checkout Session url or render the session with embedded Checkout.

Customer action

The customer completes Checkout on the hosted or embedded page. Your success page can tell the customer that the signup is being confirmed, but it should not be the only path that grants access.

Use your backend webhook handler to make the final access decision.

Server-side event handling

Handle these events:

Event What it tells you What your backend should do
checkout_session.completed The customer completed Checkout. Retrieve or store the Checkout Session, map it to your internal account, and store the linked subscription if returned.
invoice.paid An invoice for a billing period was paid. Grant or extend access idempotently.
invoice.payment_failed Paypercut could not collect payment for an invoice attempt. Notify the customer, start recovery, and fetch latest subscription and invoice state.

What to store

Store enough state to reconcile future events without relying on a browser session:

Field Why
Internal user or account ID Identifies who receives access.
customer_id Lets you reconcile Customer and invoice data.
price_id Maps the subscription to your plan.
checkout_session_id Reconciles the signup flow and checkout_session.completed.
subscription_id Reconciles recurring lifecycle and invoice parent details.
invoice_id Makes paid-period processing idempotent.
Webhook event or delivery ID Prevents duplicate processing.

Common mistakes

  • Granting access from success_url without waiting for server-side confirmation.
  • Creating a subscription Checkout Session with a one-time Price.
  • Storing the Checkout Session but not the subscription_id.
  • Ignoring invoice.payment_failed.
  • Treating PaymentIntent events as the subscription lifecycle source.
  • Assuming public subscription.created, subscription.updated, or subscription.canceled webhooks exist.

Troubleshooting

Symptom Check
Checkout Session creation fails Confirm mode is subscription, the line item uses a recurring Price, and the request has a customer when your flow requires one.
Customer reaches success page but has no access Confirm your webhook handler processed the server-side event and mapped the Checkout Session to your internal account.
Access is not extended after renewal Confirm your webhook endpoint receives and processes invoice.paid idempotently.
Customer remains blocked after failed payment Confirm invoice.payment_failed starts your recovery UX and that you retrieve latest state before making customer-visible decisions.

Next