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

# External payment button

> Host your own pay CTA with hidePaymentButton and submitPayment

Render your own pay button outside the widget iframe while keeping card fields, validation, and payment processing inside the widget.

## Overview

Set `hidePaymentButton: true` to hide the in-iframe **Pay** and **Upsell** buttons. Call `submitPayment()` or `submitUpsell()` from the host page when the user clicks your custom button.

Apple Pay and Google Pay still render in host containers via `applePayContainerId` / `googlePayContainerId`.

## Configuration

```javascript theme={null}
{
  hidePaymentButton: true,
  productId: YOUR_PRODUCT_ID,
  sessionId: 'YOUR_SESSION_ID',
  environment: 'sandbox',
  amount: 29.99,
  customer: { email: 'customer@example.com', country: 'US' },
}
```

## Host API

### Vanilla JavaScript

```javascript theme={null}
const widget = PaySightSDK.createWidget({ targetId: 'widget', config, onMessage });

document.getElementById('pay-btn').onclick = () => widget.submitPayment();
```

| Method            | Use when                                        |
| ----------------- | ----------------------------------------------- |
| `submitPayment()` | Card checkout (normal form)                     |
| `submitUpsell()`  | Page 2 upsell / `usePreviousPaymentMethod` flow |

Wait for `READY` before enabling your button.

## Layout

```
┌─────────────────────────┐
│  Widget iframe          │
│  (fields + card, no btn)│
└─────────────────────────┘
│  Your order summary     │
│  Your checkbox          │
┌─────────────────────────┐
│  [ Pay $29.99 ]  host   │
└─────────────────────────┘
```

## Events

| Event                               | When                                       |
| ----------------------------------- | ------------------------------------------ |
| `ERROR`                             | Validation or guard failure                |
| `PAYMENT_START`                     | Card payment attempt started               |
| `PAYMENT_SUCCESS` / `PAYMENT_ERROR` | Checkout or upsell result (`payload.mode`) |

Structured `ERROR` codes: see [Error codes](/widget-sdk/reference/error-codes).

## Subscription opt-out (`singlePurchase`)

When your product includes an optional subscription, use a host checkbox and update the widget before pay:

```javascript theme={null}
// User declined subscription → one-time purchase only
widget.update({ singlePurchase: true });

// User opted in to subscription
widget.update({ singlePurchase: false });
```

| `singlePurchase` | Meaning                                 |
| ---------------- | --------------------------------------- |
| `true`           | Charge without subscription             |
| `false`          | Include subscription per product config |
| omitted          | Default product behavior                |

## Two-page checkout + upsell

Page 1: `hidePaymentButton: true` + `submitPayment()` + `savePaymentMethod: true`.

Page 2: `hidePaymentButton: true` + `submitUpsell()` + `upsell.initialPaymentSession`.

See [Saved payment & upsell](/widget-sdk/guides/saved-payment-and-upsell) and the [external button example](/widget-sdk/examples/external-button-checkout-upsell).

## Live demo

Hosted demo: `https://payment.paysight.io/demo?preset=external-button`

## Related

* [API reference](/widget-sdk/reference/api)
* [Saved payment & upsell](/widget-sdk/guides/saved-payment-and-upsell)
