Checkout Sessions API

Create and manage checkout sessions for one-time payments and subscriptions.

Create a Checkout Session

POST/api/v1/checkout-sessions

Auth: Server key required

Request Body

{
  "amount": 99.99,
  "currency": "USD",
  "mode": "embedded",
  "paymentType": "oneTime",
  "successUrl": "https://yoursite.com/success?session_id={CHECKOUT_SESSION_ID}",
  "cancelUrl": "https://yoursite.com/cancel",
  "customer": {
    "email": "[email protected]",
    "name": "Jane Doe",
    "phone": "+1234567890"
  },
  "lineItems": [
    {
      "name": "Pro Plan",
      "quantity": 1,
      "unitAmount": 99.99,
      "description": "Monthly subscription"
    }
  ],
  "metadata": {
    "orderId": "order_12345"
  },
  "expiresAt": "2025-01-16T10:30:00Z",
  "allowSavedCards": true,
  "enableClickToPay": true
}

Response

{
  "id": "cs_live_abc123",
  "object": "checkout_session",
  "status": "open",
  "amount": 99.99,
  "currency": "USD",
  "mode": "embedded",
  "paymentType": "oneTime",
  "clientSecret": "cs_live_abc123_secret_xyz789",
  "url": null,
  "successUrl": "https://yoursite.com/success?session_id=cs_live_abc123",
  "cancelUrl": "https://yoursite.com/cancel",
  "customer": {
    "email": "[email protected]",
    "name": "Jane Doe"
  },
  "paymentStatus": "unpaid",
  "expiresAt": "2025-01-16T10:30:00Z",
  "createdAt": "2025-01-15T10:30:00Z"
}

Return URL placeholder

Put {CHECKOUT_SESSION_ID} anywhere in successUrl or cancelUrl (as-is or percent-encoded). It is replaced with the session id when the session is created, so the hosted page redirects to, and the session reports, the final URL.

Paying an existing invoice

To collect an invoice you already issued, pass invoiceId (its numeric id) or invoiceReference (the reference code from its pay link, not the display invoice number). The session charges that invoice instead of creating one.

{
  "invoiceReference": "INV-7F3K2Q",
  "mode": "hosted",
  "paymentType": "oneTime",
  "successUrl": "https://yoursite.com/paid?session_id={CHECKOUT_SESSION_ID}"
}
  • Only with paymentType: "oneTime". Sending both fields, or lineItems, is a validation_error; description is ignored.
  • Amount, currency and payment options come from the invoice (amount = its total due). If you also send amount, currency or paymentOptionGroupId, they must match.
  • The invoice must be yours and in the same mode as your key; otherwise 404 invoice_not_found.
  • A paid, cancelled, rejected, expired, draft or zero-balance invoice is refused with invoice_not_payable.
  • While a session on the invoice is still open, creating another returns that same session.
  • If the session expires or is cancelled, your invoice is left as it was and can be paid later.
  • checkout.session.completed carries invoiceId and invoiceReference.

Retrieve a Checkout Session

GET/api/v1/checkout-sessions/{id}

Auth: Publishable key + client secret, the session's client secret alone (hosted page), or a server key

Response

{
  "sessionId": "cs_live_abc123",
  "status": "completed",
  "amount": 99.99,
  "currency": "USD",
  "customerEmail": "[email protected]",
  "allowGuestSavedCards": false,
  "paymentType": "one_time",
  "mode": "hosted",
  "expiresAt": "2025-01-15T11:00:00Z",
  "merchantName": "Yard Shop",
  "merchantLogoUrl": "https://cdn.example.com/logo.png",
  "allowedPaymentMethods": null,
  "successUrl": "https://yoursite.com/success",
  "cancelUrl": "https://yoursite.com/cancel"
}

Statuses: created, payment_pending, processing, completed, expired, cancelled.

Confirm a Checkout Session

POST/api/v1/checkout-sessions/{id}/confirm

Auth: Publishable key + client secret

Request Body

{
  "paymentMethodId": "pm_card_visa_1234",
  "returnUrl": "https://yoursite.com/complete"
}

Response

{
  "id": "cs_live_abc123",
  "object": "checkout_session",
  "status": "complete",
  "paymentStatus": "paid",
  "paymentResult": {
    "id": "pay_xyz789",
    "status": "succeeded",
    "amount": 99.99,
    "currency": "USD"
  }
}

Tokenize Card

POST/api/v1/checkout-sessions/{id}/tokenize

Auth: Publishable key + client secret

Request Body

{
  "cardNumber": "4242424242424242",
  "expiryMonth": 12,
  "expiryYear": 2027,
  "cvc": "123",
  "billingDetails": {
    "name": "Jane Doe",
    "email": "[email protected]"
  }
}

Response

{
  "id": "pm_card_visa_1234",
  "object": "payment_method",
  "type": "card",
  "card": {
    "brand": "visa",
    "last4": "4242",
    "expiryMonth": 12,
    "expiryYear": 2027
  },
  "createdAt": "2025-01-15T10:31:00Z"
}

List Saved Cards

GET/api/v1/checkout-sessions/{id}/saved-cards

Auth: Publishable key + client secret

