Checkout
Drop-in multi-step checkout UI for Next.js apps built on the Sazito SDK.
Overview
@sazito/checkout is a ready-made, fully typed checkout flow with built-in state management. It handles:
- Cart review (edit quantities, remove items, apply discount codes)
- Shipping address form with region / city cascading selects
- Shipping method selection (multiple groups supported)
- Payment method selection and gateway redirect
- Post-payment result screen (success, pending, failed, stock violated) with order code, public ID, shipping methods, purchased-item details, and totals
- Automatic pending-payment polling after gateway return
Steps run in order: cart → shipping → payment → result
The payment step is the last interactive step: its CTA (انجام پرداخت / "Pay now") finalizes the order directly — there is no separate review step. Payment methods show the default method first, online methods next, and non-default pay-on-delivery/card-to-card choices last. The order-details action on a successful result opens in a new tab.
Installation
pnpm add @sazito/client-sdk @sazito/checkout react@18 react-dom@18The checkout package requires Node.js 18 or newer. It ships ESM and CommonJS builds, bundled TypeScript declarations, and server-safe entry points:
| Entry point | Use case |
|---|---|
@sazito/checkout/core | Framework-independent engine, state, actions, selectors, events, and formatters. |
@sazito/checkout/react | CheckoutProvider, SazitoProvider, and checkout hooks. |
@sazito/checkout/next | Drop-in checkout page, rendered UI, hooks, and customizable primitives. |
@sazito/checkout/next/server | Next.js-compatible GET/POST gateway callback handlers. |
@sazito/checkout/server | Framework-neutral Web Request/Response callback handlers. |
@sazito/checkout/styles.css | Self-contained RTL/LTR styles and theme variables. |
Import the stylesheet once — typically in your root layout:
import '@sazito/checkout/styles.css';Next.js setup
1. Add environment variables
NEXT_PUBLIC_SAZITO_DOMAIN=shop.example.com
SAZITO_STORE_DOMAIN=shop.example.com2. Add the SDK provider
// app/providers.tsx
'use client';
import { createSazitoClient } from '@sazito/client-sdk';
import { SazitoProvider } from '@sazito/checkout/next';
const client = createSazitoClient({
domain: process.env.NEXT_PUBLIC_SAZITO_DOMAIN!,
});
export function Providers({ children }: { children: React.ReactNode }) {
return <SazitoProvider client={client}>{children}</SazitoProvider>;
}Import the styles and provider once:
// app/layout.tsx
import '@sazito/checkout/styles.css';
import { Providers } from './providers';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="fa" dir="rtl">
<body><Providers>{children}</Providers></body>
</html>
);
}3. Add the checkout page
// app/checkout/page.tsx
'use client';
import { SazitoCheckoutPage } from '@sazito/checkout/next';
export default function CheckoutPage() {
return (
<SazitoCheckoutPage
credentials={{ cart: { identifier: '<cart-identifier>' } }}
config={{ locale: 'fa', continueShoppingUrl: '/' }}
/>
);
}Replace <cart-identifier> with the identifier created through client.cart.
4. Add the payment callback route
// app/checkout/[...callback]/route.ts
import { SazitoCheckout } from '@sazito/checkout/next/server';
export const { GET, POST } = SazitoCheckout({
domain: process.env.SAZITO_STORE_DOMAIN!,
checkoutPath: '/checkout',
}).handlers;That is all the host needs for gateway returns. Keep both GET and POST:
different gateways use different callback methods. The SDK validates the
callback, verifies the payment on the server, redirects back to /checkout,
and shows the final result. Use a Route Handler here, not a Server Action.
5. Test the flow
- Open
/checkoutand complete a test payment. - Confirm the gateway return reaches the catch-all route.
- Confirm the browser returns to
/checkoutand displays the payment result.
Props reference
SazitoProvider
Wraps the app once and exposes the existing SDK client to every checkout below
it. Create the client with createSazitoClient; the provider does not create a
client from a domain.
| Prop | Type | Description |
|---|---|---|
client | SazitoClient | Required pre-built SDK client. Checkout reuses this client's credentials and configuration. |
children | ReactNode | Application or checkout subtree. |
SazitoCheckoutPage
| Prop | Type | Description |
|---|---|---|
credentials | CheckoutCredentials | Cart (and optionally invoice) identifiers to attach to. |
config | CheckoutConfig | Locale, theme, URLs, event hook, behaviour flags. |
paymentReturn | CheckoutPaymentReturn | Optional callback data for custom integrations. The server handler setup does not require this prop. |
paymentReturnParams | Record<string, string> | Legacy query-only callback parameters. The server handler setup does not require this prop. |
className | string | Extra class on the root element. |
getOrderDetailsUrl | (order: CheckoutOrder) => string | null | Build the result screen's order-details link using your theme's routes and host. Return null to hide it. |
renderNextButton | (props: RenderButtonProps) => ReactNode | Replace the continue / next button across all steps. |
renderBackButton | (props: RenderButtonProps) => ReactNode | Replace the back button across all steps. |
emptyCart | EmptyCartOptions | Customize the built-in empty state's title, description, icon, action label, or action URL. |
renderEmptyCart | (props: RenderEmptyCartProps) => ReactNode | Replace the empty-cart screen. Receives the resolved content and continueShoppingUrl. |
renderResult | (props: RenderResultProps) => ReactNode | Replace the post-payment result screen. Receives the result, status, finalized order, continue-shopping URL, and retry action. |
CheckoutCredentials
interface CheckoutCredentials {
cart?: { id?: number; identifier: string };
invoice?: { id: number; identifier: string };
payment?: { id: number; identifier: string };
}Typically only cart.identifier is needed. Supply invoice to re-attach to an
already-created invoice. Payment credentials are restored automatically after
the server callback handler redirects to checkout.
CheckoutConfig
| Field | Type | Default | Description |
|---|---|---|---|
locale | 'fa' | 'en' | 'fa' | UI language. Controls all labels, RTL/LTR layout, and number formatting. |
direction | 'rtl' | 'ltr' | derived from locale | Override text direction explicitly. |
theme | CheckoutTheme | — | Visual overrides — see Theming. |
continueShoppingUrl | string | — | URL for the back button on the cart step and the "continue shopping" link on the result screen. |
returnUrl | string | — | Reserved for gateways that support a caller-provided return URL. Legacy Sazito callbacks use their generated nested result path. |
pollIntervalMs | number | 15000 | How often (ms) to poll for a pending payment result after gateway return. |
debug | boolean | false | Log detailed, correlated payment-verification parsing and checkout state transitions. Sensitive values are redacted. |
currencyLabel | string | locale default | Override the currency unit label (e.g. 'تومان'). |
onEvent | (event: CheckoutEvent) => void | — | Analytics hook — called for every checkout lifecycle event. See Analytics. |
Theming
All visual tokens are CSS custom properties. Pass a theme object to override them:
config={{
theme: {
accent: '#7c3aed', // primary colour — buttons, active states, selected rows
accentForeground: '#ffffff', // text rendered on top of accent
accentSoft: '#ede9fe', // subtle accent tint — hover, selection background
background: '#ffffff', // page background
foreground: '#0f172a', // primary text
muted: '#f1f5f9', // muted surface background
mutedForeground: '#64748b', // secondary text
border: '#e2e8f0', // borders and dividers
card: '#ffffff', // form, product card, shipping card background
summaryBackground: '#f8fafc', // order-summary sidebar background
danger: '#ef4444', // error and destructive states
success: '#22c55e', // success and completed states
successForeground: '#ffffff', // content on solid success surfaces
logoBackground: '#ffffff', // plate behind shipping-provider logos
shippingNeutral: '#f1f5f9', // fallback surface for white shipping colors
shippingNeutralForeground: '#475569', // content on that neutral surface
radius: 12, // base border-radius in px (scaled per element)
fontFamily: 'inherit', // font — defaults to host page font
},
}}Reuse your application's design tokens
Theme colors and fontFamily accept any valid CSS value, including references
to variables already defined by the host application. This is the recommended
way to connect checkout to an existing design system:
<SazitoCheckoutPage
credentials={{ cart: { identifier: '<cart-identifier>' } }}
config={{
locale: 'fa',
theme: {
accent: 'var(--color-primary)',
accentForeground: 'var(--color-on-primary)',
accentSoft: 'var(--color-primary-soft)',
background: 'var(--color-background)',
foreground: 'var(--color-foreground)',
muted: 'var(--color-muted)',
mutedForeground: 'var(--color-muted-foreground)',
border: 'var(--color-border)',
card: 'var(--color-card)',
summaryBackground: 'var(--color-surface)',
danger: 'var(--color-danger)',
success: 'var(--color-success)',
successForeground: 'var(--color-on-success)',
logoBackground: 'var(--color-logo-plate)',
shippingNeutral: 'var(--color-muted)',
shippingNeutralForeground: 'var(--color-muted-foreground)',
fontFamily: 'var(--font-sans)',
radius: 12,
},
}}
/>CSS fallbacks work as usual—for example,
accent: 'var(--color-primary, #4f46e5)'. The host variables must be defined
on :root or another ancestor of the checkout. When a light/dark theme changes
their values, checkout updates automatically without a React rerender:
:root {
--color-primary: #6d28d9;
--color-on-primary: #ffffff;
--color-background: #ffffff;
--color-foreground: #18181b;
--color-card: #ffffff;
--color-border: #e4e4e7;
}
[data-theme='dark'] {
--color-background: #09090b;
--color-foreground: #fafafa;
--color-card: #111113;
--color-border: #27272a;
}CSS-only token mapping
For a stylesheet-driven integration, add a class to the checkout and map its
native variables. Import these overrides after @sazito/checkout/styles.css:
<SazitoCheckoutPage
className="store-checkout"
credentials={{ cart: { identifier: '<cart-identifier>' } }}
/>.szc-root.store-checkout {
--szc-accent: var(--color-primary);
--szc-accent-foreground: var(--color-on-primary);
--szc-bg: var(--color-background);
--szc-fg: var(--color-foreground);
--szc-muted: var(--color-muted);
--szc-muted-fg: var(--color-muted-foreground);
--szc-border: var(--color-border);
--szc-card: var(--color-card);
--szc-summary-bg: var(--color-surface);
--szc-danger: var(--color-danger);
--szc-success: var(--color-success);
--szc-font: var(--font-sans);
--szc-radius: var(--radius-lg);
}Do not set the same token through both approaches. Values supplied through
config.theme are written as inline --szc-* properties and take precedence
over ordinary stylesheet declarations. The CSS-only approach is also required
when radius must reference a CSS variable, because config.theme.radius
accepts a number in pixels.
Payment gateway return
Gateway callbacks use a nested URL such as:
/checkout/paymentinplaceresult/payment/304/identifier/6f8a717eb211f0839e522a5358932968The catch-all Route Handler from the setup section receives this URL. It parses
the GET or POST fields and verifies the payment. When the API returns
show_order, it carries that confirmed result to checkoutPath using a small
HTML response and tab-scoped storage. Checkout displays the original success
without calling process_payment_step again. If storage is unavailable, the
HTML response itself displays order confirmation. Other responses use a 303
redirect and a status read; pending results start polling automatically.
Optional server settings:
| Field | Default | Description |
|---|---|---|
checkoutPath | /checkout | Checkout result page. Locale-prefixed paths such as /fa/checkout are supported. |
maxCallbackBodyBytes | 65536 | Maximum accepted callback body size. |
gatewayResultMarkers | Built-in Sazito list | Override the accepted callback route names for a custom gateway. |
debug | false | Log server-side callback errors without exposing them to the browser. |
The response uses Cache-Control: no-store and Referrer-Policy: no-referrer.
Malformed callbacks are rejected before the payment API is called. After the
return is recognized, checkout removes the temporary payment parameters from
the browser URL.
Test the return flow with mock data
The documentation checkout includes local payment-result scenarios, so you can exercise verification without creating an order or contacting a payment gateway. Start the docs app and open the demo:
pnpm --dir docs devhttp://localhost:3000/checkout-demo?mockPayment=success-minimalYou can also change Payment result in the demo toolbar:
| Scenario | Expected result |
|---|---|
success-minimal | Success with only the required order identifiers. This protects against the former Invalid payment step result failure when totals are absent. |
success-full | Sanitized real payment-in-place show_order response with product, shipping, totals, receipt, and nullable fields. |
pending-success | Pending callback followed by a successful JSON status poll. |
failure | Gateway-declared payment failure. |
malformed | Incomplete show_order payload; this should remain a compact success instead of displaying a false failure. |
live | Normal checkout using the configured domain and cart identifier. |
Mock mode simulates payment verification and checkout finalization.
It also asserts that the initial callback is sent as
application/x-www-form-urlencoded with payment_identifier and
payload[RefId]; the pending poll must remain JSON. No real payment, cart, or
gateway redirect is performed.
Analytics
Pass onEvent to receive structured events at every step. Use it to send to any analytics provider:
config={{
onEvent(event) {
analytics.track(event.name, {
step: event.step,
value: event.value, // order total in Rials where applicable
...event.metadata,
timestamp: event.timestamp,
});
},
}}Event names
| Event | Fired when |
|---|---|
checkout_viewed | Checkout mounts |
step_viewed | User lands on a step |
address_submitted | Shipping address saved |
shipping_rate_selected | User picks a shipping method |
discount_applied | Discount code accepted |
discount_removed | Discount code removed |
payment_method_selected | User picks a payment gateway |
payment_initiated | Order placed, gateway redirect started |
payment_succeeded | Gateway return resolved as success |
payment_failed | Gateway return resolved as failed |
payment_pending | Gateway return resolved as pending (polling starts) |
Validation gates
The next button disables automatically — no configuration needed:
| Step | Disabled when |
|---|---|
| Cart | Cart is empty |
| Shipping | Shipping rates loaded but no rate selected (skipped for digital-only orders) |
| Payment | No payment methods available, or none selected |
Replacing the empty-cart screen
For copy and icon changes, keep the responsive built-in layout and pass
emptyCart:
<SazitoCheckoutPage
config={{ locale: 'fa', continueShoppingUrl: '/products' }}
emptyCart={{
title: 'هنوز چیزی انتخاب نکردهاید',
description: 'محصولات فروشگاه را ببینید و انتخابهای خود را به سبد اضافه کنید.',
actionLabel: 'مشاهده محصولات',
icon: <MyBagIcon />,
}}
/>Use renderEmptyCart when the storefront has its own empty-state component:
<SazitoCheckoutPage
credentials={{ cart: { identifier: '<cart-identifier>' } }}
config={{ locale: 'fa', continueShoppingUrl: '/products' }}
renderEmptyCart={({ continueShoppingUrl, title, description }) => (
<EmptyCart
actionHref={continueShoppingUrl ?? '/products'}
actionLabel="Browse products"
title={title}
description={description}
/>
)}
/>Customizing the order detail link
Set getOrderDetailsUrl on SazitoCheckoutPage (or SazitoCheckout) to use your
storefront's order detail route. The callback receives the completed order,
including id and orderIdentifier. Include both in the URL so the destination
can call client.orders.get(id, orderIdentifier).
'use client';
import { SazitoCheckoutPage } from '@sazito/checkout/next';
export function ThemeCheckout() {
return (
<SazitoCheckoutPage
config={{ locale: 'fa', continueShoppingUrl: '/fa/products' }}
getOrderDetailsUrl={(order) =>
`/fa/orders/${encodeURIComponent(String(order.id))}?identifier=${encodeURIComponent(order.orderIdentifier)}`
}
/>
);
}The returned URL is used as supplied: return a relative path for the current
host, or an absolute URL such as https://shop.example.com/fa/orders/... for a
different storefront host. Encode dynamic path and query values. Define the
callback in a Client Component in Next.js, inside the existing SazitoProvider.
Without this prop, checkout keeps /orderinfo/{id}/{identifier}, using the
origin of continueShoppingUrl when it is absolute. Returning null hides the
order-details action without falling back to that default. The link continues
to open in a new tab. No callback runs when the payment result has no order.
If you supply renderResult, your custom renderer owns its links.
Replacing the result screen
Use renderResult to replace the complete post-payment screen while keeping
the checkout engine's payment verification and pending polling:
import type { RenderResultProps } from '@sazito/checkout/next';
function StorefrontResult({
status,
order,
result,
continueShoppingUrl,
onRetry,
}: RenderResultProps) {
if (status === 'pending') return <PaymentVerification />;
if (status !== 'success') {
return (
<PaymentError message={result?.message} onRetry={onRetry} />
);
}
return (
<OrderSuccess
order={order}
continueHref={continueShoppingUrl ?? '/products'}
/>
);
}
<SazitoCheckoutPage
credentials={{ cart: { identifier: '<cart-identifier>' } }}
config={{ locale: 'fa', continueShoppingUrl: '/products' }}
renderResult={(props) => <StorefrontResult {...props} />}
/>onRetry returns the checkout to the payment step. order is populated when
the payment response includes valid order details; a terminal show_order
success may omit it while the order is still being finalized server-side.
RenderResultProps
| Prop | Type | Description |
|---|---|---|
result | CheckoutResult | null | Complete engine result. Includes the returned message and finalized order when available. It can be null during the initial resolving render. |
status | 'success' | 'failed' | 'pending' | 'stock_violated' | Normalized status. Defaults to pending until a result is resolved. |
order | CheckoutOrder | undefined | Convenience reference to result.order. Available for valid show_order and pending responses. |
continueShoppingUrl | string | undefined | Value configured through config.continueShoppingUrl. The custom renderer decides whether and how to navigate to it. |
onRetry | () => void | Clears the result view and returns to the payment step. Use for failed and stock_violated states. |
Supplying renderResult replaces only the result content; the checkout root,
direction, theme variables, stepper, and .szc-result-wrap layout container
remain mounted. The callback runs only while the active step is result.
Returning null intentionally leaves the result area empty.
The slot is also available when composing the React UI directly:
<CheckoutProvider client={sazito} credentials={credentials}>
<SazitoCheckout renderResult={(props) => <StorefrontResult {...props} />} />
</CheckoutProvider>Replacing action buttons
Use renderNextButton / renderBackButton to swap the built-in action buttons for components from your own design system. Both receive pre-computed checkout state. The next button renders under the order summary on desktop and inside the sticky bottom bar (next to the payable total) on mobile; the back button renders at the end of the step content.
import type { RenderButtonProps } from '@sazito/checkout/next';
<SazitoCheckoutPage
credentials={{ cart: { identifier: '<cart-identifier>' } }}
config={{ locale: 'fa' }}
renderNextButton={({ loading, disabled, onClick, children }) => (
<MyButton loading={loading} disabled={disabled} onClick={onClick}>
{children}
</MyButton>
)}
renderBackButton={({ onClick, children }) => (
<MyGhostButton onClick={onClick}>{children}</MyGhostButton>
)}
/>RenderButtonProps
| Prop | Type | Description |
|---|---|---|
loading | boolean | Action is in-flight — show a spinner |
disabled | boolean | Validation not met — button should be inert |
onClick | () => void | Triggers the checkout action for this step |
children | ReactNode | Localised label for the current step |
The children label changes per step: ثبت سفارش, ثبت اطلاعات ارسال, ادامه به پرداخت, انجام پرداخت (Persian) or the equivalent English strings.
Replacing primitives with asChild
All built-in primitives accept an asChild prop. When set, the component merges its behaviour props onto your single child element instead of rendering its own DOM node — the same pattern used by Radix UI and shadcn/ui.
Class names are merged (primitive class + child class). Event handlers are composed (both called).
Button
import { Button } from '@sazito/checkout/next';
<Button asChild loading={isLoading} disabled={isDisabled} onClick={handleClick}>
<MyButton variant="filled">Continue</MyButton>
</Button>Props forwarded: className, disabled, aria-busy, onClick, and all standard button attributes.
Field
Keeps the label, optional marker, and error message. Swaps the <input> element.
import { Field } from '@sazito/checkout/next';
<Field label="Email" id="email" error={errors.email} asChild>
<MyInput placeholder="you@example.com" />
</Field>Spinner
import { Spinner } from '@sazito/checkout/next';
<Spinner asChild>
<MyLoadingIndicator />
</Spinner>ErrorBanner
Merges role="alert" and class onto your component.
import { ErrorBanner } from '@sazito/checkout/next';
<ErrorBanner message={errorMessage} asChild>
<MyAlert />
</ErrorBanner>SectionTitle
Swaps the default <h3> for any heading element or typography component.
import { SectionTitle } from '@sazito/checkout/next';
<SectionTitle asChild>
<h2 className="text-xl font-bold">Payment method</h2>
</SectionTitle>ProductPlaceholder
Replaces the default box icon shown when a product has no image.
import { ProductPlaceholder } from '@sazito/checkout/next';
<ProductPlaceholder asChild>
<img src="/fallback-product.png" alt="" />
</ProductPlaceholder>Programmatic control with useCheckout
Use useCheckout inside any component rendered within CheckoutProvider to read state or trigger actions directly.
'use client';
import { useCheckout } from '@sazito/checkout/next';
export function DiscountWidget() {
const { state, actions } = useCheckout();
return (
<div>
<input
value={state.discountCode}
onChange={(e) => actions.setDiscountCode(e.target.value)}
/>
<button
onClick={() => actions.applyDiscount()}
disabled={state.flags.applyingDiscount}
>
Apply
</button>
{/* Invalid/expired codes set an inline error, not the global banner. */}
{state.discountError ? <p role="alert">{state.discountError}</p> : null}
{state.appliedDiscountCode ? (
<button onClick={() => actions.removeDiscount()}>
Remove {state.appliedDiscountCode}
</button>
) : null}
</div>
);
}CheckoutState fields
| Field | Type | Description |
|---|---|---|
step | CheckoutStep | Active step: cart | shipping | payment | result |
status | CheckoutStatus | Coarse engine status: idle | bootstrapping | working | redirecting | polling | error |
locale | 'fa' | 'en' | Active label and number-formatting locale |
direction | 'rtl' | 'ltr' | Active layout direction |
cart | Cart | null | Current cart |
invoice | Invoice | null | Current invoice |
regions | CheckoutRegion[] | Regions and nested cities used by the address form |
addressForm | AddressFormValues | Live shipping address form values |
postalCodeMandatory | boolean | Whether shop settings require a postal code |
emailMandatory | boolean | Whether shop settings require an email address |
addressDirty | boolean | Whether the form differs from the saved invoice address |
applicable | ApplicableShippingMethods | null | Raw invoice-specific shipping response |
shippingGroups | ShippingGroup[] | Grouped shipping rates for each item bundle |
paymentMethods | PaymentMethod[] | Available payment gateways |
selectedPaymentMethodId | number | null | Selected gateway |
discountCode | string | Input value of the discount field |
appliedDiscountCode | string | null | Successfully applied code |
appliedDiscount | AppliedDiscount | null | Classified percentage, fixed-amount, or free-shipping discount and its savings |
discountError | string | null | Inline error for the discount field (e.g. invalid code); cleared on edit/apply/remove |
result | CheckoutResult | null | Post-payment result (status, order, message) |
error | CheckoutError | null | Last error with message, code, step |
flags | CheckoutFlags | Granular async flags (see below) |
CheckoutFlags
| Flag | Fires during |
|---|---|
bootstrapping | Initial cart + invoice load |
updatingCart | Quantity change or item remove |
savingAddress | Shipping form submit |
loadingShipping | Fetching applicable rates after address save |
selectingRate | Selecting a shipping rate |
applyingDiscount | Discount code submission |
loadingPayments | Fetching payment methods |
placingOrder | Order placement + gateway redirect |
CheckoutActions
| Method | Description |
|---|---|
start() | Bootstrap cart and invoice. Called automatically. |
next() | Advance to the next step (validates current step). |
back() | Return to the previous step. |
goToStep(step) | Jump to any step directly. |
updateItemQuantity(cartProductId, variantId, quantity) | Update a cart line quantity. |
removeItem(cartProductId, variantId) | Remove a cart line. |
setAddressField(key, value) | Update a single address form field. |
submitAddress() | Save address and load applicable shipping rates. |
selectShippingRate(groupKey, rateId) | Select a rate within a shipping group. |
setDiscountCode(code) | Update the discount code input. |
applyDiscount() | Submit the discount code. |
removeDiscount() | Remove the applied discount. |
selectPaymentMethod(id) | Select a payment method. |
placeOrder() | Place the order and redirect to the gateway. |
resolvePaymentReturn(params) | Resolve a return from the payment gateway. |
reset() | Reset checkout state to initial. |
Using SazitoCheckout directly
SazitoCheckoutPage bundles the provider and UI. If you already have a
CheckoutProvider in your tree, render SazitoCheckout directly:
import {
CheckoutProvider,
SazitoCheckout,
} from '@sazito/checkout/next';
// SazitoProvider must still wrap the tree above this component.
export default function CheckoutPage() {
return (
<CheckoutProvider
credentials={{ cart: { identifier: '<cart-identifier>' } }}
config={{ locale: 'fa' }}
>
<SazitoCheckout className="my-checkout" />
</CheckoutProvider>
);
}SazitoCheckout includes the stepper, active checkout step, footer actions,
and order summary. Use SazitoCheckoutPage unless you need to place the
provider and UI separately.
Error codes
CheckoutError.code gives a machine-readable reason:
| Code | Meaning |
|---|---|
no_cart | Cart identifier not found |
no_invoice | Invoice could not be created or found |
min_basket | Cart total below store minimum |
rate_limited | Too many requests |
cart_invalid | Cart is empty or contains invalid items |
invoice_locked | Invoice is locked (already placed or expired) |
stock_violated | One or more items went out of stock during checkout |
shipping_required | Cart requires shipping but no address or rate provided |
address_required | Shipping address missing |
payment_failed | Gateway reported payment failure |
network | Network or server error |
validation | Invalid input sent to the API |
unknown | Unclassified error |