# Checkout

Checkout is easypay's integrated solution for collecting payments in any website with minimal development effort.

## Overview

Checkout is a pre-built payment form that you can embed directly into your website. It handles the entire payment flow including:

- Collecting customer information
- Payment method selection
- Payment information collection
- Invoking payment APIs
- Displaying payment feedback


![Checkout Overview](https://easypay-cdn-delivery.s3.eu-central-1.amazonaws.com/docs/checkout/overview-v1.1.0.png)

## Key Benefits

- **No extensive programming required**: Embed with just a few lines of code
- **All payment methods supported**: Credit cards, MB WAY, Apple Pay, Google Pay, Samsung Pay, Multibanco, Direct Debit, Virtual IBAN
- **All payment types supported**: Single, Frequent, and Subscription payments
- **Fully customizable**: Match your brand with extensive styling options
- **Mobile responsive**: Works seamlessly on all devices
- **Multiple integration methods**: Script tag or NPM package


## Live Demo

Explore the [live Checkout demo](https://checkout-demo.easypay.pt) to see the solution in action and try different payment flows.

View the [source code on GitHub](https://github.com/Easypay/checkout-demo) with instructions for running locally.

## How It Works

### 1. Create a Checkout Session (Server-Side)

Make a server-to-server POST request to create a checkout session:


```bash
curl -X POST 'https://api.test.easypay.pt/2.0/checkout' \
  -H 'AccountId: YOUR_ACCOUNT_ID' \
  -H 'ApiKey: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "type": ["single"],
    "payment": {
      "methods": ["cc", "mb", "mbw", "dd", "vi"],
      "type": "sale",
      "currency": "EUR",
      "capture: { "descriptive": "Purchase in MyStore" }
    },
    "order": {
      "items": [
        {
          "description": "T-shirt",
          "quantity": 1,
          "key": "t-shirt",
          "value": 12.50
        }
      ],
      "key": "order-123",
      "value": 12.50
    }
  }'
```

Response:


```json
{
  "id": "57cc19e9-f393-4cfa-9516-8807763b5096",
  "session": "8zoaBOC0Mj5Mg_YAbdRCqY...",
  "config": null
}
```

This response is called the **Checkout manifest**.

### 2. Display the Checkout Form (Client-Side)

#### Option A: Script Tag (Simplest)


```html
<!-- Include the SDK -->
<script src="https://cdn.easypay.pt/checkout/2.9.1/"></script>

<!-- Prepare a container -->
<div id="easypay-checkout"></div>

<script>
  // Get the manifest from your server
  const manifest = await getManifestFromServer();

  // Initialize Checkout
  easypayCheckout.startCheckout(manifest);
</script>
```

#### Option B: NPM Package


```bash
npm install --save @easypaypt/checkout-sdk
```


```javascript
import { startCheckout } from "@easypaypt/checkout-sdk";

const manifest = await getManifestFromServer();
startCheckout(manifest);
```

## Common Use Cases

### Single Payment

For one-time purchases:


```json
{
  "type": ["single"],
  "payment": {
    "methods": ["cc", "mbw", "mb"],
    "type": "sale",
    "currency": "EUR"
  },
  "order": {
    "items": [
      { "description": "Product", "quantity": 1, "value": 29.99 }
    ],
    "value": 29.99
  }
}
```

### Frequent Payment (Tokenization)

To save payment details for future use:


```json
{
  "type": ["frequent"],
  "payment": {
    "methods": ["cc", "mbw", "dd"],
    "currency": "EUR"
  }
}
```

Handle the success callback to get the payment ID:


```javascript
startCheckout(manifest, {
  onSuccess: (checkoutInfo) => {
    // Save checkoutInfo.payment.id for later captures
    saveTokenToServer(checkoutInfo.payment.id);
  }
});
```

Later, capture funds using the saved ID:


```bash
POST /capture/:id
{
  "value": 50.00,
  "descriptive": "Purchase in MyStore"
}
```

### Subscription Payment

For recurring payments:


```json
{
  "type": ["subscription"],
  "payment": {
    "methods": ["cc", "dd"],
    "type": "sale",
    "frequency": "1M",
    "start_time": "2024-02-01 00:00",
    "max_captures": 12
  },
  "order": {
    "items": [
      { "description": "Monthly Subscription", "value": 9.99 }
    ],
    "value": 9.99
  }
}
```

![Subscription Confirmation](https://easypay-cdn-delivery.s3.eu-central-1.amazonaws.com/docs/checkout/subscription.png)

## Advanced Features

### Display Modes

**Inline Mode** (default): Embeds the checkout form in your page


```javascript
startCheckout(manifest, {
  display: "inline"
});
```

**Popup Mode**: Opens checkout in a popup/modal


```html
<button id="checkout-button">Pay Now</button>

<script>
easypayCheckout.startCheckout(manifest, {
  id: "checkout-button",
  display: "popup"
});
</script>
```

![Popup Mode](https://user-images.githubusercontent.com/30448483/172881494-7265ff97-d142-4fee-9a2b-047b986dbefc.png)

### Event Handlers

React to payment events:


```javascript
startCheckout(manifest, {
  onSuccess: (checkoutInfo) => {
    console.log('Payment successful:', checkoutInfo);
    // checkoutInfo contains payment details, method, status, etc.
  },

  onError: (error) => {
    console.error('Unrecoverable error:', error);
    if (error.code === 'checkout-expired') {
      // Create new session
    }
  },

  onPaymentError: (error) => {
    console.log('Recoverable payment error:', error);
    // User can retry
  },

  onClose: () => {
    console.log('Checkout closed');
    // Clean up or redirect
  }
});
```

### Customization

Match your brand with extensive styling options:


```javascript
startCheckout(manifest, {
  logoUrl: "https://yoursite.com/logo.png",
  accentColor: "#FF6B35",
  backgroundColor: "#F7F7F7",
  buttonBackgroundColor: "#FF6B35",
  buttonBorderRadius: 5,
  inputBorderRadius: 5,
  fontFamily: "Arial, sans-serif",
  baseFontSize: 12
});
```

Example customization:

![Custom Styling](https://easypay-cdn-delivery.s3.eu-central-1.amazonaws.com/docs/checkout/stylingapi.png)

Available customization options:

- Company logo
- Background colors
- Accent colors
- Button colors and styles
- Input field colors and styles
- Font family and size
- Border radius
- Box shadows


## Testing

To test without real transactions:


```javascript
startCheckout(manifest, {
  display: "inline",
  testing: true  // Use test environment
});
```

**Important**:

- Create sessions using `https://api.test.easypay.pt`
- Use test payment methods (see [Payment Methods guide](/docs/guides/payment-methods))
- Remove `testing: true` when going to production


## Managing Checkout Instance

Store the instance for later management:


```javascript
const checkoutInstance = startCheckout(manifest, {
  onSuccess: (info) => {
    // Payment successful, clean up
    checkoutInstance.unmount();
    showThankYouMessage();
  }
});

// Later, manually remove checkout
checkoutInstance.unmount();
```

## Session Expiration

Checkout sessions expire after **30 minutes**. Handle expiration gracefully:


```javascript
startCheckout(manifest, {
  onError: async (error) => {
    if (error.code === 'checkout-expired') {
      // Create a new session
      const newManifest = await createNewSession();
      startCheckout(newManifest);
    }
  }
});
```

## Error Codes

| Error Code | Cause | Solution |
|  --- | --- | --- |
| checkout-expired | Session expired (>30 min) | Create new session |
| already-paid | Checkout already completed | Confirm payment status |
| checkout-canceled | Checkout was canceled | Create new session |
| generic-error | General error before payment | Allow retry |
| payment-failure | Error during payment | Allow retry, check details |


## Supported Languages

Checkout automatically detects the user's browser language, but you can override it:


```javascript
startCheckout(manifest, {
  language: "pt_PT"  // Portuguese
  // Options: "en", "pt_PT", "es_ES"
});
```

## Best Practices

1. **Always Create Sessions Server-Side**: Never expose your API keys in client code
2. **Handle All Error Cases**: Implement error handlers for better UX
3. **Use Webhooks**: Don't rely solely on client-side success callbacks for critical logic
4. **Test Thoroughly**: Use the test environment extensively before going live
5. **Customize for Your Brand**: Match Checkout to your website's look and feel
6. **Mobile First**: Test on various devices and screen sizes
7. **Verify Payments**: Always verify payment status on your server using the API


## SDK Reference

### `startCheckout(manifest, [options])`

#### Parameters:

- `manifest`: The return object from the [checkout service](/openapi/checkout/checkout-post#checkout/checkout-post/t=response&c=201&path=session).
- `options`: An optional object containing any of the following properties:


| Option | Type | Default | Description |
|  --- | --- | --- | --- |
| id | string | 'easypay-checkout' | The id of the HTML element where the Checkout form should be included. |
| onSuccess | function | () => {} | Callback function to be called when the Checkout is finished successfully. |
| onError | function | () => {} | Callback function to be called on (unrecoverable) errors. |
| onPaymentError | function | () => {} | Callback function to be called on (recoverable) payment errors. |
| onClose | function | undefined | Callback function to be called when the Checkout interaction is closed. |
| testing | boolean | false | Whether to use the testing API (`true`) or the production one (`false`). |
| display(1) | string | 'inline' | The display style of the element that hosts the Checkout. |
| showLoading | boolean | false | Whether to show a loading indicator. If shown, it can be customized using the CSS selector `.epcsdk-loading::before`. |
| hideDetails | boolean | false | Whether to hide the details form or not. An expandable summary will be shown with the details, instead, unless `hideDetailsButton` is also `true`. |
| hideDetailsButton | boolean | false | Whether to hide the details button and expandable summary, when `hideDetails` is `true`. |
| hideCartButton | boolean | false | Whether to hide the cart button and expandable order summary. |
| hideSubscriptionSummary | boolean | false | Whether to hide the subscription summary or not. |
| language(2) | string | undefined | The language in which to display the Checkout. |
| logoUrl | string | undefined | The merchant logo url to display in the Checkout. |
| backgroundColor | string | '#ffffff' | The color used as the background of the Checkout page. |
| accentColor | string | '#0d71f9' | The color used in highlights, as well as default buttons and input borders. |
| errorColor | string | '#ff151f' | The color used for errors. |
| inputBackgroundColor | string | 'transparent' | The color used for the input backgrounds. |
| inputBorderColor | string | accentColor | The color for input borders. |
| inputBorderRadius | number | 50 | The border radius for inputs, in `px`. |
| inputFloatingLabel | boolean | true | Whether inputs should use floating labels. |
| buttonBackgroundColor | string | accentColor | The color used for the button backgrounds. |
| buttonTextColor | string | undefined | The color used for the button text. If undefined, a contrasting color will be chosen. |
| buttonBorderRadius | number | 50 | The border radius for buttons, in `px`. |
| buttonBoxShadow | boolean | true | Whether the buttons should have box-shadow. |
| linkColor | string | '#0d71f9' | The color used for the links text. |
| stepperTextColor | string | undefined | The color used for the stepper text. If undefined, a contrasting color will be chosen. |
| fontFamily | string | 'Overpass' | The font used for the text. |
| baseFontSize | number | 10 | The value in `px` for the font size of the root element (`1rem`). |


##### Options

(1) **display** available values: `inline` (default) or `popup`.

(2) **language** available values: `en` (English), `pt_PT` (Portuguese) or `es_ES` (Spanish). If left `undefined`, a default language will be selected according to the customer's browser language.

#### Return:

- A `CheckoutInstance` object, containing the following method:
  - `unmount()`: Removes all Checkout form content and event listener.


### Success handler

`onSuccess(checkoutInfo)`

Receives an object with the following properties:

| Property | Type | Description |
|  --- | --- | --- |
| id | string | The id of the Checkout session. |
| type | string | The payment type for this Checkout (`'single'`, `'frequent'` or `'subscription'`). |
| payment | Object | Detailed information about the payment. |


#### Properties of the `payment` Object:

**Note**: Some properties only appear with certain payment methods.

| Property | Method | Type | Description |
|  --- | --- | --- | --- |
| id | All | string | The payment's id. |
| method (1) | All | string | The payment method chosen by the customer. |
| status (2) | All | Object | The status of the payment. |
| value | All | number | The order value, rounded to two decimal places. Not used in `frequent` payments. |
| cardType | Credit Card | string | The credit card type (`'VISA'` or `'MasterCard'`). |
| lastFour | Credit Card | string | The last four digits of the credit card. |
| cardCountryCode | Credit Card | string | The country code of the credit card. |
| expirationDate (3) | Credit Card / Multibanco | string | The expiration date of the card (Credit Card) or the payment (Multibanco). |
| entity | Multibanco | string | The Multibanco entity. |
| reference | Multibanco | string | The Multibanco reference. |
| sddMandate (4) | Direct Debit | Object | SEPA Direct Debit mandate. |
| iban | Virtual IBAN | string | The created IBAN. |


(1) Possible method values are the same as in the [Checkout creation](/openapi/checkout/checkout-post).

(2) Possible payment status values:

details
summary
Expand
- `'authorised'`
- `'deleted'`
- `'enrolled'`
- `'error'`
- `'failed'`
- `'paid'`
- `'pending'`
- `'success'`
- `'tokenized'` (To be Used later in `frequent` payments.)
- `'voided'`


(3) Format of the expiration varies between Credit Card (`'MM/YY'` format) and Multibanco (`'Y-m-d H:i'`).

(4) Properties of the `sddMandate` Object:

details
summary
Expand
| Property | Type | Description |
|  --- | --- | --- |
| accountHolder | string | Name of the account holder. |
| billingEntity | string | The billing entity for the payments. |
| countryCode | string | Country code of the bank account. |
| email | string | The customer's e-mail address. |
| iban | string | The IBAN. |
| id | string | The mandate's id. |
| maxNumDebits | string | The maximum number of debits allowed for this Direct Debit. |
| name | string | The customer's name. May be different from the account holder's name. |
| phone | string | The customer's phone number. |
| referenceAdc | string | The authorization reference. |


### Error handler:

`onError(error)`

Receives an object with the following property:

| Property | Type | Description |
|  --- | --- | --- |
| code | string | The type of error that occurred. See the table below for possible values. |


The error `code` has the following possible values and recommended solutions:

| Value | Cause | Recommended solution |
|  --- | --- | --- |
| checkout-expired | The Checkout session has expired. | Create a new Checkout session with the server-to-server call and use the newly returned Manifest to instantiate a new Checkout form. |
| already-paid | The Checkout was already paid. | Refresh the order information and confirm that it was paid. Give feedback to the user accordingly. |
| checkout-canceled | The Checkout was canceled. | Create a new Checkout session with the server-to-server call and use the newly returned Manifest to instantiate a new Checkout form. |
| generic-error | There was an error before the payment process had started. | Allow the user to try again. If problem persists, report it to easypay. |


### Payment error handler

`onPaymentError(error)`

Signals the occurrence of a recoverable error during a payment attempt. These errors are informative and for logging/analysis purposes, as the user is allowed (and encouraged) to try the payment again with the same or other payment method.

Receives an object with the following properties:

| Property | Type | Description |
|  --- | --- | --- |
| code | string | The type of error that occurred. See the table below for possible values. |
| paymentMethod | string | The payment method for which the error happened. |
| checkout | object | On `payment-failure` errors, the Checkout object containing the payment information that had already been created. Has the same properties as the [onSuccess](#success-handler) `checkoutInfo` object. |


The error `code` has the following possible values and recommended solutions:

| Value | Cause | Recommended solution |
|  --- | --- | --- |
| generic-error | There was an error before the payment process had started. | Allow the user to try again. If problem persists, report it to easypay. |
| payment-failure | There was an error after the payment process had started. | Allow the user to try again. If problem persists, use the attached `checkout` object to get details about the payment intent. |


## Next Steps

- [Checkout API Reference](/openapi#tag/Checkout) - Complete API documentation
- [Webhooks Guide](/docs/guides/webhooks) - Receive payment notifications
- [Payment Methods](/docs/guides/payment-methods) - Learn about available payment methods
- [Payment Types](/docs/guides/payment-types) - Understand Single, Frequent, and Subscription payments
- [GitHub Demo](https://github.com/Easypay/checkout-demo) - Full working example