PaybytokenDocs
Checkout
Guide · Checkout

Hosted checkout

Redirect a customer to a Paybytoken-hosted stablecoin checkout page.

Hosted checkout is the quickest Paybytoken integration. Your server creates a Checkout Session and your browser redirects the customer to the returned URL. Paybytoken hosts the responsive payment UI, while your server keeps control of the order and fulfillment.

1. Install the server SDK

npm install @paybytoken/node

Store your test key in the server environment:

PAYBYTOKEN_SECRET_KEY=sk_test_...

2. Create a Checkout Session

Create the session from a server route after loading the order from your database:

import Paybytoken from '@paybytoken/node'

const paybytoken = new Paybytoken(process.env.PAYBYTOKEN_SECRET_KEY!)

export async function POST() {
  const order = await loadOrderForCurrentCustomer()

  const session = await paybytoken.checkoutSessions.create({
    currency: 'usd',
    line_items: order.items.map((item) => ({
      quantity: item.quantity,
      unit_amount: item.unitAmount,
      product_data: {
        name: item.name,
        description: item.description,
        images: item.imageUrl ? [item.imageUrl] : [],
      },
    })),
    supported_tokens: [
      { chain: 'base', currency: 'USDC' },
      { chain: 'ethereum', currency: 'USDC' },
    ],
    success_url: `https://shop.example.com/orders/${order.id}/complete`,
    cancel_url: `https://shop.example.com/cart`,
    metadata: { order_id: order.id },
  })

  return Response.json(
    { checkoutUrl: session.url },
    { status: 201, headers: { 'Cache-Control': 'no-store' } },
  )
}

Hosted is the default ui_mode; you can also set ui_mode: 'hosted' explicitly.

Do not accept a final price, destination address or token contract directly from the browser. Resolve them from merchant-owned data on your server.

See Create a Checkout Session for every supported request field.

3. Redirect the customer

Call your server route from the checkout button, then use a top-level navigation:

const response = await fetch('/api/paybytoken/checkout-session', {
  method: 'POST',
})

if (!response.ok) {
  throw new Error('Checkout session could not be created')
}

const { checkoutUrl } = await response.json()
window.location.assign(checkoutUrl)

Create a new session for a new payment attempt. Do not cache or reuse a Checkout Session across customers or orders.

4. Handle return and cancellation

The success_url is a destination for customer experience, not a fulfillment signal. Show a pending or completed order page by reading the authoritative order state from your server.

The cancel_url should restore the cart or order so the customer can try again. A canceled return does not prove that no transfer occurred, so keep payment reconciliation on the server.

5. Fulfill from a signed event

Verify payment_intent.succeeded in your webhook handler, match it to the server-authored metadata.order_id, and process the order idempotently. See Fulfill orders with webhooks.

When to use embedded checkout instead

Use embedded checkout when payment should remain inside your product, you need SDK lifecycle events, or you want to coordinate checkout with an existing in-page flow. The server-owned order and webhook fulfillment model stays the same.

On this page

API Workbench

Full Explorer

Open in new tab