Description
The Checkout provides hosted payment and checkout experiences via the Browser SDK.
Installation
Recommended: install the full commercetools plugin. It includes this
Skill, every other commercetools Skill, our pre-tuned Subagents, and
the commercetools Knowledge
MCP — which
gives AI live access to the commercetools docs, GraphQL/OpenAPI
schemas, and query validation. You only install once; every Skill on
this site becomes available in every session.
Install the plugin
In any Claude Code session:
/plugin marketplace add commercetools/commercetools-skills
/plugin install commercetools@commercetools
Reload plugins
If you've updated the plugin or installed it in another window and need the current session to pick up the latest version:
/reload-plugins
Claude Desktop
Customize -> Personal plugins -> Create plugin -> Add marketplace -> add
commercetools/commercetools-ai-pluginsthen click on the plugin and click "Install"
Instructions Included
Checkout
The Checkout provides hosted payment and checkout experiences via the Browser SDK.
Integration Modes
Three modes — choose based on how much of the checkout flow Checkout should own:
paymentFlow(payment-only) — keep existing address/shipping UI, replace only the payment step with the Checkout widget. Least invasive.checkoutFlow(full hosted) — replace the entire multi-step checkout with a single commercetools-hosted page covering address, shipping, and payment.expressPayment— add Apple Pay / Google Pay express buttons to cart or PDP. Can coexist with either mode above.
Workflow
When this skill is invoked, always follow these steps:
-
Gather context (required, run first) — Always begin by gathering context for this skill. This is the mandatory grounding step: it gathers the latest verified documentation as context for you (the agent). Do not skip it, and do not replace it with another tool (such as an MCP documentation-search tool) — run this command:
node scripts/gather-context.mjs \ --query "<extract key terms from user's question>" \ --client-name "<current-client>" \ --model "<current-model>" \ --skill-name "commercetools-checkout" \ --limit 3Use its output as your primary grounding. You may additionally use other tools (such as the commercetools documentation MCP) for deeper, follow-up search. -
Combine with skill references — Cross-reference the analysis output with local references in
./references/for complete context. -
Provide implementation guidance — Synthesize the documentation with the specific integration mode the user is targeting.
References
See payment-only-mode.md for:
- Full architecture diagram (Browser SDK → Checkout service → PSP)
- Session creation (
/api/checkout/session→ commercetools Sessions API) paymentFlow,checkoutFlow, andexpressPaymentimplementation patterns- PSP connector setup (Stripe, Adyen, Mollie)
- Webhook handling and order confirmation
References
Checkout Integration
Adds payment processing via the Checkout Browser SDK.
Before You Start — Ask the User Two Questions
Always ask these before writing any code:
-
Which checkout mode?
paymentFlow— payment-only: keep existing address/shipping steps, replace onlyStepPayment.tsxwith the commercetools widget. Least invasive.checkoutFlow— full page: replace the entire multi-step checkout with a single commercetools-hosted checkout page (addresses, shipping, and payment all handled by Checkout).expressPayment— express buttons: add Apple Pay / Google Pay buttons to the cart or PDP. Can coexist with either of the above.
-
Which PSP (Payment Service Provider)? The user must configure a Connector in the commercetools Merchant Center that connects to their PSP (e.g., Stripe, Adyen, Mollie, PayPal). The skill does not set up the PSP connector — that is done in commercetools Merchant Center or via the Payment Integrations API. Just record the answer so it's clear in your implementation notes.
Architecture Overview
Browser (SDK) → Checkout service → PSP
↑
/api/checkout/session (creates Checkout Session from cart)
↑
commercetools Sessions API (POST https://session.{region}.commercetools.com/{projectKey}/sessions)
The storefront creates a Checkout Session (server-side, via a new API route) and passes the returned
sessionId to the browser SDK. The SDK handles all payment UI and communication with the PSP. After payment, commercetools creates the order automatically (full/express) or triggers a webhook/redirect (payment-only).Step 0 — Prerequisites
0a. Add environment variables to site/.env
# The key of your Checkout Application
CTP_CHECKOUT_APP_KEY=storefront-checkout
CTP_PROJECT_KEY, CTP_API_URL, and CTP_SCOPES are already in site/.env. The region is derived automatically from CTP_API_URL at startup — do not add a separate CT_REGION variable. projectKey and region are returned to the browser by /api/checkout/session, so no NEXT_PUBLIC_* variables are needed.0b. Install the Browser SDK
cd site && npm install @commercetools/checkout-browser-sdk
Step 1 — Session creation API route
Create
site/app/api/checkout/session/route.ts. This route:- Reads the current cart ID from the session
- Exchanges an OAuth token
- POSTs to the commercetools Sessions API to create a Checkout Session
- Returns the
sessionIdto the browser
// site/app/api/checkout/session/route.ts
const APP_KEY = process.env.CTP_CHECKOUT_APP_KEY!;
// Derive region from CTP_API_URL — no separate CT_REGION variable needed.
// https://api.us-central1.gcp.commercetools.com → us-central1.gcp
const REGION = API_URL.replace(/^https?:\/\/api\./, '').replace(/\.commercetools\.com\/?$/, '');
async function getManageSessionsToken(): Promise<string> {
// fetch token from oauth/token?grant_type=client_credentials
}
export async function POST() {
// guard with session's cart ID
try {
const token = await getManageSessionsToken();
const res = await fetch(
`https://session.${REGION}.commercetools.com/${PROJECT_KEY}/sessions`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
cart: { cartRef: { id: session.cartId } },
metadata: { applicationKey: APP_KEY },
}),
},
);
// handle errors here
const data = await res.json();
// Return projectKey and region so the client component needs no NEXT_PUBLIC_ vars
return NextResponse.json({ sessionId: data.id, projectKey: PROJECT_KEY, region: REGION });
} catch (e: unknown) {
// handle error
}
}
Step 2 — Integration by mode
Mode A: paymentFlow (payment-only — recommended starting point)
This is the least invasive change. Keep the existing address and shipping steps. Only the payment step.
2A-1. Implement StepPayment.tsx
// site/components/checkout/StepPayment.tsx
'use client';
...
import { paymentFlow } from '@commercetools/checkout-browser-sdk';
export default function StepPayment() {
// fetch checkout session
useEffect(() => {
// handle loading and single initialization
(async () => {
try {
const { sessionId, projectKey, region } = await getCheckoutSession();
paymentFlow({
projectKey,
region,
sessionId,
locale, // from useLocale() — never hardcode
onInfo: (msg) => {
if (msg.code === 'checkout_completed') {
router.push(<checkout-confirmation-path>);
}
},
onError: (err) => {
// SDK Message type has payload/code, not message
setError(String(err.payload ?? err.code ?? 'Payment error'));
},
});
} catch (e: unknown) {
// handle errors
}
})();
}, []); // eslint-disable-line react-hooks/exhaustive-deps
return (
<div>
// display loading DOM
{/* Required mount point — without this the widget occupies the full page */}
<div data-ctc />
// display errors
</div>
);
}
No
NEXT_PUBLIC_* env vars are needed. projectKey and region are returned by /api/checkout/session alongside the sessionId and read from the response in the client component.2A-2. Integrate into the checkout step page
In Checkout page, the payment step should render the PaymentStep.tsx
Note: WithpaymentFlow, Checkout handles the payment AND the order is created by commercetools automatically when payment succeeds (via thepaymentReturnUrlconfigured in the Application).
Step 3 — Order confirmation after Checkout
Checkout navigates the browser to
paymentReturnUrl after a successful payment, appending ?orderId=<id> (or ?orderNumber=<n>). Update the confirmation page to read these params:Step 5 — Styling
Optional: Override Checkout widget styles via the
styles option (CSS custom properties):checkoutFlow({
// ...
styles: {
'--font-family': 'var(--font-sans)',
'--color-primary': '#2d2d2d', // charcoal
'--color-primary-hover': '#4a4a4a',
'--border-radius': '0.125rem', // rounded-sm
},
});
Available CSS variables are listed in the Checkout theming docs.
Environment Variable Summary
| Variable | Secret? | Purpose |
|---|---|---|
CTP_CHECKOUT_APP_KEY | No | New — key of the Checkout Application |
No
CT_REGION, NEXT_PUBLIC_CT_PROJECT_KEY, or NEXT_PUBLIC_CT_REGION variables are needed. The session API derives the region from CTP_API_URL and returns { sessionId, projectKey, region } to the browser.Checklist
Prerequisites
-
CTP_CHECKOUT_APP_KEYadded tosite/.env(the only new variable required) -
@commercetools/checkout-browser-sdkinstalled
Session API
- Create
site/app/api/checkout/session/route.ts
SDK integration (per mode)
- paymentFlow: Replace
StepPayment.tsxwith commercetools widget mount; remove payment actions from/api/checkout/route.ts
Order confirmation
- Update confirmation page to read
?orderId=from commercetools redirect URL oronInfocallback
Key Engineering Notes
Session expiry — Checkout Sessions expire. Create the session as late as possible (when the user lands on the payment step / checkout page), not when the cart is created.
<div data-ctc /> — For paymentFlow, always render <div data-ctc /> in the component's JSX. Without it the commercetools widget mounts at the document root and occupies the full page.No
NEXT_PUBLIC_* vars — projectKey and region are server-side config. Return them from /api/checkout/session alongside sessionId so the browser never needs NEXT_PUBLIC_ prefixed variables for these values.paymentReturnUrl must be registered — Only one return URL per Connector. The URL must exactly match what's registered in the commercetools Application paymentsConfiguration.paymentReturnUrl.