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

# Payment Portal

> Hosted payment page for collecting customer payments

Every payment created via the [Payments API](/platform/payments/overview) returns a `paymentUrl` pointing to a hosted payment page. You can share this URL directly with your customer or embed it in your application as an iframe.

## Standalone usage

Share the `paymentUrl` with your customer via link, email, or redirect. When the customer completes the payment:

* If you provided a `successRedirectUrl`, the customer is redirected there
* If you provided a `failureRedirectUrl`, the customer is redirected there on failure
* If no redirect URLs are set, the portal displays a confirmation message

## Embedding the payment portal

You can embed the payment page directly in your application for an in-app checkout experience.

### Prerequisites

<Warning>
  **Domain whitelisting required.** Before embedding, contact [support@paygentic.io](mailto:support@paygentic.io) to have your domain whitelisted. Paygentic must grant permission for your domain before the embedded portal will work.
</Warning>

Add `platform.paygentic.io` to your Content Security Policy `frame-src` directive:

```text theme={null}
Content-Security-Policy: frame-src 'self' https://platform.paygentic.io;
```

### Implementation

<CodeGroup>
  ```html HTML theme={null}
  <iframe
    src="https://platform.paygentic.io/portal/pay/SESSION_ID"
    width="100%"
    height="800px"
    sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
    style="border: none; border-radius: 8px;"
  ></iframe>

  <script>
    window.addEventListener('message', function(event) {
      if (event.origin !== 'https://platform.paygentic.io') return;

      if (event.data?.type === 'payment_success') {
        window.location.href = '/success';
      } else if (event.data?.type === 'payment_error') {
        alert('Payment failed. Please try again.');
      }
    });
  </script>
  ```

  ```jsx React theme={null}
  import { useEffect } from 'react';

  export function PaymentCheckout({ paymentUrl, onSuccess, onError }) {
    useEffect(() => {
      const handleMessage = (event) => {
        if (event.origin !== 'https://platform.paygentic.io') return;

        if (event.data?.type === 'payment_success') {
          onSuccess?.();
        } else if (event.data?.type === 'payment_error') {
          onError?.();
        }
      };

      window.addEventListener('message', handleMessage);
      return () => window.removeEventListener('message', handleMessage);
    }, [onSuccess, onError]);

    return (
      <iframe
        src={paymentUrl}
        width="100%"
        height="800px"
        sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
        style={{ border: 'none', borderRadius: '8px' }}
      />
    );
  }
  ```
</CodeGroup>

Replace `SESSION_ID` with the session ID from the `paymentUrl` returned by the API. The `paymentUrl` is in the format `https://platform.paygentic.io/portal/pay/{sessionId}`.

## Handling payment events

When embedded in an iframe, the portal sends `postMessage` events instead of redirecting. Listen for these events to update your UI:

| Event type        | When triggered                  |
| ----------------- | ------------------------------- |
| `payment_success` | Payment completed successfully  |
| `payment_error`   | Payment failed or was cancelled |

<Note>
  **How redirects work:** When the portal is loaded as a standalone page, it uses `successRedirectUrl` and `failureRedirectUrl` for navigation. When embedded in an iframe, it sends `postMessage` events instead. The portal detects the context automatically.
</Note>

<Accordion title="Understanding sandbox attributes">
  The `sandbox` attribute is required for security. Each value serves a specific purpose:

  * `allow-scripts` — Portal JavaScript functionality
  * `allow-same-origin` — Communication between the portal and your site
  * `allow-forms` — Payment form submission
  * `allow-popups` — 3D Secure authentication popups
</Accordion>

## Next steps

* [Payments](/platform/payments/overview) — Create payments via the API
* [Customer Lifecycle](/platform/billing/customer-lifecycle) — Subscription portal and customer management
* [Create Payment API Reference](/api-reference/payments/create-payment) — Full endpoint documentation
