> ## Documentation Index
> Fetch the complete documentation index at: https://docs.overflow.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating from Stripe

> Map Stripe Elements integration patterns to Payment Elements at the SDK level.

This guide covers the SDK-level migration only: loading, mounting, options, events, and submit flow. Data migration (customers, saved payment methods, stored tokens) is a separate operations topic and is not covered here.

<Note>
  Migrating stored payment credentials and historical customer data requires a separate handoff with the Overflow team. That content is not yet published. [Contact support](https://overflow.co/contact) when you are ready to plan that work.
</Note>

## Before you start

* Get a `test_pub_…` publishable key for your staging environment and a `live_pub_…` key for production. See [Concepts](/payment-elements/concepts).
* Confirm your server has an authorize endpoint wired to Overflow. See the [authorize a payment API reference](/api-reference/payments/authorize-payment).
* Read the [Checkout element](/payment-elements/elements/checkout/introduction) overview. Checkout is the recommended primary path and maps most directly to Stripe's Payment Element.

## Concept mapping

| Stripe concept                                     | Payment Elements equivalent                                                                                                          |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `loadStripe(pk)`                                   | `loadOverflow(pk)` (async loader). See [Installation](/payment-elements/installation).                                               |
| `Elements` provider                                | `new Overflow(pk)` instance. Pass the instance to element factories.                                                                 |
| `elements.create('payment')`                       | `overflow.checkout(options)`                                                                                                         |
| `elements.create('card')`                          | `overflow.card(options)`                                                                                                             |
| `elements.create('iban')` / bank                   | `overflow.bank(options)`                                                                                                             |
| `elements.create('paymentRequestButton')`          | `overflow.applePay(options)` and `overflow.googlePay(options)` (separate elements)                                                   |
| `elements.create('address')`                       | `overflow.address(options)`                                                                                                          |
| `elements.create('linkAuthentication')`            | `overflow.email(options)` and `overflow.phone(options)`                                                                              |
| `element.mount('#slot')`                           | `element.mount('#slot')` (same signature)                                                                                            |
| `element.unmount()` / `destroy()`                  | `element.unmount()`                                                                                                                  |
| `elements.submit()` / `stripe.confirmPayment(...)` | `element.submit()` returns the tokenized payload; forward it to your server                                                          |
| `paymentIntent.client_secret` flow                 | No client secret in the browser. Server calls authorize with the tokenized payload from `submit()`                                   |
| Appearance API (`appearance.variables`)            | `appearance.variables`. See [Theming](/payment-elements/theming/overview)                                                            |
| Appearance rules / element-scoped CSS              | `appearance.elements.<name>` overrides. See [Element-scoped overrides](/payment-elements/theming/element-scoped-overrides)           |
| Locale option                                      | `locale` option. See [Localization](/payment-elements/options/localization)                                                          |
| `element.on('change', fn)`                         | `onChange` in options. See [onChange](/payment-elements/events/on-change)                                                            |
| `element.on('ready', fn)`                          | `onReady`. See [onReady](/payment-elements/events/on-ready)                                                                          |
| `element.on('focus' / 'blur', fn)`                 | `onFocus` / `onBlur`. See [Focus and blur](/payment-elements/events/on-focus-blur)                                                   |
| Stripe error object (`type`, `code`, `message`)    | `PaymentElementsError` with `code`, `message`, and structured `fieldErrors`. See [Error codes](/payment-elements/events/error-codes) |

## Loading and initialization

Stripe:

```js theme={null}
import { loadStripe } from '@stripe/stripe-js';
const stripe = await loadStripe('pk_test_...');
const elements = stripe.elements({ appearance, locale: 'en' });
```

Payment Elements:

```js theme={null}
import { loadOverflow } from '@getoverflow/payment-elements';

const overflow = await loadOverflow('test_pub_...');
const checkout = overflow.checkout({
  paymentMethods: ['card', 'bank'],
  appearance: { variables: { colorPrimary: '#111827' } },
  locale: 'en',
});
```

Notes:

* Publishable keys use the `live_pub_…` and `test_pub_…` prefixes. There is no separate live/test toggle in code; the prefix determines the environment.
* The npm package is a small loader that fetches the SDK from the CDN. There is no bundled SDK build. See [Installation](/payment-elements/installation).
* Appearance is set per element, not on a shared provider. Pass `appearance` into each element's options.

## Mounting

The `mount()` signature is compatible:

```js theme={null}
// Stripe
const card = elements.create('card', { hidePostalCode: true });
card.mount('#card');

// Payment Elements
const card = overflow.card({ postalCode: 'hidden' });
card.mount('#card');
```

Only one instance may be mounted to a given selector at a time. Call `unmount()` before re-mounting.

## Options mapping

Options are set per element in the factory call, not on a shared `elements` object.

| Stripe option                   | Payment Elements option                                                                                                                                                    |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `disabled`                      | `disabled`                                                                                                                                                                 |
| `hidePostalCode: true` on card  | `postalCode: 'hidden'` on card                                                                                                                                             |
| `showIcon`                      | Not exposed. Icons render based on element and theme.                                                                                                                      |
| Appearance `variables`          | `appearance.variables`. See [Token reference](/payment-elements/theming/token-reference).                                                                                  |
| Appearance `rules`              | `appearance.elements.<name>` overrides. See [Element-scoped overrides](/payment-elements/theming/element-scoped-overrides).                                                |
| `fields.billingDetails`         | `fields` on the address or contact element. See [Address](/payment-elements/elements/address/introduction) and [Contact](/payment-elements/elements/contact/introduction). |
| `terms` copy                    | Not exposed; consent copy is merchant-owned outside the element.                                                                                                           |
| `wallets: { applePay: 'auto' }` | Mount `overflow.applePay()` explicitly. See [Wallets](/payment-elements/elements/payment-methods/wallets/introduction).                                                    |

Optional fields document their defaults on each page under [Options](/payment-elements/options/overview).

## Event mapping

Handlers are passed as options at construction time, not attached with `.on()`.

```js theme={null}
// Stripe
card.on('ready', () => {});
card.on('change', (event) => { setDisabled(!event.complete || !!event.error); });
card.on('focus', () => {});
card.on('blur', () => {});

// Payment Elements
const card = overflow.card({
  onReady: () => {},
  onChange: (event) => { setDisabled(!event.complete || !!event.error); },
  onFocus: () => {},
  onBlur: () => {},
});
```

The full event surface for each element is documented in [Events](/payment-elements/events/overview). Highlights:

* `onChange` carries `complete`, `empty`, and a structured `error`. See [onChange](/payment-elements/events/on-change).
* `onSubmit` fires after `submit()` completes with the tokenized payload to forward to your server. See [onSubmit](/payment-elements/events/on-submit).
* Wallet buttons emit `onClick` synchronously so you can validate the cart before showing the sheet. See [onClick](/payment-elements/events/on-click).
* Shopper abandonment fires `onExit` and is not an error. See [onExit](/payment-elements/events/on-exit).

## Submit and authorize flow

There is no client secret in the browser. The browser produces a tokenized payload; the server authorizes.

```js theme={null}
// Stripe
const { error } = await stripe.confirmPayment({
  elements,
  confirmParams: { return_url: 'https://example.com/return' },
});

// Payment Elements
const { value, error } = await checkout.submit();
if (error) {
  // Render validation errors inline. See handle-validation-errors guide.
  return;
}

// Forward `value` to your server. Your server calls authorize.
await fetch('/orders/authorize', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ elementPayload: value, orderId }),
});
```

On the server, call the Overflow authorize endpoint with your secret key. See the [authorize a payment API reference](/api-reference/payments/authorize-payment) for the request and response shape.

## Validation and error handling

* Validation errors surface through `onChange` and are returned from `submit()`. See [Handle validation errors](/payment-elements/guides/handle-validation-errors).
* Errors are typed as `PaymentElementsError` with `code`, `message`, and, for Checkout, structured `fieldErrors` keyed by section. See [Field errors](/payment-elements/events/field-errors) and [Error codes](/payment-elements/events/error-codes).
* Wallet unavailability (Apple Pay or Google Pay not offered on this device) is not an error. Fall back to the primary Checkout element.

## Theming

* Set high-level tokens with `appearance.variables`. See [Token reference](/payment-elements/theming/token-reference).
* Use `appearance.size` and `appearance.shadowSize` presets rather than per-element pixel values. See [Sizing presets](/payment-elements/theming/sizing-presets) and [Shadows](/payment-elements/theming/shadows).
* Element-scoped overrides live under `appearance.elements.<name>`. See [Element-scoped overrides](/payment-elements/theming/element-scoped-overrides).
* The element renders inside an isolated tree; page CSS does not leak in. See [CSS isolation](/payment-elements/theming/css-isolation).

## What this guide does not cover

* Migrating stored payment methods, customer records, or existing Stripe tokens. That work requires coordination with the Overflow team and is not published yet.
* Drop-in API compatibility. The event names, options shapes, and payloads are different by design; do not rely on Stripe types.
* Webhook and dispute migration. Those are server-side concerns unrelated to the SDK.

## See also

* [Quickstart](/payment-elements/quickstart)
* [Concepts](/payment-elements/concepts)
* [Accept a payment](/payment-elements/guides/accept-a-payment)
* [Compose standalone elements](/payment-elements/guides/compose-standalone-elements)
* [Handle validation errors](/payment-elements/guides/handle-validation-errors)
