Checkout
If you want to integrate the checkout process directly into your application, you can use our API to create sessions programmatically. This gives you full control over when and how your customers are prompted to pay.
Checkout isn’t just for one-time payments - when a customer completes checkout, Paid creates an order (subscription) that tracks their plan, billing cycle, and usage over time.
Prerequisites
- A Paid API key and the Paid SDK installed in the service that creates checkout sessions.
- A product or plan the customer can purchase. You can find the product ID in Products, or create one through the Products API.
- Stripe connected for the organization. On a test-mode organization, you can use a Stripe sandbox and pay with test payment methods.
- A success URL in your application and a stable customer identifier when the checkout should attach to an existing user or account.
Creating a session
To create a checkout session, call the API with the products you want the customer to purchase and a URL to redirect them to after payment.
The API returns an object containing all the information about the session, including a url where you should redirect your customer so they can complete their order.
Node.js
Python
Go
Ruby
Java
The {CHECKOUT_ID} placeholder in successUrl is automatically replaced with the checkout’s display ID (e.g. chk_abc123), so you can retrieve the result when the customer returns.
Handling the return
After payment, verify the checkout before provisioning access. Check that the status is completed and that externalCustomerId matches the currently authenticated user. This prevents one user from using another’s checkout ID to gain unauthorised access.
Node.js
Python
Go
A checkout reads completed once it has been paid only if it is single-use,
which is the default. A reusable checkout (singleUse: false) stays active
after each payment, so check for completed only on single-use checkouts. To
react to payments on a reusable checkout, listen for the
billing-checkout-completed webhook.
Checkout status
A checkout’s status tells you whether it can still be paid:
You can list checkouts by status, for example GET /v2/checkouts?status=completed returns every paid single-use checkout.
When Paid contacts Stripe
Opening a checkout and choosing a plan does not charge anything. Paid contacts Stripe only when the customer submits their payment details:
- Paid asks Stripe to charge the card. If the card is declined, the customer can try again on the same page.
- If the customer’s bank asks for 3D Secure, the payment waits until they finish it. Paid then checks the result with Stripe.
- If the customer closes the page during payment, Paid still learns the outcome from Stripe and creates the order once the payment succeeds.
When a checkout can’t be paid
These rules apply to single-use checkouts. A reusable checkout can always be paid while it is active.
Stripe does not cancel an unfinished payment on its own. If a customer abandons 3D Secure, the checkout stays in “Payment in progress”. To let them pay again:
- Cancel the payment in your Stripe dashboard. Until you do, the customer can still finish 3D Secure on the old page and be charged.
- Archive the checkout.
- Send the customer a new checkout.
Identifying the customer
There are three ways that customers become associated with a checkout.
externalCustomerId (recommended for most integrations)
Pass your own user identifier: a database ID, UUID, or email. On the first checkout for a given ID, Paid creates the customer automatically. On subsequent checkouts with the same ID, Paid resolves to the existing customer, so upgrades and plan changes work seamlessly without any extra setup.
Node.js
Go
customerId
If you’ve already created a customer in Paid, for example via the Customers API or the dashboard, you can reference them directly by their Paid customer ID (cus_...).
Node.js
Go
Only one of customerId or externalCustomerId may be provided.
Anonymous
If you don’t have a customer yet, for example on a public pricing page, omit both. The checkout page will collect the customer’s name and email, and Paid creates the customer record on completion.
Node.js
Python
Go
Multiple products
You can pass several products in a single session. If a product has plan tiers, the customer picks one during checkout. If it doesn’t, it’s shown directly with its base pricing.
Node.js
Python
Go
Automatic upgrades
If the externalCustomerId already has an active order for the product, Paid automatically handles the upgrade with proration. No need for separate upgrade logic. The same API call works for both new purchases and plan changes.
Node.js
Python
Go
Expiration
By default, checkout sessions expire after 24 hours. You can override this by setting expiresAt to an ISO 8601 timestamp.
Node.js
Python
Go
Metadata
You can attach arbitrary key-value metadata to a checkout session for your own tracking. This data is returned on the checkout object but is never shown to the customer.
Node.js
Python
Go
Settings
Currency
Lock the checkout to a specific currency with currency. If omitted, the customer can pay in any currency supported by the selected plan.
Node.js
Go
Single use
By default, checkouts are single-use: they can be paid once. The link stays usable until someone pays:
- If the payment fails, for example because the card is declined, or the customer closes the tab before paying, opening the link again takes them back to the same payment page.
- While a payment is being processed, anyone else who opens the link sees “Payment in progress”, so the checkout can’t be paid twice.
- Once paid, the checkout’s status becomes
completed. Opening the link again shows “This checkout has already been completed”.
Set singleUse: false for a reusable link that many customers can pay, for example on a public pricing page. A reusable checkout stays active.
Node.js
Go
Collecting customer information
By default, Paid collects the customer’s billing address (required for tax calculation). You can also request a phone number.