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

# Card JavaScript SDK integration

> Accept AUD and USD card payments in your checkout with the Hello Clever JavaScript SDK: setup, initialisation, payment creation, callbacks, and token reuse.

The JavaScript SDK lets you accept card payments securely in your checkout flow with a few lines of code. Hello Clever renders the card form inside an iframe, so raw card details never touch your frontend or servers.

This guide covers setup, initialisation, payment creation, and callback handling.

> [!NOTE]
>
> Supported currencies: **AUD** and **USD**.

## Environments

| Environment | Script URL |
| - | - |
| Sandbox | `https://cdn.lightningpay.me/media/getkollo-sdk/1.1.0/sandbox/getkollo.js` |
| Production | `https://cdn.lightningpay.me/media/getkollo-sdk/1.1.0/prod/getkollo.js` |

To see the SDK running, visit the [demo website](https://demo-getkollo-five.vercel.app).

## Integration steps

**1. Register your app ID and domain**

Contact the Hello Clever team to register your domain and receive your `app_id`.

**2. Include the SDK script in your checkout page**

```html theme={null}
<script
  src="https://cdn.lightningpay.me/media/getkollo-sdk/1.1.0/sandbox/getkollo.js"
  async
></script>
```

Switch to the production script URL when you go live.

**3. Add a mount element to your HTML**

```html theme={null}
<div class="get-kollo"></div>
```

The SDK injects the payment iframe into this element. It must exist before you call `createPayment()`.

**4. Initialise the SDK and create a payment**

```javascript theme={null}
async function createGetKollo() {
  const getKolloSDK = new GetKollo({
    app_id: "your-app-id",
  });

  const init = await getKolloSDK.initialize();
  if (!init?.success) return alert(init?.error);

  const order = {
    external_id: "order-001",
    customer_name: "John Doe",
    customer_email: "john.doe@example.com",
    amount: 1000,
    currency: "USD",
    return_url: "https://yourdomain.com/success",
    payment_type: "regular",
  };

  const options = {
    mountElement: ".get-kollo",
    styleProps: {
      frame: {
        width: "100%",
        height: "100%",
      },
    },
  };

  const resp = await getKolloSDK.createPayment(order, options);
  if (!resp?.success) return alert(resp?.error);

  window.getkolloCardCallback = (message) => {
    if (message?.status !== "succeeded") {
      alert(message?.error);
    }
  };
}
```

## SDK configuration reference

### `GetKollo({ app_id })`

Creates an SDK instance.

| Field | Type | Required | Description |
| - | - | - | - |
| `app_id` | string | Yes | Your unique application identifier. |

```javascript theme={null}
const getKolloSDK = new GetKollo({
  app_id: "your-app-id",
});

const init = await getKolloSDK.initialize();
```

### `createPayment(order, options)`

Creates the payment and renders the card form in your mount element.

#### `order` (required)

| Field | Type | Required | Description |
| - | - | - | - |
| `external_id` | string | Yes | Unique identifier for the order. |
| `customer_name` | string | No | Name of the customer. |
| `customer_email` | string | No | Email of the customer. |
| `amount` | number | Yes | Transaction amount in cents. |
| `currency` | string | Yes | `USD` or `AUD`. |
| `return_url` | string | No | URL to redirect to after success or failure. |
| `payment_type` | enum | No | `regular` or `unscheduled`. Defaults to `regular`. See [Payment types](#payment-types). |

#### `options` (required)

| Field | Type | Required | Description |
| - | - | - | - |
| `mountElement` | string | Yes | CSS selector (class or ID) of the element that hosts the iframe. |
| `styleProps.frame.width` | string | No | Width of the iframe. Defaults to `500px`. |
| `styleProps.frame.height` | string | No | Height of the iframe. Defaults to `500px`. |
| `paymentButton` | enum | No | `iframe` (default) uses the payment button inside the iframe. `external` lets you use your own button outside the iframe; you must then call `getKolloSDK.onSubmit()` when it is clicked. |
| `events` | object | No | Event handlers. `onReady()` fires when the payment form is fully loaded and ready for input. `onLoading(isLoading)` reports the loading state, so you can manage your external button. |

```javascript theme={null}
const order = {
  external_id: "order-001",
  customer_name: "John Doe",
  customer_email: "john.doe@example.com",
  amount: 1000,
  currency: "USD", // USD or AUD
  return_url: "https://yourdomain.com/success", // optional redirect URL
  payment_type: "regular", // optional: "regular" | "unscheduled"
};

const options = {
  mountElement: ".get-kollo", // element class name or ID
  styleProps: {
    frame: {
      width: "100%",
      height: "100%",
    },
  },
  paymentButton: "iframe",
  events: {
    // Fires when the payment form is fully loaded and ready for input.
    onReady: () => {
      console.log("Payframe is ready.");
    },
    // With paymentButton: "external", use this to manage your button's loading state.
    onLoading: (isLoading) => {
      console.log(`Payframe loading state: ${isLoading}`);
    },
  },
};

const resp = await getKolloSDK.createPayment(order, options);
```

### `onSubmit(payload)`

Submits the card form when `paymentButton` is set to `external`. Call it from your own button's click handler.

| Field | Type | Required | Description |
| - | - | - | - |
| `country` | string | Yes | Two-letter country code ([ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)). |

```javascript theme={null}
const payload = {
  country: "AU",
};

getKolloSDK.onSubmit(payload);
```

### Payment status callback

After the payment is submitted, or if the card form fails to render, the SDK calls `window.getkolloCardCallback`:

```javascript theme={null}
window.getkolloCardCallback = (response) => {
  if (response?.status !== "succeeded") {
    // If the card form fails to render within 7 seconds, the SDK returns an error code.
    if (response?.error?.code === "card_init_timeout") {
      // Handle the rendering timeout.
    } else {
      alert(response?.error?.message);
    }
  }
};
```

| Field | Description |
| - | - |
| `status` | `succeeded` or `failed`. |
| `error` | An error object with `message` and `code`. The `card_init_timeout` code means the card form failed to render. |
| `order` | The order object you passed to the SDK. |
| `type` | Always `callback`. |

> [!NOTE]
>
> The callback reflects what happened in the browser. Confirm the final payment status from your [webhook notifications](#webhook-notifications) before you fulfil the order.

## Payment types

### Regular payment

Customers can choose to store their card details during a payment. You can then use them for future payments without the customer re-entering them.

**SCA requirements:** in regions that require Strong Customer Authentication (SCA), the customer must complete a 3D Secure (3DS) challenge during payment. When SCA is required, the API response includes a `pay_code.3ds_url` field. Redirect your customer to this URL to complete authentication.

**Set up a regular payment:** pass `payment_type: "regular"` in the `order` object when you call `createPayment()`. This is optional, because `regular` is the default.

```javascript theme={null}
const order = {
  external_id: "order-001",
  customer_name: "John Doe",
  customer_email: "john.doe@example.com",
  amount: 1000,
  currency: "USD",
  return_url: "https://yourdomain.com/success",
  payment_type: "regular",
};

const resp = await getKolloSDK.createPayment(order, options);
```

### Unscheduled payment

With an unscheduled payment agreement, you store a customer's card details during an initial transaction. You can then make a card-not-present transaction with the stored card later.

For example, a customer gives their card details when checking in to a hotel, but is only charged at check-out, by which time they may have incurred extra charges.

**SCA requirements:** merchant-initiated transactions fall outside the scope of SCA and qualify for the Merchant Initiated Exclusion, so 3DS authentication is not required.

**Set up an unscheduled payment:**

**1. Initial payment (SDK)**

Pass `payment_type: "unscheduled"` in the `order` object when you call `createPayment()`. This stores the customer's card details.

```javascript theme={null}
const order = {
  external_id: "order-001",
  customer_name: "John Doe",
  customer_email: "john.doe@example.com",
  amount: 1000,
  currency: "USD",
  return_url: "https://yourdomain.com/success",
  payment_type: "unscheduled",
};

const resp = await getKolloSDK.createPayment(order, options);
```

**2. Subsequent payments (Tokenisation API)**

Charge the saved token with [Create Payment via Tokenisation](/api/cards/create-payment-via-tokenisation), using these fields:

* `payment_type`: set to `unscheduled`.
* `previous_payment_uuid`: the `uuid` returned for the initial payment. It references the original SCA-authorised transaction and improves approval rates.
* `charge_reason`: recommended, because it improves approval rates and chargeback handling. Use one of:
  * `resubmission`: the original purchase happened, but you could not get authorisation when the goods or services were provided.
  * `delayed_charge`: there is a delayed charge.
  * `no_show`: the cardholder agreed to a purchase but did not meet the terms of the agreement.
  * `reauthorisation`: an additional purchase was made after the original one, typically for delayed or split orders.

```json Request theme={null}
{
  "amount": 100,
  "currency": "AUD",
  "token": {
    "id": "tok_dfe1988a1ffc0d6562d3",
    "type": "card"
  },
  "external_id": "order_test_xxx",
  "return_url": "https://example.com",
  "capture": false,
  "payment_type": "unscheduled",
  "charge_reason": "delayed_charge",
  "previous_payment_uuid": "7PPPMXIGH",
  "webhook_notification": {
    "endpoint_url": "https://merchant.com/webhook",
    "authorization_header": "Bearer xxxxxx"
  }
}
```

```json Response theme={null}
{
  "uuid": "7PPPMXIGH",
  "name": "Testing",
  "email": "john.doe@example.com",
  "external_id": "wc_order_6C1hcvg4T7Pom",
  "status": "authorised",
  "currency": "AUD",
  "amount": 100,
  "total": 100,
  "paid_amount": 0,
  "is_refundable": true,
  "payment_method": "card",
  "capture": false,
  "payment_type": "unscheduled",
  "token": {
    "id": "tok_dfe1988a1ffc0d6562d3",
    "type": "card"
  },
  "created_at": "2025-05-28T04:22:21.567+0000"
}
```

## Reuse tokens for future payments

Call [Create Payment via Tokenisation](/api/cards/create-payment-via-tokenisation) with your saved token (`token.id` and `token.type`). `payment_type` defaults to `regular` if you omit it. For the differences between `regular` and `unscheduled`, see [Payment types](#payment-types).

```json Request theme={null}
{
  "amount": 100,
  "currency": "AUD",
  "token": {
    "id": "tok_dfe1988a1ffc0d6562d3",
    "type": "card"
  },
  "external_id": "order_test_xxx",
  "return_url": "https://example.com",
  "capture": false,
  "payment_type": "regular",
  "webhook_notification": {
    "endpoint_url": "https://merchant.com/webhook",
    "authorization_header": "Bearer xxxxxx"
  }
}
```

```json Response theme={null}
{
  "uuid": "7PPPMXIGH",
  "name": "Testing",
  "email": "john.doe@example.com",
  "external_id": "wc_order_6C1hcvg4T7Pom",
  "status": "pending",
  "pay_code": {
    "3ds_url": "https://3ds-auth.example.com/verify"
  },
  "currency": "AUD",
  "amount": 100,
  "total": 100,
  "paid_amount": 0,
  "is_refundable": true,
  "payment_method": "card",
  "expired_at": "",
  "webhook_notification": {
    "endpoint_url": "https://merchant.com/webhook",
    "authorization_header": "****"
  },
  "refund_information": null,
  "sender_details": {
    "card": {
      "card_type": "card",
      "card_brand": "visa",
      "card_last_4": "1111",
      "card_country": "US"
    }
  },
  "capture": false,
  "payment_type": "regular",
  "token": {
    "id": "tok_dfe1988a1ffc0d6562d3",
    "type": "card"
  },
  "created_at": "2025-05-28T04:22:21.567+0000"
}
```

If the response includes `pay_code.3ds_url`, redirect your customer there to complete 3DS. After authorisation, they return to your `return_url`.

## Webhook notifications

When the payment status changes (for example, `pending` to `authorised` to `waiting`), Hello Clever sends a webhook event to your configured endpoint.

When the payment reaches `authorised` or `waiting`, the webhook includes a `token` object:

```json theme={null}
{
  "token": {
    "id": "tok_dfe1988a1ffc0d6562d3",
    "type": "card"
  }
}
```

> [!WARNING]
>
> Save `token.id` securely in your database. You can reuse it for future payments without the customer re-entering their card details.

See [Webhooks](/api/webhooks) for the payload structure, token inclusion after authorisation, setup, and webhook security.

## Payment statuses

| Status | Meaning |
| - | - |
| `pending` | The customer started a payment but has not proceeded yet. |
| `authorised` | The payment is authorised and ready to capture. |
| `waiting` | The payment is approved and awaiting settlement. |
| `received` | Funds have been received. |
| `expired` | The payment session expired before completion. |
| `return_pending` | A refund was requested and is awaiting processing. |
| `partially_refunded` | A partial refund was issued to the customer. |
| `return_received` | The full amount was refunded to the customer. |
| `return_expired` | The refund expired (after 10 days). |
| `return_rejected` | The refund request was denied. |
| `failed` | The payment failed due to an error or decline. |
| `in_dispute` | The customer raised a dispute, which is under review. |
| `dispute_lost` | The dispute was resolved in the customer's favour. |


## Related topics

- [Card Payment API Overview](/api/card/overview.md)
- [Issue and Manage Card Payments](/developer-reference/api-use-cases/issue-and-manage-cards.md)
- [Hello Clever API Overview](/api/overview.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.