# Embedded checkout and card fields

Take a payment inside your own page, with Vezmo's embedded checkout (vezmo.js) or with card fields you place in your own form (vezmo-elements.js), covering trusted origins, the client token, browser events, wallets, pay-later methods that finish outside the frame, appearance and knowing the result.

Source: https://vezmo.com/docs/developers/embedded-checkout

## Overview

Two ways keep your customer on your own page while Vezmo collects the payment:

- **Embedded checkout** (`vezmo.js`): Vezmo's payment form inside your page, in a frame. You add a container and your
  own Pay button.
- **Card fields** (`vezmo-elements.js`): you build the checkout form, and mount Vezmo's secure payment field in it, or
  separate fields for the card number, expiry date and security code.

Both start the same way as [hosted checkout](/docs/developers/hosted-checkout): your server creates a checkout session.
Card details are typed into Vezmo's fields and never reach your page's code or your servers.

Not sure which one fits? [Choose how to take payments](/docs/developers/integration-options) compares every option.

## Compare the two

| | Embedded checkout | Card fields |
| --- | --- | --- |
| Script | `vezmo.js` | `vezmo-elements.js` |
| What you build | A container on your page and your Pay button. | Your own checkout form, with Vezmo's field (or the three card fields) inside it. |
| Ways to pay | Cards, Apple Pay and Google Pay, and every other method you've turned on that fits the payment. | The all-in-one field: cards, Apple Pay and Google Pay, US bank payments and pay-later methods. The three card fields: cards only. |
| Your customer's details | You send them when you create the session. The frame asks only how they pay. | The same. You can add a billing address field. |
| Result in the browser | Events, such as `success`, `pending` and `error`. | `confirm()` answers with a `status`. |
| Your site in **Trusted origins** | Required | Required |

**What loads on your page:**
The embedded checkout keeps the whole payment form on a Vezmo page inside the frame. Card fields load a card-security
library from a third party into your page, which you can see in your browser's network tab. If every part of the
payment must stay on Vezmo's own pages, use the embedded checkout or the hosted checkout.

## 1. Add your site to Trusted origins

The embedded checkout loads only on the websites listed in **Developers › Trusted origins**, and only sends its events
to them. Card fields work only from those websites too.

1. **Open Trusted origins**
Go to **Payments › VezmoPay**, then **Developers**, and open the **Trusted origins** tab.

2. **Add your site**
Type your site's origin, like `https://yourstore.com`, and select **Add origin**. Use the scheme and the
domain only: no path, no wildcards. `https://www.yourstore.com` and `https://yourstore.com` are two origins; add each
one your checkout runs on.

