# Quick Start

## Overview

The embedded SDK requires some initialisation before it can be used to process payments. The minimal initialisation consists of the following fields:

- `clientSecret`: This is the secret key returned when creating a Payment Session, although it could also be passed later when attempting the payment (see [here](/documentation/get_started/process_payments/embedded_sdk_v3/additional_config#passing-additional-data)).
- `publicKey`: This is the public key which is used to authenticate the SDK and is available in the Ryft Portal.
- `accountId`: This is the unique identifier for the Sub-Account, provided the Payment Session is set-up using the Platform Fee model.


In the next sections on this page, you will learn how to set up a **basic card payment form** using the embedded SDK.

Please note: the following guide demonstrates the process using the **JavaScript Web SDK**. However, the same features and functionalities are available across all other SDKs, unless otherwise specified.

## Install the SDK

If your web project is built in React, it is recommended that you use the dedicated React SDK instead of the JavaScript Web SDK, as it provides a much simpler integration experience with React-specific features such as hooks and components. You can refer to the [React SDK documentation](https://web-sdk.ryftpay.com/docs/react/latest/index.html) for more details on how to get started with the React SDK.

The embedded SDK can be installed in your project using either `npm` or by including a script tag in your HTML file as described in the sections below.

JavaScript Web SDK via npm

```bash Installing the JavaScript Web SDK via npm
npm install @ryftpay/web
# or
pnpm add @ryftpay/web
# or
yarn add @ryftpay/web
# or
bun add @ryftpay/web
```

When installed via `npm`, you can import the SDK modules you need in your JavaScript/TypeScript file as follows:


```javascript Importing the SDK in your JavaScript file
import { createController, createCardForm } from '@ryftpay/web';
```

If your implementation uses TypeScript, the embedded SDK also provides type definitions and inline documentation to enhance your development experience and help you understand the available methods and configurations.

JavaScript Web SDK via Script Tag

```html Installing the JavaScript Web SDK via script tag
<script src="https://web-sdk.ryftpay.com/embedded/latest/ryft.min.js"></script>
```

This will expose a global `Ryft` object which can be accessed in your JavaScript environment as follows:


```javascript Importing the SDK in your JavaScript file
const { createController, createCardForm } = window.Ryft;
```

## Controller Initialisation

Once the SDK is installed, you can instantiate a controller object that can be used to initialise the payment form and handle the payment submission according to the payment flow you are implementing (e.g. Single Payment, Split Payment, or Platform Fee).

Single Payment & Split Payment

```javascript Single Payment & Split Payment
const publicKey = "pk_XXXXXXX"; // Available in the Ryft Portal
const clientSecret = "ps_XXXXXXX"; // Returned when creating a Payment Session

const controller = createController({
    publicKey,
    clientSecret
});
```

Platform Fee

```javascript Platform Fee
const publicKey = "pk_XXXXXXX"; // Available in the Ryft Portal
const clientSecret = "ps_XXXXXXX"; // Returned when creating a Payment Session
const accountId = "ac_XXXXXXX"; // The unique identifier for the Sub-Account

const controller = createController({
    publicKey,
    clientSecret,
    accountId
});
```

## Card Form Initialisation

After initialising the controller, you can create a `cardForm` component to render a card payment form in your application.

This component provides a secure and seamless way to collect card details from customers and process payments using the embedded SDK. It also allows you to listen to various events emitted by the SDK to manage different stages of the payment process, such as enabling/disabling the PAY button based on the validity of the card details entered by the customer.

The `cardForm` component takes as an argument the controller you initialised in the previous step, as well as an optional configuration object to customise the form's behaviour and appearance.

For this basic example, we will create a simple card form using its default configuration, which includes fields for card number, expiry date, and CVC. We will also listen to the `validationChange` event to enable or disable the PAY button based on whether the card details entered by the customer are valid.


```javascript Creating and mounting the card form component
// Initialise the card form component using:
// - the controller initialised in the previous step;
// - the default configuration for the card form
const cardForm = createCardForm(controller);

// Listen to validation changes to enable/disable the PAY button
cardForm.on("validationChange", (event) => {
    payButton.disabled = !event.isValid;
});

/* Additional logic to handle the payment submission will go here.
See the next sections for more details */

// Mount the card form component to the desired container in your HTML
cardForm.mount('#card-form-container');
```

## Submitting the Payment

Once the card form component is initialised, you can handle the form submission to process the payment when the user clicks the **PAY** button.

This is done by adding an event listener to the PAY button via the `attemptPayment` method of the card form instance. Here’s an example of how to do this:


```javascript Handling the PAY button click event
const payButton = document.getElementById("pay-btn");

payButton.addEventListener("click", async (e) => {
    e.preventDefault();
    
    try {
        // Await the payment attempt
        const result = await cardForm.attemptPayment();
        handlePaymentResult(result);
    } catch (error) {
        // Log and display the error
        console.error("System Error:", error);
    }
});
```

The `attemptPayment` method will handle the payment submission and return a promise that resolves when the payment is complete or rejects if there was an error.

You can then handle the result accordingly, such as showing a success message or displaying an error to the customer.

## Handling the Result

The result of the payment attempt can be handled in the promise returned by the `attemptPayment` method. Here’s an example of how to do this:


```javascript Handling the payment result
function handlePaymentResult(result) {
    const session = result.paymentSession;

    if (
        session.status === "Approved" ||
        session.status === "Captured"
    ) {
        // Payment successful – show success page
        console.log("Payment Successful", session);
        return;
    }
    if (session.lastError) {
        // Payment failed – show error to customer
        const message = result.userFacingErrorMessage;
        console.error("Payment Error", message);
    }
}
```

The example above checks the status of the `paymentSession` returned by the `attemptPayment` method:

- If the status is `Approved` or `Captured`, it indicates that the payment was successful, and you can show a success page to the customer.
- If there is a `lastError`, you can use the `userFacingErrorMessage` method to get a user-friendly error message to display to the customer and log the error for debugging purposes as shown in the example below.


## Complete Example

The following is a complete working example that combines:

- all the steps above to create a basic payment form using the embedded SDK
- a simple PAY button to submit the payment (please note that this is not part of the SDK)
- a simple loading spinner to indicate when the payment is being processed (please note that this is not part of the SDK)
- error handling to display user-friendly error messages to the customer when a payment fails



```html Complete Basic Payment Form Example
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Ryft Card Form</title>

    <!-- Only if using the script tag method to install the SDK -->
    <script src="https://web-sdk.ryftpay.com/embedded/latest/ryft.min.js"></script>

    <style>
        #pay-btn {
            background-color: #0070f3;
            color: white;
            border: none;
            padding: 14px 22px;
            /* slightly bigger */
            font-size: 16px;
            /* slightly larger text */
            border-radius: 4px;
            cursor: pointer;
            margin-top: 12px;
        }

        #pay-btn:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
        }

        .spinner {
            border: 4px solid rgba(0, 0, 0, 0.1);
            width: 36px;
            height: 36px;
            border-radius: 50%;
            border-left-color: #09f;
            animation: spin 1s ease infinite;
            display: none;
            /* Initially hidden */
            margin: 10px auto;
        }

        @keyframes spin {
            0% {
                transform: rotate(0deg);
            }

            100% {
                transform: rotate(360deg);
            }
        }
    </style>
</head>

<body>

    <div class="Ryft--paysection">
        <form id="ryft-pay-form" class="Ryft--payform">
            <div id="card-form-container"></div>

            <button id="pay-btn" disabled>PAY NOW</button>

            <div id="ryft-pay-error"></div>
            <div id="spinner-container" class="spinner"></div>
        </form>
    </div>

    <script type="module">
        import { createController, createCardForm } from '@ryftpay/web';  // If using npm to install the SDK
        // const { createController, createCardForm } = window.Ryft;  // If using the script tag method to install the SDK

        // Returned when creating a Payment Session
        const clientSecret = "";
        // Available in the Ryft Portal
        const publicKey = "";
        // The unique identifier for the Sub-Account, if using the Platform Fee model
        const accountId = "";

        // Get a reference to the pay button
        const payButton = document.getElementById("pay-btn");
        // Get a reference to the error div
        const errorDiv = document.getElementById("ryft-pay-error");
        // Get a reference to the spinner container
        const spinner = document.getElementById("spinner-container");

        // Initialise Controller
        const controller = createController({
            publicKey,
            clientSecret,
            // accountId  // Uncomment if using the Platform Fee model
        });

        // Create Card Form instance using the default card form configuration
        const cardForm = createCardForm(controller);

        // Listen to validation changes to enable/disable the PAY button
        cardForm.on("validationChange", (event) => {
            payButton.disabled = !event.isValid;
        });

        // Disable the PAY button when the payment is being processed to prevent multiple submissions
        payButton.disabled = true;

        // Handle the payment result after attempting payment
        function handlePaymentResult(result) {
            spinner.style.display = "none";
            const session = result.paymentSession;

            // Check the payment session status to determine the outcome of the payment
            // If the status is Approved or Captured, the payment was successful
            if (session.status === "Approved" || session.status === "Captured") {
                console.log("Payment Successful", session);
                errorDiv.innerHTML = "<p style='color: green;'>Payment Successful!</p>";
                return;
            }

            // If there is a lastError, display the error message to the user and log the error for debugging
            if (session.lastError) {
                payButton.disabled = false;
                const lastError = session.lastError;
                const message = result.userFacingErrorMessage;
                console.error("Payment Error", lastError);
                errorDiv.innerHTML = `<p style='color: red;'>${message}</p>`;
            }
        }

        // Add event listener to the PAY button to handle form submission and attempt payment
        payButton.addEventListener("click", async (e) => {
            e.preventDefault();

            errorDiv.innerHTML = "";
            payButton.disabled = true;
            spinner.style.display = "block";

            // Attempt the payment using the card form instance and handle the result
            try {
                const result = await cardForm.attemptPayment();
                handlePaymentResult(result);
            } catch (error) {
                spinner.style.display = "none";
                payButton.disabled = false;

                console.error("System Error:", error);
                errorDiv.innerHTML = "<p style='color: red;'>An unexpected error occurred.</p>";
            }
        });

        // Mount the card form to the specified container in the HTML
        cardForm.mount("#card-form-container");

    </script>

</body>

</html>
```

When you open this HTML file in a browser, it will display a simple **card payment form** with a **PAY** button.

When a [test card](/documentation/get_started/process_payments/test_cards) is used and the button is clicked, it will attempt to process the payment using the embedded SDK and handle the result accordingly.

Make sure to replace the placeholder values for `clientSecret`, `publicKey`, and `accountId` with actual values from your Ryft account and Payment Session.

## Next Steps

You should now have a basic payment form set up and be able to process card payments using the embedded SDK.

You can now explore additional features and customisation options offered by the SDK. Some recommended next steps include:

- Collecting additional information from the customer during checkout, such as billing/shipping address or custom fields. See the [Field Collection](/documentation/get_started/process_payments/embedded_sdk_v3/field_collection) page for more details on how to do this.
- Adding support for other payment methods like [Apple Pay](/documentation/get_started/process_payments/embedded_sdk_v3/apple_pay) and [Google Pay](/documentation/get_started/process_payments/embedded_sdk_v3/google_pay) to provide a seamless checkout experience for your customers.
- Enabling additional configuration options to further customise the payment form and flow according to your business needs. You can refer to the [Additional Configuration](/documentation/get_started/process_payments/embedded_sdk_v3/additional_config) page for more details on the available options and how to use them.
- Using the `checkout` component to easily enable multiple payment methods and additional features all in a single component. You can refer to the [Checkout Component](https://web-sdk.ryftpay.com/docs/web/latest/documents/checkout.html) page for more details.
- Handling SDK errors: Implement comprehensive error handling to manage different types of errors that may occur during the payment process, such as validation errors, network issues, or unexpected system errors. This will help you provide a better user experience and ensure that customers are informed about any issues that arise during checkout. You can refer to the [SDK Errors](/documentation/get_started/process_payments/sdk_errors) page for best practices and examples on how to implement effective error handling in your integration.
- Webhook handling: Set up webhooks to receive real-time notifications about payment events, such as successful payments, refunds, or chargebacks. This allows you to automate order fulfillment, update inventory, and keep customers informed about their transactions. You can refer to the [Webhooks documentation](/documentation/get_started/webhooks) for more details on how to set up and manage webhooks with Ryft.