Getting Started

Quick Start

Process your first payment with CommerceJS in 5 minutes.

This guide walks through creating a checkout session, submitting a payment, and handling the result. You will use the CheckoutSession state machine with the Tap payment provider.

No external platform? Use the built-in @commercejs/platform engine instead. See Platform Quick Start below.

Create a Checkout Session

The CheckoutSession class manages the entire checkout flow. Pass it a payment provider and the order details:

server/checkout.ts
import { CheckoutSession } from '@commercejs/checkout'
import { TapPaymentProvider } from '@commercejs/payment-tap'

const provider = new TapPaymentProvider({
  secretKey: process.env.TAP_SECRET_KEY!,
  baseUrl: 'https://api.tap.company/v2',
})

const session = new CheckoutSession({
  provider,
  amount: 99.999,
  currency: 'BHD',
  orderId: 'order-001',
  returnUrl: 'https://myapp.com/checkout/confirm',
})

Set Customer Info

The session follows a state machine. Set customer information to advance from idle to info:

server/checkout.ts
session.setCustomerInfo({
  email: 'customer@example.com',
  firstName: 'Ahmed',
  lastName: 'Al-Rashid',
  phone: '+97312345678',
})

Set Shipping Address

Provide a shipping address to advance to shipping:

server/checkout.ts
session.setShippingAddress({
  street: '123 Main Street',
  street2: null,
  city: 'Manama',
  state: null,
  country: 'BH',
  postalCode: '1234',
  district: null,
  nationalAddress: null,
})

Submit Payment

Submit a payment with a tokenized card. The provider creates a charge with Tap:

server/checkout.ts
const paymentSession = await session.submitPayment({
  sourceToken: 'tok_card_xxxxx', // from Tap Card SDK tokenization
})

if (paymentSession.redirectUrl) {
  // Customer needs to complete 3DS verification
  // Redirect them to paymentSession.redirectUrl
}
Most card payments require 3DS authentication. The redirectUrl takes the customer to Tap's 3DS page, which redirects back to your returnUrl after verification.

Confirm Payment

After the customer returns from 3DS, confirm the payment:

server/confirm.ts
const chargeId = getQueryParam('tap_id') // from the redirect URL

const confirmed = await session.confirmPayment(chargeId)

if (session.state === 'complete') {
  // Payment captured successfully
  console.log('Order paid!', confirmed)
}

Handle Webhooks

For asynchronous payment results, Tap sends a webhook to your server. The handleWebhookUpdate method updates the session state from trusted server-side events:

server/webhook.ts
import { WebhookVerifier } from '@commercejs/webhook-verifier'
import { tap as tapConfig } from '@commercejs/webhook-verifier/configs'

const verifier = new WebhookVerifier({
  ...tapConfig,
  secretKey: process.env.TAP_SECRET_KEY!,
})

// Verify the webhook signature
const result = verifier.verify(body, headers)
if (!result.isValid) {
  throw new Error('Invalid webhook signature')
}

// Update the session
session.handleWebhookUpdate({
  id: body.id,
  providerId: 'tap',
  status: body.status === 'CAPTURED' ? 'captured' : 'failed',
  amount: body.amount,
  currency: body.currency,
  redirectUrl: null,
  createdAt: body.created,
})

State Machine Summary

The checkout session follows this state flow:

Checkout Flow

State Machine

Information
👤 Collect Info
📦 Shipping Details
Payment
💳 Process Payment
🔒 Verify & Capture
Result
✅ Order Complete
❌ Payment Failed

Failed → Retry → Payment

Flow:InfoPaymentComplete|Failed
Collection
Payment
Success
Failure
Documentation Asset // COMMERCE_JS_FLOW_01