docs
IntegrateCheckout Session

Advanced configuration

Submit button text, locale, branding, payment-method restrictions, promotion codes, fees, expiration, and metadata. Everything else you can set on a Checkout Session.

The other Checkout Session sub-pages cover the load-bearing fields: line items, the customer, what happens after payment. This page is the catch-all for the rest: how the page reads (submitType, locale, brandingSettings), what payment methods show (paymentMethodTypes, paymentMethodConfigurationId), what's added to the bill (feeConfig, discounts), how long the session stays open (expiresAfterMinutes), and the freeform key-value store you can attach (metadata).

Every field below is optional. Defaults come from your merchant settings or system defaults; sending nothing here is fine.

Submit button text

submitType controls the label on the pay button at the bottom of the hosted form. Default is pay.

ValueButton label
payPay
subscribeSubscribe
bookBook
donateDonate

Use donate for fundraising pages, book for reservations or appointments, subscribe for any recurring sale framing. The default pay covers everything else.

submitType is rejected when uiMode: "custom" (Elements). In that mode you build your own button. It's also locked at session creation: PATCH doesn't accept it.

Locale

locale controls the language of the hosted checkout and the card-form iframe. Two values today.

ValueLanguage
enEnglish
arArabic

Resolution at render time: the value on the session wins, then your merchant default locale (set in dashboard settings), then English. The SDK's runtime locale parameter (Drop-in / Elements) overrides everything when the page renders inside an SDK iframe.

{ "locale": "ar" }

Branding

brandingSettings overrides the dashboard-level brand defaults for one session. Anything you set here wins; anything you omit falls back to the merchant default. Colors merge key by key, so a session can override primary without erasing the merchant's background.

{
  "brandingSettings": {
    "colorMode": "light",
    "borderStyle": "rounded",
    "spacing": "normal",
    "inputSize": "medium",
    "inputStyle": "outlined",
    "formLayout": "spacious",
    "fontFamily": "Inter, sans-serif",
    "colors": {
      "primary": "#635bff",
      "background": "#ffffff",
      "foreground": "#0a0a0a"
    }
  }
}

The shape:

FieldValuesPurpose
colorModelight, dark, system (default)Light vs dark vs follow the customer's OS preference.
borderStylerounded (default), sharp, pillCorner radius on inputs, buttons, cards.
spacingcondensed, normal (default), spaciousVertical density of the page.
inputSizesmall, medium (default), largeForm field height.
inputStyleflat, outlined (default), filledVisual treatment of inputs.
formLayoutcompact, spacious (default)Layout density for the form column.
fontFamilyCSS font-family valueOverride the page font. Up to 512 characters.
colorsObject of hex colors (see below)Brand colors. Hex only.

