Skip to content

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/sessions
Idempotency-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

modeWhat the page does
subscriptionCaptures method + creates a subscription on the named plan.
setupCaptures a payment method and attaches it to the customer. No charge.
paymentOne-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:

statusMeaning
completedSubscription created and (if applicable) first payment captured.
pending_actionPayment captured but a follow-up step is in progress (e.g. webhook delivery).
expiredSession 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 done
checkout.session.expired → no resource created

In your handler:

  1. Verify the signature.
  2. Look up the session by session.id to get the subscription_id (or payment_method_id for setup mode).
  3. Provision the customer’s account.
  4. 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

EventWhen
checkout.session.createdSession URL was created.
checkout.session.completedCustomer finished checkout.
checkout.session.expiredSession TTL elapsed without completion.
subscription.activated(For mode: subscription) the resulting subscription is live.
payment.succeededFirst payment captured.