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:
- An internal account or user record that will receive access.
- A Paypercut Customer, or a flow that creates or identifies one before Checkout.
- A recurring Price for the plan.
- A webhook endpoint that verifies signatures.
- 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_urlwithout 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, orsubscription.canceledwebhooks 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. |

