> ## Documentation Index
> Fetch the complete documentation index at: https://developers.paychoice.com.au/llms.txt
> Use this file to discover all available pages before exploring further.

# PayChoice Widget

> Embed the hosted payment page in an iframe so card and bank details never touch your systems.

The PayChoice Widget is a hosted payment page you embed in an iframe. Customers enter their card or bank details on the PayChoice page, so sensitive data never passes through your systems and your PCI scope stays small. It supports card and bank payments, is responsive, and can be [branded](https://developers.paychoice.com.au/taking-payments/brand-settings.md) to match your site.

## Environments

| Environment | Payment page URL |
| - | - |
| Sandbox | `https://sandbox-spa.paychoice.com.au/renderPaymentPage` |
| Production | `https://spa.paychoice.com.au/renderPaymentPage` |

The path is case-insensitive.

## Before you start

1. **A public key.** PayChoice provides it when onboarding completes. It identifies your merchant (or, for partners, your agency).
2. **A registered webhook.** The final transaction result is delivered there; it is the only message you should fulfil orders from. See [Webhooks](https://developers.paychoice.com.au/getting-the-result/webhooks.md).

## Embed the Widget

Load the payment page in an iframe with the parameters below as a query string. URL-encode the values, in particular `PublicKey`.

**Amount** `decimal` *required*

Transaction amount, e.g. `10.00`. Must be greater than 0. Charged as-is in the merchant's currency; there is no currency parameter.

**MerchantReference** `string` *required*

Your reference for the transaction, e.g. `INV-10101534`. It should be unique per transaction. It becomes the charge's `reference` and is echoed back in the `postMessage` and in the webhook, so use it to match the result to your order.

**PublicKey** `string` *required*

Public key provided during onboarding. Can be a merchant-level or agency-level key.

**MerchantGuid** `uuid`

Required when the public key covers more than one merchant (an agency or agency-group key), to identify which merchant the payment belongs to.

**Method** `string` (default: all)

`card`, `bank` or `all`. Lowercase. Restricts which payment types the customer can choose.

**RequireConfirm** `boolean`

`true` keeps the Pay button disabled until your page posts `{ "type": "pc-submit-status", "data": true }` into the iframe. Any other value posted later disables it again. See [Messages from your page to the Widget](#messages-from-your-page-to-the-widget).

**meta** `string`

Free-text value passed through to the charge as `meta_data_reference`. Silently dropped if longer than 2048 characters. Not included in the webhook payload.

```html theme={null}
<iframe
  height="400"
  width="800"
  src="https://sandbox-spa.paychoice.com.au/renderPaymentPage?Amount=155.50&MerchantReference=INV-12&PublicKey={YOUR_URL_ENCODED_PUBLIC_KEY}"
  frameborder="0">
</iframe>
```

## Payment flow

**1. The customer pays**

They see the payment methods enabled for your merchant account, enter their details, accept the PayChoice terms and click **Confirm and Pay**.

**2. The Widget creates the charge**

It shows the result to the customer and sends a `postMessage` to your page so you can update your own UI.

> [!WARNING]
>
> The `postMessage` is for display only. Do not process or fulfil the order from it.

**3. The webhook delivers the final result**

Every Widget charge triggers the merchant [webhook](https://developers.paychoice.com.au/getting-the-result/webhooks.md) with the standard `charge` payload. Match on `charge.reference` (your `MerchantReference`), check `charge.status_code`, and verify the signature before acting.

Bank payments are `Processing` (status code 9) at submit time; the final outcome comes only through the webhook.

## Messages from the Widget to your page

All messages are sent to `window.parent`. **Always check `event.origin`** against the Widget host you embedded.

> [tab] Charge completed
>
> Sent whenever a charge was created, whatever its status (Approved, Dishonoured, Processing …):
>
> ```json theme={null}
> {
>   "type": "pc-transaction-v1",
>   "data": {
>     "TransactionReference": "12345678-abcd-4321-efgh-9876543210ab",
>     "data": {
>       "created": "01/01/2025 12:00:00",
>       "amount": 99.99,
>       "currency": "AUD",
>       "error": "",
>       "error_code": "",
>       "id": "abcdef12-3456-7890-abcd-ef1234567890",
>       "link": {
>         "href": "/api/v4/charge/abcdef12-3456-7890-abcd-ef1234567890",
>         "rel": "self"
>       },
>       "reference": "test-ref-001",
>       "aggregator_reference": "123456789012",
>       "merchantguid": "11223344-5566-7788-99aa-bbccddeeff00",
>       "status": "Approved",
>       "status_code": "0",
>       "card_type": "Visa"
>     }
>   }
> }
> ```
>
> * `data.data` is the charge object. `data.data.id` is the charge ID and matches `charge.id` in the webhook.
> * `data.TransactionReference` is the Widget's own session identifier. It does **not** appear in the webhook; match on `reference` or `id` instead.
> * `status_code` is a string here and a number in some API responses — compare loosely or normalise.

> [tab] Page could not load
>
> Sent for missing or invalid parameters, an invalid key, or no payment methods available:
>
> ```json theme={null}
> {
>   "type": "pc-transaction-v1",
>   "data": null,
>   "error": {
>     "message": "Public Key is required",
>     "field": "PublicKey"
>   }
> }
> ```
>
> `field` is one of `Amount`, `MerchantReference`, `PublicKey`, `Transaction` or `Merchant`.

> [tab] Submit errors
>
> If the charge request itself fails, the error is shown inside the iframe only; no `postMessage` is sent. Your page will learn the outcome from the webhook.

### Listener

```javascript theme={null}
const PAYCHOICE_ORIGIN = 'https://sandbox-spa.paychoice.com.au'; // production: https://spa.paychoice.com.au

window.addEventListener('message', (event) => {
  if (event.origin !== PAYCHOICE_ORIGIN) return;

  const msg = event.data;
  if (!msg || msg.type !== 'pc-transaction-v1') return;

  if (msg.error) {
    console.warn('Widget error:', msg.error.message);
    return;
  }

  const charge = msg.data.data;
  console.log('Status:', charge.status, 'Reference:', charge.reference, 'Charge id:', charge.id);
  // Display only. Fulfil the order from the server-side webhook, not from this message.
});
```

## Messages from your page to the Widget

Only used with `RequireConfirm=true`:

```javascript theme={null}
iframe.contentWindow.postMessage(
  { type: 'pc-submit-status', data: true },
  'https://spa.paychoice.com.au'
);
```

The Widget sends no resize or height messages.

## Next

* [Brand settings](https://developers.paychoice.com.au/taking-payments/brand-settings.md) to match the Widget to your site.
* [Webhooks](https://developers.paychoice.com.au/getting-the-result/webhooks.md) to receive the result.
* [Create Token page](https://developers.paychoice.com.au/storing-payment-methods/create-token-page.md) to capture a payment method without charging it.


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