(Screenshot: Developers, Trusted origins tab: Trusted origins, 1 of 20, the websites allowed to load your embedded checkout; the field for another origin with the hint Scheme and domain only, like https://yourstore.com, and the Add origin button; under Websites, Live and test checkouts, the origin https://shop.example.com.)

- An origin must start with `https://`.
- One list serves your test and live checkouts.
- The list belongs to your business: every teammate's sessions use it.
- Until your site is listed, the browser refuses to show the frame on your page, and no events arrive.

## 2. Create a session on your server

Your server creates the session with `POST /merchant/secure-payments`, exactly as for
[hosted checkout](/docs/developers/hosted-checkout#create-a-session): the order's `title`, `amount` and `currency`,
and your customer in `client`. Send the customer's name, email, country and postal code there: neither the frame nor
the card fields ask for them.

From the answer, pass `data.securePayment.clientToken` to your page. It is a short-lived token for this one payment:

- It works for `ttlMinutes` (30 minutes by default, up to 24 hours).
- It can't change the amount, the currency or the customer.
- It isn't a key. Your API key and secret stay on your server.

Request and response examples: [Secure payments](https://user.vezmo.com/docs/v1/secure-payments).

## 3a. Embedded checkout

Load `vezmo.js` from `https://api.vezmo.com/api/v1/vezmo.js` on your checkout page, mount the checkout into a
container with the client token, and call `pay()` when your customer selects your Pay button. Load the script from that
address each time; don't copy it to your own server, so fixes reach your checkout without a change on your side.

The frame resizes itself to fit the form. Its look follows the session's `theme` (`light`, `dark` or `auto`), or the
theme you pass when you mount it.

### Browser events

The checkout tells your page what happens. With `vezmo.js` you listen with `on()`; the SDK only passes on messages from
the frame it created.

| Event | What it means |
| --- | --- |
| `ready` | The form has loaded. |
| `processing` | The payment is being confirmed. Keep your Pay button disabled. |
| `success` | The payment succeeded. Usually carries `paymentId` and `transactionId`. |
| `pending` | A bank payment was submitted. It settles in a few business days. |
| `error` | The payment was declined or failed. The customer can try again in the same form. |
| `action-required` | The customer has one more step in a window the checkout opened, such as a pay-later method. Not final: `success`, `pending` or `error` follows. |
| `expired` | The client token expired. Create a new session. |
| `already-paid` | This payment is already complete. Don't charge again. |

Every event name, with its fields and a raw-frame example: [Event reference](https://user.vezmo.com/docs/v1/secure-payments).

### Apple Pay and Google Pay

The wallet buttons show at the top of the form when your customer's device supports them. A wallet charges as soon
as the customer approves it in the wallet sheet, without your Pay button. If your page creates its order before it
charges, mount with `wallets: 'authorize'` and answer in your `onWalletAuthorized()` handler: nothing is charged unless
it says yes, and without a handler every approval is cancelled. `wallets: false` hides the buttons on that page. Details:
[Wallet buttons](https://user.vezmo.com/docs/v1/secure-payments).

### Pay-later methods in the frame

Klarna, Affirm, Afterpay and Amazon Pay can't run inside a frame. When your customer picks one, the form shows a
button, like **Continue to Klarna**, that opens a secure window on that method. Your page gets `action-required`, then `success` (or `pending`)
when they finish there. If they select your Pay button with one of these chosen, nothing is charged.

Some cards also need a step outside the frame (3D Secure, a card check): the checkout opens a secure window for it on
the customer's click, and the usual event follows.

## 3b. Card fields

Load `vezmo-elements.js` from `https://api.vezmo.com/api/v1/vezmo-elements.js`, open the session with the client
token, and mount one of these into your own elements:

- **The payment field**: one field that offers every method the session allows, laid out as tabs or as a list.
- **Split card fields**: the card number, expiry date and security code, each in an element of your own. Cards only,
  and you can't mix them with the payment field on one page.
- **A billing address field**, optional, beside either one.

When your customer pays, `confirm()` sends what they chose to Vezmo, and Vezmo's server prices and confirms the
payment: nothing is confirmed in the browser. It answers with a `status`: `succeeded`, `processing` (a bank payment
on its way), `requires_verification` (a bank account typed in by hand, waiting for your customer to confirm small test
deposits: it carries the `paymentId` and the verify link), or `failed`, with an `error` message to show. 3D Secure opens
in your page when the bank asks for it.

When your customer may pay in their own currency, ask them which currency they want and pass their choice with
`chooseCurrency()` before `confirm()`: until then, `confirm()` answers with the error `currency_choice_required`.

Every function and option, with examples: [Elements](https://user.vezmo.com/docs/v1/elements).

### Pay-later methods with card fields

With card fields, Klarna, Affirm, Afterpay and Amazon Pay take your customer to the method's own page and back to a
`returnUrl` of yours. Pass `returnUrl` to `confirm()` for every payment: without it, these methods fail before anything
is created. On the return page, open the same session again and call `handleReturn()` to read the result.

### Appearance

Pass `appearance` to match your brand: a light or dark theme, your main colour, corner radius and font, and finer rules
for the field's parts. Without it, the field follows the session's `theme`.

## 4. Fulfil from the webhook

A browser event or a `confirm()` result tells your page what to show. It is not proof of payment: ship the order when
your server receives `payment.success` for that `paymentId`, or after `GET /merchant/payment/:id` reads
`"state": "succeeded"`. See [Fulfil from the webhook](/docs/developers/hosted-checkout#fulfil-from-the-webhook) and
[Webhooks](/docs/developers/webhooks).

A bank payment ends in the browser with the `pending` event (embedded checkout) or the `processing` status (card
fields), and `payment.success` reaches your server only when it settles, a few business days later. Don't ship before
that.

## Test it

Use a [test key](/docs/developers/test-mode) and the test cards: `4242 4242 4242 4242` succeeds, and
`4000 0000 0000 3220` asks for 3D Secure. With a test session, the form shows an orange **Test mode** mark.

## Questions

### The frame is empty on my page

Your site's origin isn't in **Trusted origins**, or it is spelled differently (`www.`, another port). Add the exact
origin your page runs on.

### Can I style the embedded checkout?

You choose its theme (light, dark or follow the device) and the size of its container. To style the payment field
itself, use card fields with `appearance`.

### Do I still need the webhook?

Yes. A customer can close the page after paying, and a bank payment settles days later. The webhook reaches your server
either way.

### Does the frame ask for my customer's name and address?

No. It asks only how they pay. Collect the details on your own form and send them in `client` when you create the
session: its name, email, country and postal code are then required.

## Related

- [Hosted checkout](/docs/developers/hosted-checkout)
- [Choose how to take payments](/docs/developers/integration-options)
- [Secure payments in the API reference](https://user.vezmo.com/docs/v1/secure-payments)
- [Elements in the API reference](https://user.vezmo.com/docs/v1/elements)
