# Integrate: Embedded Checkout

An interactive bench for SDK integrations. Your server creates a payment with `confirm: false` and hands the resulting `client_secret` to the SDK; one embedded checkout collects the payment method and confirms with your publishable key. The secret key never leaves your server.

Unlike the other integration styles, this page has no payment-method picker — deliberately. **One integration covers every payment method the account has enabled**, including each one's redirect, inline QR or wallet sheet. There is nothing method-specific to write, so walking methods one at a time would misrepresent the integration.

## What this page covers
- A generated `POST /payments` body with `confirm: false` that names no payment method at all
- The one method-specific parameter, `allowed_payment_method_types`, with a picker for it
- A currency selector, because a method only appears if it accepts the payment's currency
- The web checkout mounted live from the client secret, with appearance and layout from the SDK theming settings
- The mobile path: an iOS or Android simulator, and the `/api/create-msdk-intent` endpoint the app calls for its intent
- Final-state confirmation through the webhook feed and `GET /payments/{id}?force_sync=true`
- A refund step, whose rules depend on the method the shopper actually chose

## allowed_payment_method_types
An array of `payment_method_type` values on the payment intent. It **restricts** what the checkout offers:

```json
"allowed_payment_method_types": ["pay_shap", "payflex", "credit", "debit"]
```

Omit it — which is the default on this page — and the checkout offers everything the account has enabled for the payment's currency. That is what makes enabling a new payment method a dashboard change rather than a code change.

Two things to know:

- It filters; it does not enable. A type listed here still has to be enabled on the merchant account and support the payment's currency.
- The client-side equivalents are different parameters: the SDK's `paymentMethodOrder` reorders what is shown and `paymentMethodsConfig` can hide entries. Those are presentation; `allowed_payment_method_types` is on the intent and is what the API enforces.

## The two keys
- **Secret key** — server-side only. Creates the intent (`confirm: false`).
- **Publishable key** — safe in the browser or app. Confirms the payment using the client secret.

## Mobile
There is no in-browser mobile SDK, so the app running in the simulator fetches its intent over HTTP:

- `GET /api/create-msdk-intent` mints the intent server-side and returns `clientSecret`, `ephemeralKey`, `publishableKey` and `hyperswitchBaseUrl`.
- Add `?sessionId=<id>` to serve a payload you have edited on [Modify MSDK intent](/modify-msdk-intent), so you can change the request the device receives without rebuilding the app.
- The ephemeral key is what lets the app list and reuse the customer's saved payment methods.

## Recurring: storing a credential here, charging it later

The flows above are all **CIT** — customer-initiated, with the shopper present. Switch the panel to **Merchant (MIT)** and the sequence changes: the payment that stores the credential comes first, then an off-session charge with nobody there.

The setup payment is the same `confirm: false` intent with `setup_future_usage: "off_session"`, a `customer_id` and `mandate_data` added. The SDK shows the mandate terms as part of the checkout, and the shopper pays and agrees in one go:

```json
"confirm": false,
"customer_id": "cust_123",
"setup_future_usage": "off_session",
"authentication_type": "three_ds",
"mandate_data": {
  "customer_acceptance": {
    "acceptance_type": "online",
    "online": { "ip_address": "127.0.0.1", "user_agent": "Mozilla/5.0" }
  },
  "mandate_type": { "multi_use": { "amount": 100000, "currency": "ZAR" } }
}
```

That checkout is the only step the shopper is present for. Everything after it is a plain server-side request.

The off-session charge is identical in every integration style — how the shopper paid the first time changes nothing about charging them later:

```json
"amount": 6500,
"currency": "ZAR",
"confirm": true,
"off_session": true,
"customer_id": "cust_123",
"recurring_details": { "type": "payment_method_id", "data": "pm_..." }
```

`payment_method_id` is **not** a field on `POST /payments` — the stored credential is referenced through `recurring_details`. Only card-backed credentials can be stored this way, so the toggle is offered for cards and network tokens and not for the alternative methods.

## Key concepts
- The SDK handles whatever the chosen method needs, so redirect, QR and wallet flows are all the same integration to you.
- Redirect-based methods return to `return_url`. With `is_iframe_redirection_enabled: true` on the payment the connector returns a `redirect_inside_popup` next action and the SDK handles the redirect itself, in a full-screen overlay.
- `inline_iframe_redirection_enabled: true` on the payment element options (alongside `layout`; use it by default) moves that redirect inline, into the checkout form. Pair it with `sdkHandleConfirmPayment: { confirmParams: { return_url } }` on the same options object — the SDK confirms from inside the element and needs the return URL there. Non-card methods only — cards always pop out, because 3DS pages refuse to be framed — and only for redirect targets that allow framing; one sending `X-Frame-Options: DENY` renders blank. Completion is detected by polling the intent, so it works cross-origin, with a 15-minute backstop.
- The payment's `payment_method_type` in the response tells you what the shopper chose. That, not the SDK, decides whether a refund is allowed and whether it can be partial.
- Peach rate-limits status queries to 2 per minute per transaction; automatic polling here is 30 seconds apart.

## Related
- [Integrate: Server-to-Server](/integrate/api-only.md): send the payment method data yourself, per method
- [Integrate: Hosted Checkout](/integrate/hosted-checkout.md): let Peach host the page instead
- [Integrate: cards](/integrate/cards.md): the card-only mechanics
- [Web SDK](/sdk-web.md) and [SDK theming](/operate/customization.md): integration reference and appearance
- [API reference](/playground.md): every endpoint, with the OpenAPI reference beside it

---

Interactive version: https://playground.peachpayments.com/integrate/sdk
