Hosted Router checkout
Create one Payment and redirect the customer to a Paybytoken-hosted multi-method checkout.
Hosted checkout is the recommended Router integration. Your server creates the Payment, then
redirects the customer to its short-lived checkout_url. Paybytoken owns option selection,
provider actions, responsive UI and return handling.
Configure the server SDK
Configure the Core and Payments credentials separately. The Payments base URL has no version
suffix because the SDK adds /v2 for Router resources.
import Paybytoken from '@paybytoken/node'
const paybytoken = new Paybytoken(process.env.PAYBYTOKEN_SECRET_KEY!, {
payments: {
apiKey: process.env.PAYBYTOKEN_PAYMENTS_API_KEY!,
baseUrl: 'https://payments-api.paybytoken.io',
},
})Create the Payment
const created = await paybytoken.payments.create(
{
amount: { value: '50.00', currency: 'USD' },
options: ['stablecoin', 'card', 'apple_pay', 'google_pay'],
line_items: [
{ name: 'Starter plan', quantity: 1, unit_amount: '50.00' },
],
checkout: {
merchant_name: 'Example Store',
order_description: 'Order #123',
success_url: 'https://shop.example/orders/order_123/success',
cancel_url: 'https://shop.example/orders/order_123',
brand_color: '#163300',
accent_color: '#9fe870',
},
metadata: { order_id: 'order_123' },
},
'create-order_123',
)
return Response.redirect(created.checkout_url!, 303)Use a stable idempotency key for the logical create operation. Do not generate a new key after an ambiguous timeout unless you intend to create a second Payment.
checkout_url contains a customer capability. Do not write it to analytics, support logs or a
different customer's page.
Verify completion
export async function POST(request: Request) {
const rawBody = await request.text()
const signature = request.headers.get('paybytoken-signature') ?? ''
const event = paybytoken.paymentsWebhooks.constructEvent(
rawBody,
signature,
[
process.env.PAYBYTOKEN_PAYMENTS_WEBHOOK_SECRET!,
process.env.PAYBYTOKEN_PAYMENTS_PREVIOUS_WEBHOOK_SECRET ?? '',
],
)
if (event.type === 'payment.succeeded') {
await fulfillOrderOnce(event.data.payment.metadata?.order_id, event.id)
}
return new Response(null, { status: 204 })
}Preserve the exact raw request body, accept overlapping current and previous secrets during rotation, and deduplicate by event ID.
Roll out options safely
Start with stablecoin. Add card, apple_pay and google_pay only after the merchant's Stripe
connection is ready for that mode. Test and live provider connections are isolated; readiness in
test mode does not enable a live option.
Read Payments Router for the resource model and Node SDK for the complete server client.
Did this page answer your question?
Your feedback helps us improve the integration path.