Node SDK
Create Checkout Sessions, manage payment resources and verify webhooks on your server.
Use @paybytoken/node in trusted server code. It provides typed access to Checkout Sessions,
Payment Intents, Payment Requests, customer deposits and withdrawals, refunds, merchant balances,
payouts, events, webhook endpoints and private-beta Paybytoken Pay handoffs.
Install
pnpm add @paybytoken/nodeInitialize the client
import Paybytoken from '@paybytoken/node'
const paybytoken = new Paybytoken(
process.env.PAYBYTOKEN_SECRET_KEY!,
)Use a test key during development and a live key only in your production secret store.
When one order can offer stablecoin, card, Apple Pay or Google Pay, configure the independent Payments Router credential as well:
const paybytoken = new Paybytoken(process.env.PAYBYTOKEN_SECRET_KEY!, {
payments: {
apiKey: process.env.PAYBYTOKEN_PAYMENTS_API_KEY!,
baseUrl: 'https://payments-api.paybytoken.io',
},
})Core and Payments credentials are not interchangeable. The Payments URL has no version suffix;
the SDK uses /v2/payments for Router resources. See
Hosted Router checkout.
The default API base is https://api-prod.paybytoken.io/api/v1 and the default request timeout is
10 seconds. Override them only for an approved test deployment:
const paybytoken = new Paybytoken(process.env.PAYBYTOKEN_SECRET_KEY!, {
baseUrl:
process.env.PAYBYTOKEN_API_BASE_URL ?? 'https://api-prod.paybytoken.io/api/v1',
timeout: 15_000,
})Create a Checkout Session
const session = await paybytoken.checkoutSessions.create({
currency: 'usd',
line_items: [
{
quantity: 1,
unit_amount: '50.00',
product_data: {
name: 'Account balance top-up',
},
},
],
supported_tokens: [
{ currency: 'USDC', chain: 'base' },
{ currency: 'USDC', chain: 'ethereum' },
],
success_url: 'https://shop.example.com/order/success',
cancel_url: 'https://shop.example.com/cart',
})Hosted checkout is the default. Redirect the customer to session.url.
For embedded checkout, set ui_mode: 'embedded' and provide the exact allowed_origin. For a
merchant-owned interface, set ui_mode: 'custom' and confirm the selected token from your server.
Confirm custom checkout
const instructions = await paybytoken.checkoutSessions.confirm(
session.id,
{ selected_token_id: selectedTokenId },
session.csrf_token!,
)Keep the CSRF token on your server. Do not accept a price, destination address, contract or atomic amount from browser input.
Create a multi-method 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' }],
metadata: { order_id: 'order_123' },
},
'create-order_123',
)Redirect to created.checkout_url for hosted checkout. Router selects a merchant- and mode-scoped
provider connection; your server and browser choose only an option_id.
After payment, keep using the Router Payment resource:
const operations = await paybytoken.payments.getOperations(created.payment.id)
if (operations.payment.status === 'succeeded') {
await paybytoken.payments.createRefund(
operations.payment.id,
{ amount: '10.00' },
`refund:${operations.payment.id}:support-case-42`,
)
}
const reconciliation = await paybytoken.payments.listReconciliation({ limit: 100 })Use payments.sync(paymentId) only to reconcile uncertain provider state. It is not a replacement
for webhook-driven fulfillment.
Configure stablecoin checkout
const current = await paybytoken.paymentMethodConfigurations.getDefault()
await paybytoken.paymentMethodConfigurations.updateDefault({
if_version: current.version,
stablecoin: {
...current.stablecoin,
wallets: { browser_wallet: true, manual_transfer: true },
tokens: [{ currency: 'USDC', chain: 'base' }],
},
})Every new Checkout Session snapshots the resolved version. Its payment_method_options field is
the authoritative contract for hosted, embedded and custom presentation.
Verify a webhook
const event = paybytoken.webhookEvents.constructEvent(
rawBody,
signature,
process.env.PAYBYTOKEN_WEBHOOK_SECRET!,
)Verify the exact raw body before parsing or modifying it. Fulfill only after a verified terminal event and make event processing idempotent.
Create a Payment Request
const request = await paybytoken.paymentRequests.create(
{
title: 'August services',
customer_email: 'alex@example.com',
currency: 'usd',
line_items: [{ name: 'Consulting', quantity: 1, unit_amount: '50.00' }],
supported_tokens: [{ currency: 'USDC', chain: 'base' }],
},
{ idempotencyKey: 'payment-request:PO-1042' },
)
const finalized = await paybytoken.paymentRequests.finalize(request.id, {
idempotencyKey: 'payment-request:PO-1042:finalize',
})Use send, listPayments, listDeliveries, timeline, listAllPayments, and reconciliation
for the complete receivables workflow. See Request a payment.
Customer balances and refunds
const customer = await paybytoken.customers.create(
{ reference: 'merchant_customer_8' },
{ idempotencyKey: 'customer:merchant_customer_8' },
)
const account = await paybytoken.customerDepositAccounts.create(
customer.id,
{
address_family: 'evm',
initial_address: { chains: ['base'] },
},
{ idempotencyKey: `deposit-account:${customer.id}` },
)
const balances = await paybytoken.customerBalances.list(customer.id)Use depositAssets.list() and withdrawalAssets.list() instead of hard-coding asset policies.
The SDK also exposes customerDeposits, customerWithdrawals, refunds, and
consumerPaymentSessions. See Build customer balances and
Paybytoken Pay.
Handle API errors
import Paybytoken, { PaybytokenError } from '@paybytoken/node'
try {
await paybytoken.checkoutSessions.get('chk_missing')
} catch (error) {
if (error instanceof PaybytokenError) {
console.error(error.code, error.type, error.message)
}
throw error
}code is the API status when available and type is the machine-readable error category. Do not
match business logic against message. Network failures and timeouts also surface as
PaybytokenError; reconcile a mutation before deciding whether to retry it.
Continue with Get started, Custom checkout, or Fulfill orders with webhooks.
Did this page answer your question?
Your feedback helps us improve the integration path.