# Inline Checkout
This guide shows you how to securely accept payments (cards, alternative payments)
**directly on your website**, using our Embedded Components SDK and API SDK.
This guide covers:
- Integrating the xMoney Client SDK
- Creating payment intents with the Server API SDK
- Submitting and confirming payments
- Mobile integration via WebView
## Integration Modes
| Mode | Description | Use Case |
| --- | --- | --- |
| **Full** | Renders the entire checkout form including saved cards and submit button. | Fastest integration with minimal frontend effort |
| **Embed Card Elements** | Embed only the necessary input elements (card input, expiry, CVV), with full UI control. | Custom UI or deeper |
## Full Flow Overview
```mermaid
sequenceDiagram
actor Frontend as Merchant's Frontend
actor API as Merchant's API
actor API SDK as xMoney API SDK
actor SDK as xMoney Frontend SDK
actor xMoney API
Note over API SDK: Init SDK with SecretKey
Frontend ->>+ API: Prepare order data
API ->>+ API SDK: .initializeCheckout()
API SDK -->>- API: Encrypted payload
API -->>- Frontend: Encrypted payload
Frontend ->>+ SDK: .xMoneyCheckout()
SDK ->>+ xMoney API: fetch cards for userId if needed
xMoney API -->>- SDK: return cards
SDK -->>- Frontend: Render payment form
Frontend ->>+ SDK: .submitPayment()
SDK -->>- xMoney API: Process transaction
Note over xMoney API: Redirect to backurl if set
loop Every minute
Frontend->>+API: Get order status
API ->>+ API SDK: .getOrder()
API SDK ->>+ xMoney API: get order
xMoney API -->>- API SDK: return order data
API SDK -->>- API: order data
API -->>- Frontend: order data
end
Note over Frontend: Do something with order status
```
## 1. Set up the xMoney Fronted SDK
First, add the xMoney Client SDK to your website.
### Installation
Via CDN
```html
```
Full Payment Form
### Full Payment Form
```js
const sdk = new window.XMoneyPaymentForm({
container: "payment-form-widget", // placeholder for the payment form
elementsOptions: {
appearance: customThemeStyles,
locale: "en-US", // "en-US" | "el-GR" | "ro-RO";
saveCardOption?: true; // displays the checkbox for saving the cards
validationMode?: "onSubmit" | "onChange" | "onBlur" | "onTouched"; // Validation mode for the form. Default is "onSubmit".
}
savedCards: [], // list with saved cards prefetched for a customerId
checksum: '', // checksum for the payment payload, received from the API
payload: '', // order payload
publicKey: PUBLIC_KEY, // your public key using the pk__ format
onReady: () => setIsReady(true), // callback when the paymentForm is ready
onError: (err: any) => console.error("❌ Payment error", err), // error callback
});
```
#### Display the Inline Checkout Form
```html
```
This creates a secure, payment form directly into your checkout page.
### SDK Instance public properties
The SDK instance provides several available methods for interacting with the xMoney Payment Form.
It allows dynamic updates to order details, locale, appearance and handles form lifecycle events sucs as closing and destroying.
#### Methods
##### `updateOrder(payload: string, checksum: string): void`
Updates the order details in the payment form.
##### Parameters:
- `payload` (`string`): A JSON string containing the updated order details.
- `checksum` (`string`): A string used to verify the integrity of the request.
##### `updateLocale(locale: "en-US" | "el-GR" | "ro-RO"): void`
Changes the locale of the payment form to support multiple languages.
##### Parameters:
- `locale` (`"en-US"` | `"el-GR"` | `"ro-RO"`): The locale to set.
Supported values:
- `en-US`: English (United States)
- `el-GR`: Greek (Greece)
- `ro-RO`: Romanian (Romania)
##### `updateAppearance(appearance: AppearanceOptions): void`
Updates the visual appearance and theme of the payment form.
##### Parameters:
- `appearance` (`AppearanceOptions`): An object that defines the theme and styling rules.
##### `AppearanceOptions` Object:
- `theme?` (`"light"` | `"dark"` | `"custom"`): The visual theme. Defaults to `"light"`.
- `variables?` (`Record`): CSS variables used in custom themes.
- `rules?` (`Record>`): CSS rules for targeted custom styling.
##### `close(): void`
Closes the payment form interface without destroying it.
##### `destroy(): void`
Performs cleanup and permanently destroys the payment form instance.
Embedded Card Elements
### Embedded Card Elements
```js
const sdk = new window.XMoneyCheckout({
container: "payment-widget",
publicKey: PUBLIC_KEY,
elementsOptions: { appearance: customThemeStyles },
onError: (err: any) => console.error("❌ Payment error", err),
onReady: () => setIsReady(true),
});
document.querySelector("#pay-button").addEventListener("click", async () => {
await sdk.submitPayment({ payload, checksum })
})
```
### Make the payment
To make the payment after validating inputs and
creating the payment intent, call your merchant server,
then submit the payment using the Client SDK.
```javascript
try {
const response = await fetch(
"http://localhost:3001/checkout-initialization",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
publicKey, // pk_test_xmoneykey1234
firstName: "",
lastName: "",
email: "",
amount: 1,
currency: "EUR",
}),
}
);
const result = await response.json();
if (!response.ok) {
throw new Error(result.error || "Failed to create payment intent");
}
await checkout.submitPayment(result);
} catch (error) {
console.error("Error creating payment intent:", error);
} finally {
setIsSubmitting(false);
}
```
Make sure your backend endpoint `/checkout-initialization` returns the required
payload and checksum for the checkout to proceed.
#### Init Parameters explained
| Parameter | Type | Required | Description | Availability |
| --- | --- | --- | --- | --- |
| container | string | yes | DOM selector where the card input will be mounted. This will draw all 3 card elements (card number, expiry, cvv) into the DOM. | v1.0 |
| publicKey | string | yes | Merchant’s public key. It has this format: `pk__siteUID`. Env can be: `test` or `live`. | v1.0 |
| onReady | function | no | Callback fired when the widget is successfully loaded. | v1.0 |
| onError | function | no | Callback fired when the payment fails. Receives an error object with details. | v1.0 |
| elementOptions | object | no | Optional customizations (primary text color, font) | v1.0 |
### Customize the Experience
You can easily customize the UI of your checkout form.
#### Theme Options
```javascript
const customThemeStyles = {
theme?: "light" | "dark" | "custom";
variables: {
colorPrimary: "#009688",
colorDanger: "#e53935",
colorText: "#212121",
colorTextSecondary: "#757575",
colorTextPlaceholder: "#bdbdbd",
colorBorder: "#e0e0e0",
colorBorderFocus: "#009688",
colorBackground: "#f5f5f5",
colorBackgroundFocus: "#0096880a",
},
```
#### Localization
Set the locale manually or auto-detect based on browser settings.
```javascript
locale: 'ro-RO'
```
If locale is omitted the SDK will default to `en-US`
### Advanced: Saved Cards and One-Click Payments
If you want to offer one-click checkout for returning customers, simply enable card saving:
```javascript
saveCardOption: true; // show "Save card" checkbox for new cards
```
On future checkouts, pre-fill saved cards securely without
collecting card info again.
### SDK Instance methods
## 2. Create a Payment Intent (Server Side)
Before submitting a payment, you must create a payment intent on your
server using the xMoney API SDK.
### Install the API SDK
```shell
npm install @xmoney/api-sdk
```
### Initialize the API SDK
```typescript
import xMoneyApiClient from "@xmoney/api-sdk";
const client = new xMoneyApiClient({
secretKey: "sk_test_secretkey",
});
```
### Initialize the checkout
```typescript
async function createPaymentIntent(orderData, customerData) {
const checkout = client.initializeCheckout({
publicKey: orderData.publicKey,
customer: {
identifier: customerData.id,
firstName: customerData.firstName,
lastName: customerData.lastName,
country: customerData.country,
city: customerData.city,
email: customerData.email,
},
order: {
orderId: orderData.id,
description: orderData.description,
type: "purchase",
amount: orderData.amount,
currency: orderData.currency,
},
cardTransactionMode: "authAndCapture",
backUrl: "https://localhost:3002/transaction-result", // this is the client side URL, where the user will be redirected
});
return checkout; // { payload, checksum }
}
```
You will use the `checkout` object as an input on the initialization of the paymentForm or `submitPaymet()` function on the Embedded card elemenets in client SDK
## 3. Validate the card inputs
Before submitting the payment, you can validate the card fields
programmatically, along with your own checkout page validation.
Use the built-in `validate(showErrors: bool)` method from the xMoneyCheckout
instance. Passing `true` will automatically show the errors bellow the checkout elements.
Passing `false` will just validate and return the errors so you can handle the messages
and how they are displayed to your customers.
```javascript
const { cardNumberError, expDateError, cvvError } = await xMoneyCheckout.validate(true);
if (cardNumberError || expDateError || cvvError) {
console.error('Validation errors:', { cardNumberError, expDateError, cvvError });
// Stop the process
} else {
// Proceed to submit the payment
}
```
This ensures the card inputs are correctly validated before attempting a payment.
## 4. Handle the payment result
### Client
After submitting the payment, handle the encrypted response for the payment received on the redirect using the `backUrl`.
Send the result back to your merchant backend for decryption.
#### Handle response without redirect
To provide a seamless user experience in your inline checkout integration with xMoney,
you can implement a polling mechanism that continuously checks the status of an order
until it’s completed, avoiding the need for a post-payment redirect.
##### Prerequisites
- You have the orderId from your system
- You have access to the xMoney [Get Order](https://docs.xmoney.com/api/reference/order/retrieve-an-order)
##### Behaviour
- Call GET `/order?page=0&perPage=1&externalOrderId=` endpoint repeatedly (e.g. every 6 seconds)
- Once the status contains "complete" (e.g. `complete-ok` or `complete-failed`) stop the polling and update the UI
- Remove the payment form by calling `sdk.close()`
### API
On the server side, decrypt the response using the API SDK:
```javascript
const paymentResponse = this.xMoneyApiClient.decryptOrderResponse(
body.result,
);
//TODO Your business logic here
if (
paymentResponse.transactionStatus ===
xMoneyTransactionStatusEnum.CompleteOk
) {
console.log('Transaction was successful');
}
return Promise.resolve(paymentResponse);
```
Display the decrypted transaction status to your users accordingly.
## 5. 3DSv2 Authentication
The SDK automatically detects and sends necessary 3DSv2
parameters, like:
- Browser IP
- Browser Language
- User Agent
You don't need to manually collect these unless you want to
override defaults.
## 6. Mobile Integration via WebView
You can also use xMoney Checkout in a mobile app using a WebView.
The API SDK returns a full HTML page that you load directly.
### Example
```javascript
import xMoney from "@xmoney/api-sdk";
const xMoneyApiClient = new xMoney({
secretKey: "sk_test_secretKey",
});
const orderHtml = xMoneyApiClient.getWebviewCheckoutHtml({
publicKey: 'pk_test_abc123',
customer: {
identifier: "customerIdentifier",
firstName: "John",
lastName: "Doe",
country: "RO",
city: "Bucharest",
email: "john.doe@test.com",
},
order: {
orderId: "myUniqueOrderId",
description: "Order Description",
type: "purchase",
amount: 100,
currency: "EUR",
},
cardTransactionMode: "authAndCapture",
backUrl: "https://127.0.0.1:8080",
});
```
Render orderHtml inside a mobile WebView.
This is ideal for hybrid apps or apps where embedding raw form components is not desirable.
Find more details about [Accepting Payments in Your Mobile App](/guides/mobile-apps/accepting-payments)
## 7. Examples
- Frontend demo: [Inline Checkout GitHub Example](https://github.com/Twispay/checkout-samples)
- Backend demo: [Inline Checkout API Githup Example](https://github.com/Twispay/checkout-samples-api)
- [SDK API](https://github.com/Twispay/api-sdk)
### Checkount-Samples-API setup
**Clone the repository**
```bash
git clone git@github.com:xMoney-Payments/checkout-samples-api.git
cd checkout-samples-api
```
**Install dependencies**
```bash
npm install
```
**Set the secretKey**
Update the `app.service.ts` class and set the correct secret key when initialising the
`xMoneyApiClient`
```typescript
constructor() {
this.xMoneyApiClient = new xMoneyApiClient({
secretKey: 'sk_test_',
verbose: true,
});
}
```
**Run**
```bash
npm run start:dev
```
### Checkout-Samples setup
**Clone the repository**
```bash
git clone git@github.com:xMoney-Payments/checkout-samples.git
cd checkout-sample
```
**Install dependencies**
```bash
npm install
```
**Update configs**
Set the public key in `src/constants/general.constants.ts`
```typescript
export const PUBLIC_KEY = "pk_test_";
```
To fetch the saved cards you need to set a `USER_ID` too.
After the first successful test payment you will receive `customerId` in the response
which can be used for future testing.
```typescript
export const USER_ID = ;
```
**Run the app**
```bash
npm start
```
### Testing
To test various scenarios you can use these [test cards](/guides/payments/testing#test-cards)