colors accepts the following keys, each a hex string (#RGB, #RGBA, #RRGGBB, or #RRGGBBAA; #0000 for transparent):

primary, primaryForeground, background, foreground, border, input, ring, muted, mutedForeground, accent, accentForeground, destructive.

Color values that aren't hex are rejected at session creation. rgb(...), named colors, and CSS variables aren't accepted.

For the merchant-side branding setup (logo, business name, favicon), see Settings → Branding in the dashboard. Those fields aren't overridable per session.

Payment methods

By default, every payment method you've enabled on your merchant account is offered to the customer. Two ways to narrow the list per session.

FieldUse it when
paymentMethodTypesYou want a one-off list for this session: ["card", "valu"].
paymentMethodConfigurationIdYou've saved a named configuration in the dashboard and want to reference it across many sessions.

The two are mutually exclusive: send one or the other, never both. Sending neither uses your merchant's default configuration.

// Restrict this session to card and Valu only
{ "paymentMethodTypes": ["card", "valu"] }

Sending a method that isn't enabled on your account is rejected with a clear error at session create. The session response carries the resolved paymentMethodTypes array with the display name, category, refund support, and any min/max amount limits XPay will enforce, so you don't need to maintain that mapping yourself.

The values you can pass in paymentMethodTypes:

ValueMethod
cardCredit and debit cards
valu, sympl, tabby, tamaraBNPL providers
fawry, amanCash-collection networks
vodafone_cash, etisalat_cash, orange_cash, we_pay, instapayMobile wallets
apple_pay, google_pay, samsung_payWallet pay buttons
bank_transferDirect bank transfer
cash_on_deliveryCash on delivery

Whether each value actually appears at checkout depends on whether you've enabled it on your merchant account and whether the session amount falls within the method's processor limits.

Promotion codes and discounts

Two related fields. Both work with CouponAPI records you've created in the dashboard.

allowPromotionCodes (boolean, default false) shows an "Add promotion code" input on the hosted form. Customers type a promo code, the page validates it server-side, and the discount applies to the session totals immediately.

discounts (array, max 1) pre-applies a coupon or promotion code. Use this for personalized links or one-off discount campaigns where you don't want the customer to type anything.

// Customer enters their own code
{ "allowPromotionCodes": true }

// You apply a specific coupon
{ "discounts": [{ "coupon": "coupon_test_AbC123" }] }

// Or a specific promotion code
{ "discounts": [{ "promotionCode": "promo_test_xyz789" }] }

Either coupon or promotionCode per entry, never both. The session response carries the applied discount (with the coupon snapshot) under discounts[], and totalDetails.amountDiscount reflects what came off.

Two restrictions worth knowing:

  • Custom-amount lines reject discounts. A session with a CUSTOM-type line item can't combine with allowPromotionCodes or discounts. The customer chose the amount; layering a coupon breaks the contract.
  • Max one discount per session. The current API rejects a second.

For the full coupon and promotion code surface (durations, redemption limits, customer restrictions), see the dashboard's Catalog → Coupons page.

Fees and VAT pass-through

In compliance with regulations, fee pass-through (feesPassThrough: true) is gated on XPay approval. Contact your account manager to enable it on your account before using this setting.

feeConfig overrides your merchant-default fee handling for a single session. Three fields.

{
  "feeConfig": {
    "feesPassThrough": true,
    "vatCollectionEnabled": true,
    "vatCollectionRate": 1400
  }
}
FieldEffect
feesPassThroughWhen true, XPay's platform fee is added on top of the line-item totals so the customer pays it instead of you. When false (default), the fee comes out of the merchant payout.
vatCollectionEnabledWhen true, your product VAT is added on top so the customer pays it. The amount is settled to you and tracked separately in your balance.
vatCollectionRateVAT rate in basis points. 1400 = 14%. Required when vatCollectionEnabled is true. Range 0 to 10000.

Resolution: the session's feeConfig wins, then your merchant default fee config (set in dashboard fee settings), then the system default (no pass-through, no VAT). The session response carries a resolved feeConfig object with a source field telling you which level provided the values.

When feesPassThrough or vatCollectionEnabled is on, the session response also carries a fees object with the exact platform fee amount, percentage, and (for cards) BIN-aware breakdown. That's what you'd display in your own UI if you wanted to surface platform fee or VAT as separate line items.

Expiration

expiresAfterMinutes controls how long the session stays open before XPay marks it expired. Default 1440 (24 hours). Minimum 30. Locked at creation; PATCH doesn't accept it.

{ "expiresAfterMinutes": 60 }

When the timer runs out, the session's status flips to expired, the hosted page shows a terminal "you're all done here" state, and a checkout.session.expired webhook fires. You can also expire a session early with POST /checkout/sessions/:id/expire (covered in Overview → Expiration).

Metadata

metadata is a freeform key-value map you attach to the session. XPay stores it verbatim and never reads it. It travels with the session everywhere it goes.

{
  "metadata": {
    "user_id": "u_42",
    "order_id": "ord_193",
    "campaign": "spring-sale"
  }
}

Where it shows up:

  • On the session retrieve response (GET /checkout/sessions/:id).
  • On the checkout.session.completed webhook payload, in data.object.metadata.
  • Forwarded to the Payment Intent created at payment time, so it's also on paymentIntent.metadata and on every Charge under that PI.

Use it to thread your own IDs through the payment flow. Most useful pattern: set metadata.user_id so your webhook handler knows which of your users paid without joining tables.

Keep values to strings. Don't put PII or secrets here.

Where to next

On this page