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

# Hosted pop-up checkout

> Add a Pay with WeGive button, open checkout from your own UI, and handle one-time and recurring donations.

The hosted pop-up handles donor identification, available payment methods,
confirmation, and donation results. Your website supplies the donation context
and controls what happens when checkout finishes. No secret key is needed for
this integration.

Complete [access and keys](/external/onboarding/wegive-pay/setup-requirements)
first. Replace the publishable-key placeholder below with your own test key.

## Add a donation button

```html theme={null}
<div id="wegive-donate"></div>
<p id="donation-status" role="status" aria-live="polite"></p>

<script
  src="https://sdk.pay.wegive.com/v0.1.0/wegive-pay.iife.js"
  integrity="sha384-FpXrJhUXBouGVVeqCRCgBlpMiJZdasKl+jVqJ+Li//qXB1nkAIQrAseifHBXlj+3"
  crossorigin="anonymous"
></script>
<script>
  const pay = WeGive.Pay.init({
    publishableKey: 'pk_test_REPLACE_WITH_YOUR_KEY',
  });
  const status = document.querySelector('#donation-status');

  const button = pay.mountButton('#wegive-donate', {
    amount: 5000,
    frequency: 'once',
    label: 'Donate',
    onSuccess(transaction) {
      status.textContent = `Thank you! Donation reference: ${transaction.id}.`;
    },
    onPending(transaction) {
      status.textContent = `Payment awaiting confirmation. Reference: ${transaction.id}.`;
    },
    onScheduled(planId) {
      status.textContent = `Recurring donation scheduled. Plan reference: ${planId}.`;
    },
    onCancel() {
      status.textContent = 'Checkout closed.';
    },
    onError() {
      status.textContent = 'Checkout could not complete. Check the payment status before trying again.';
    },
  });
</script>
```

`amount` is an integer in the processing currency's minor units: `5000` means
50.00 for a two-decimal currency. Do not pass a formatted string or a decimal
currency amount. Omitting `currency` uses the organization's currency. An
explicit ISO currency code must match that currency; it does not convert funds.

`label` is required and controls the button text. The button loads your
organization's branding automatically. Use the
[customization guide](/external/onboarding/wegive-pay/customization) for overrides.
Call `button.unmount()` when removing the component.

## Open checkout from your own button

Use `pay.open()` when your own form supplies the current amount or you want full
control over the launch button. It accepts the same options as `mountButton()`.

```html theme={null}
<button id="custom-donate" type="button">Donate</button>
<p id="custom-status" role="status"></p>
```

```js theme={null}
const launch = document.querySelector('#custom-donate');
const message = document.querySelector('#custom-status');

launch.addEventListener('click', async () => {
  launch.disabled = true;
  try {
    // Call directly from the click handler, before awaiting other work.
    const result = await pay.open({ amount: 5000, label: 'Donate' });
    switch (result.status) {
      case 'success':
        message.textContent = `Thank you! Reference: ${result.transaction.id}.`;
        break;
      case 'pending':
        message.textContent = 'Your payment is awaiting confirmation.';
        break;
      case 'scheduled':
        message.textContent = `Plan ${result.scheduledDonationId} is scheduled.`;
        break;
      case 'cancel':
        message.textContent = 'Checkout closed.';
        break;
      case 'error':
        message.textContent = 'Checkout could not complete. Check your payment status before retrying.';
        break;
    }
  } catch {
    message.textContent = 'Checkout could not start. Please contact us if this continues.';
  } finally {
    launch.disabled = false;
  }
});
```

Prepare asynchronous application data before enabling the launch button. Waiting
for a network request before calling `open()` can cause popup blocking. On mobile,
checkout opens in a separate tab and uses the same result promise. A blocked
window produces an `error` result; ask the donor to allow pop-ups or open your
page in their regular browser.

Use the SDK to open checkout. Do not construct a checkout URL yourself, embed the
checkout in an iframe, or build your own window-message listener.