Response

{
  "object": "list",
  "data": [
    {
      "id": "pm_card_visa_1234",
      "card": {
        "brand": "visa",
        "last4": "4242",
        "expiryMonth": 12,
        "expiryYear": 2027
      },
      "isDefault": true
    },
    {
      "id": "pm_card_mc_5678",
      "card": {
        "brand": "mastercard",
        "last4": "8210",
        "expiryMonth": 6,
        "expiryYear": 2026
      },
      "isDefault": false
    }
  ]
}

Verify Saved Card

POST/api/v1/checkout-sessions/{id}/saved-cards/verify

Auth: Publishable key + client secret

Initiates OTP verification for a saved card before using it for payment.

Request Body

{
  "paymentMethodId": "pm_card_visa_1234"
}

Response

{
  "verificationId": "ver_abc123",
  "status": "otp_sent",
  "maskedPhone": "+1***4567",
  "expiresAt": "2025-01-15T10:35:00Z"
}

Confirm Saved Card OTP

POST/api/v1/checkout-sessions/{id}/saved-cards/confirm-otp

Auth: Publishable key + client secret

Request Body

{
  "verificationId": "ver_abc123",
  "otp": "123456"
}

Response

{
  "verified": true,
  "paymentMethodId": "pm_card_visa_1234"
}

Refund a Checkout Session

POST/api/v1/checkout-sessions/{id}/refund

Auth: Server key with the checkout.session.refund scope

Refunds the payment behind a completed session. Only the merchant that owns the session, in the same mode as the key, can refund it; any other session is a 404. Only full refunds are supported: omit amount or send the full amount paid — any other amount is refused with partial_refund_not_supported. Card (MPGS) payments and wallet QR payments can be refunded until they are settled to your balance. A wallet refund the wallet has accepted but not yet finished comes back with status pending_reversal and completes on its own; the payment.refunded webhook tells you when. Repeating a refund returns alreadyRefunded: true without contacting the processor.

Request Body

{
  "amount": 99.99,
  "reason": "Customer returned the item"
}

Response

{
  "sessionId": "cs_live_abc123",
  "paymentId": 4821,
  "paymentReferenceNumber": "PAY-4821",
  "status": "refunded",
  "amount": 99.99,
  "currency": "USD",
  "alreadyRefunded": false
}

Errors: partial_refund_not_supported (400), payment_not_refundable (400, not yet captured, already settled, or an unsupported rail), nothing_to_refund (409, the session has no payment). A payment.refunded webhook follows a successful refund.

Cancel a Checkout Session

POST/api/v1/checkout-sessions/{id}/cancel

Auth: Server key required

Response

{
  "id": "cs_live_abc123",
  "object": "checkout_session",
  "status": "expired",
  "paymentStatus": "unpaid",
  "cancelledAt": "2025-01-15T11:00:00Z"
}

Withdraw a Wallet QR Code

POST/api/v1/checkout-sessions/{id}/withdraw-qr

Auth: Publishable key + client secret, or the client secret alone (hosted page). Scope checkout.session.confirm.

Takes back the wallet QR code (JN Pay / Jam-Dex) a confirm issued, so the payer can choose another payment method. The session stays open. Call it before showing your method picker again: a code left live could be paid on top of whatever the payer picks next. No request body.

Response

{
  "sessionId": "cs_live_abc123",
  "outcome": "withdrawn",
  "status": "payment_pending"
}
  • withdrawn: the code can no longer be paid; the session is back to payment_pending. Confirm again with another option.
  • already_paid: the code had been paid (or the wallet refused to withdraw it because it was); the session is completed. Show the payment as done.
  • failed: the code could not be withdrawn and may still be paid. Nothing changed; keep waiting on it and try again later. message explains, in words you can show the payer.

A cancelled or expired session is refused (400); its codes were already withdrawn.

Get Session Status

GET/api/v1/checkout-sessions/{id}/status

Auth: Publishable key + client secret

Lightweight endpoint for polling session status from the client.

Response

{
  "status": "completed"
}

SRC Lookup (Click to Pay)

POST/api/v1/checkout-sessions/{id}/src/lookup

Auth: Publishable key + client secret

Look up whether the customer is enrolled in Click to Pay (Secure Remote Commerce).

Request Body

{
  "email": "[email protected]"
}

Response

{
  "enrolled": true,
  "cards": [
    {
      "srcCardId": "src_card_abc123",
      "brand": "visa",
      "last4": "4242",
      "expiryMonth": 12,
      "expiryYear": 2027,
      "artUri": "https://cdn.quickpay.com/card-art/visa-4242.png"
    }
  ]
}

SRC Authenticate (Click to Pay)

POST/api/v1/checkout-sessions/{id}/src/authenticate

Auth: Publishable key + client secret

Authenticate a Click to Pay card selection and obtain a payment token.

Request Body

{
  "srcCardId": "src_card_abc123",
  "validationData": "otp_or_biometric_token"
}

Response

{
  "paymentMethodId": "pm_src_visa_4242",
  "token": "tok_src_abc123",
  "card": {
    "brand": "visa",
    "last4": "4242"
  },
  "authenticated": true
}