# Embed a Pay button

> Drop a "Pay with Soca" button onto any website with one script tag. It opens Soca’s hosted checkout in a popup and can tell your page when the payment completes.

Part of the Soca documentation (https://soca.finance/docs). Human version: https://soca.finance/docs/developers/embed
The embed is the fastest way to take a payment from a site you already have: paste one script tag and one button, and you have a working "Pay with Soca" button. No framework, no build step, no keys on the page. It works on plain HTML, and inside React, Vue, Webflow, WordPress, or a no-code builder.

> **How the embed relates to the hosted checkout**: The button does not render a payment form on your page. It opens Soca’s hosted, non-custodial checkout (the same `checkout_url` the API returns) in a centered popup. Checkout stays on Soca because wallet signing cannot run safely inside a third-party site. This is the same model as Stripe Payment Links and Coinbase Commerce.

## Add the button

Create an invoice (one-time) or a plan (subscription) first — from the dashboard or the API — and copy its id. Then add the script once, and a button wherever you want it:

**One-time payment (invoice)**

```html
<!-- Load once, anywhere on the page -->
<script src="https://YOUR-SOCA-ORIGIN/embed.js" async></script>

<!-- Repeat this button as many times as you like -->
<button data-soca data-soca-invoice="inv_123">Pay with Soca</button>
```

**Subscription (plan price)**

```html
<button data-soca data-soca-price="price_123">Subscribe with Soca</button>
```

Replace `YOUR-SOCA-ORIGIN` with your Soca domain (the same origin your dashboard and `checkout_url`s use). If you already have a full `checkout_url`, you can skip the ids and point the button straight at it with `data-soca-url`.

## Options

Configure a button with `data-` attributes. If the button element is empty, the script styles it and fills in the label; if it already has your own markup, the script leaves the look alone and only wires up the click.

| Attribute | Values | What it does |
| --- | --- | --- |
| `data-soca` | (flag) | Marks the element as a Soca pay button. Required. |
| `data-soca-invoice` | invoice id | Opens the checkout for a one-time invoice. |
| `data-soca-price` | price id | Opens the checkout for a subscription plan price. |
| `data-soca-url` | checkout URL | An explicit `checkout_url`. Overrides invoice/price. |
| `data-soca-mode` | `popup` · `tab` · `redirect` | How checkout opens. Default `popup`; falls back to a new tab if popups are blocked. |
| `data-soca-label` | text | Button text, used only when the element is empty. |
| `data-soca-theme` | `light` · `dark` | Style of the auto-rendered button. Default `light`. |

## Know when a payment completes

When the popup checkout confirms a payment, Soca sends a message back to your page. Listen for it to show a thank-you, unlock content, or redirect. Two equivalent ways:

**Success callback**

```html
<script>
  // Runs once the embed script has loaded
  window.addEventListener('load', function () {
    Soca.on('success', function (detail) {
      // e.g. show a confirmation, redirect, or reveal a download
      console.log('Payment complete', detail);
    });
  });

  // Or listen for the DOM event, from anywhere
  document.addEventListener('soca:success', function (e) {
    console.log('Payment complete', e.detail);
  });
</script>
```

> **Confirm real payments server-side**: The success message is a convenience for updating your UI. It is not proof of payment and can be spoofed by a hostile page. For anything that must be trustworthy — fulfilling an order, granting access — rely on the [`invoice.paid` / `subscription.active` webhook](/docs/developers/webhooks), which is signed and authoritative.

## Programmatic use

You do not need the `data-` button at all. Call the checkout yourself — handy in a single-page app or when the amount is decided at runtime:

```javascript
// Open checkout for an invoice you just created
Soca.checkout({ invoice: 'inv_123' });

// Or a subscription, in a new tab instead of a popup
Soca.checkout({ price: 'price_123', mode: 'tab' });

// Or an explicit hosted URL
Soca.checkout({ url: 'https://YOUR-SOCA-ORIGIN/invoice/inv_123' });

// If you inject buttons after page load, re-scan for them
Soca.refresh();
```

## Good to know

- The script is dependency-free and self-contained; it derives your Soca origin from its own `src`, so there is nothing to configure.
- No secrets ever touch the page. The button only points at a hosted checkout URL — your API key stays on your server.
- Checkout cannot be shown in an `<iframe>` on your site (it is frame-denied on purpose, and wallet signing does not work framed). The popup model is deliberate, not a limitation to work around.
- Card and bank checkout are [coming soon](/docs/business/payments); today the hosted checkout the button opens settles in USDC.