## Understand the result

| Result | Data | Meaning |
| - | - | - |
| `success` | `transaction` | WeGive reports a successful transaction |
| `pending` | `transaction` | Accepted for processing; final confirmation is pending |
| `scheduled` | `scheduledDonationId` | A future recurring plan exists; no initial payment was taken |
| `cancel` | No transaction is guaranteed | The window closed or checkout was cancelled |
| `error` | Optional `error` string | Checkout could not start or complete |

`transaction` contains `id`, integer `amount`, and `status`. A recurring result
with an initial transaction can also include `scheduledDonationId` alongside
`success` or `pending`.

The corresponding callbacks are `onSuccess(transaction)`,
`onPending(transaction)`, `onScheduled(planId)`, `onCancel()`, and
`onError(error)`. A callback and a resolved promise handle the same result.
Avoid recording a donation twice by handling it through both paths.

Use these results to update your page, not as trusted server-side proof of payment.
Reconcile donations using their WeGive records. A pending bank payment is not
settled revenue. A closed window or lost connection does not prove an in-flight
donation failed. See [lifecycle and retries](/external/onboarding/wegive-pay/versions-and-lifecycle).

## Accept recurring donations

Add a `monthly-donate` mount element and pass the schedule agreed with the donor:

```js theme={null}
pay.mountButton('#monthly-donate', {
  amount: 2500,
  label: 'Give monthly',
  frequency: 'recurring',
  recurringFrequency: 'monthly',
  onScheduled(planId) {
    document.querySelector('#donation-status').textContent = `Plan ${planId} is scheduled.`;
  },
});
```

Supported `recurringFrequency` values are `daily`, `weekly`, `1_and_15`,
`bimonthly`, `monthly`, `quarterly`, `semiannual`, and `yearly`.
Use the schedule supported by your account.

`recurringStartDate` and `recurringEndDate` use `YYYY-MM-DD`. Omitting the start
date starts today and can take the first payment immediately. A future start
creates a plan without charging today. Handle `success` and `pending` for an
initial payment, as well as `scheduled` for a future start.

The plan continues on WeGive after the donor closes their browser. Removing the
button does not cancel it. Manage plans in WeGive or, for an authorized backend
integration, use the [recurring-plan API](/external/onboarding/wegive-pay/processing-api#recurring-plans).

## Pass donation context and attribution

Pass numeric `designationId`, `campaignId`, `fundraiserId`,
`campaignFundraiserId`, `checkoutId`, `campaignEventId`, or
`organizationBrandId` when relevant. Use identifiers belonging to your
organization and validate selections in your application.

`organizationBrandId` identifies the financial brand associated with the donation.
Visual theme settings control appearance separately; choosing a logo does not
select a financial brand or processor.

The SDK forwards UTM values from the current page URL. To carry attribution you
persisted on your own site, pass the complete desired set:

```js theme={null}
const donationOptions = {
  amount: 5000,
  label: 'Support the campaign',
  campaignId: 123,
  organizationBrandId: 456,
  trackingUrl: 'https://giving.example.org/spring',
  utmParams: {
    utm_source: 'newsletter',
    utm_medium: 'email',
    utm_campaign: 'spring',
  },
};
```

The supported UTM keys are `utm_source`, `utm_medium`, `utm_campaign`, `utm_term`,
`utm_content`, and `utm_id`. A nonempty explicit set wins as a whole; it is not
merged field by field with the current URL. The SDK's attribution helper does not
read or write cookies. Your application owns any cross-page attribution storage
and consent handling.

`trackingUrl` defaults to the embedding page URL. Provide a clean source URL when
your page URL contains private query parameters. Do not put secrets or sensitive
donor information in URLs, theme copy, or attribution fields.

See the [SDK reference](/external/onboarding/wegive-pay/sdk-reference) for all
donation options, including email prefill, fee coverage, and tributes.


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