Hosted checkout
Hosted checkout is the simplest way to take a customer from “interested” to “subscribed.” You create a checkout session with the plan and return URL; we host the page; the customer comes back to you with the subscription already active (or, if you’d prefer, just a payment method on file).
When to use it
- You don’t want to handle card data on your servers (PCI scope stays at SAQ-A).
- You want 3DS / SCA flows to “just work” without coding the redirect dance.
- You want a polished checkout in 30 minutes, not 30 days.
- You’re fine with the customer leaving your domain briefly.
If you need a fully embedded checkout, see Collect a payment method for the elements-style integration.
Create a session
POST /v1/checkout/sessionsIdempotency-Key: <uuid>Content-Type: application/json
{ "mode": "subscription", "customer_id": "cus_…", "plan_code": "pro-monthly-usd", "success_url": "https://yourapp.example/billing/welcome?session_id={CHECKOUT_SESSION_ID}", "cancel_url": "https://yourapp.example/pricing", "allow_promotion_codes": true, "trial_days": 14, "metadata": { "campaign": "spring-launch" }}{CHECKOUT_SESSION_ID} in success_url is replaced by Paylera with the
real session ID before redirect. Use it on your success page to fetch
the resulting subscription.
Modes
mode | What the page does |
|---|---|
subscription | Captures method + creates a subscription on the named plan. |
setup | Captures a payment method and attaches it to the customer. No charge. |
payment | One-off charge for a specified amount. No subscription. |
Pricing display
By default, the page shows the plan’s price as defined in the catalog. To override per session — e.g., for a sales-quoted price:
{ "line_items": [ { "plan_code": "enterprise-monthly-usd", "unit_amount": "999.00", "quantity": 1 } ]}Overrides are session-only and recorded in the audit trail.
Promotion codes
Set allow_promotion_codes: true to surface a “Have a code?” field on
the checkout page. When the customer enters one, the page validates it
against your coupons. The discount applies to the resulting
subscription.
To pre-apply a coupon (no input field):
{ "coupons": ["WELCOME20"] }Tax
If your tax engine is configured, the checkout page asks for the
customer’s billing address (if not already known) and shows the tax
breakdown live. For B2B, an optional VAT-ID field can be enabled with
collect_tax_ids: true.
Returning to your application
The customer is redirected to success_url after the session
completes. The session has one of three terminal states:
status | Meaning |
|---|---|
completed | Subscription created and (if applicable) first payment captured. |
pending_action | Payment captured but a follow-up step is in progress (e.g. webhook delivery). |
expired | Session timed out (24-hour TTL by default). |
To inspect:
GET /v1/checkout/sessions/{id}The response includes the resulting subscription_id and
payment_id.
React to the webhook
Don’t rely on the redirect to provision access — the customer might close the tab, the network might fail, the redirect domain might be hijacked. The source of truth is the webhook:
checkout.session.completed → subscription created, all donecheckout.session.expired → no resource createdIn your handler:
- Verify the signature.
- Look up the session by
session.idto get thesubscription_id(orpayment_method_idfor setup mode). - Provision the customer’s account.
- Ack with 2xx.
Customisation
The hosted page inherits your tenant’s brand:
- Logo — uploaded in Settings → Branding.
- Accent colour — single hex value; used on buttons and headings.
- Domain — by default
checkout.paylera.io; for your own domain (checkout.yourapp.com), see Custom domains — requires a CNAME and a managed certificate.
Locale is auto-detected from Accept-Language and overridable with
locale: "fr".
Customer portal
For ongoing self-service (change plan, update method, view invoices),
use the Customer portal — same pattern, a
POST /v1/portal/sessions call returns a hosted URL.
Webhook events
| Event | When |
|---|---|
checkout.session.created | Session URL was created. |
checkout.session.completed | Customer finished checkout. |
checkout.session.expired | Session TTL elapsed without completion. |
subscription.activated | (For mode: subscription) the resulting subscription is live. |
payment.succeeded | First payment captured. |