> ## 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.

# Versions and lifecycle

> Understand immutable SDK releases, session lifetime, donation attempts, recurring plans, and cleanup.

## SDK versions and upgrades

An SDK URL identifies a particular release:

```text theme={null}
https://sdk.pay.wegive.com/v0.1.0/wegive-pay.iife.js
```

Published version URLs retain their original bytes. A new SDK release gets a new
version path; deploying your website or WeGive's hosted checkout does not replace
your pinned SDK file. There is no unversioned `latest` URL to follow automatically.

Versioned SDK assets use long-lived caching, with
`Cache-Control: public, max-age=31536000, immutable`. This one-year cache lifetime
controls how browsers and caches reuse a file. It is **not** the SDK's expiration
date, a payment-session lifetime, or a promise of an indefinite support period.
An older file remaining available does not mean it supports every newer feature.

To upgrade:

1. Review the target release's integration changes with WeGive. Treat updates
   within the initial `0.x` series as changes that need testing.
2. Update the versioned URL and its integrity hash together, or replace your
   complete vendored release directory.
3. Exercise your payment methods, themes, callbacks, and retry handling with test
   keys. Run your application's normal type and build checks.
4. Deploy the updated reference. Keep the previous version reference available
   for rollback if it remains supported for your integration.

Pinning the SDK pins the JavaScript files you load. It does not freeze the hosted
pop-up, API, or payment-provider services. Those services are managed by WeGive.
Contact WeGive about compatibility and supported releases before depending on an
older version for an extended period.

| Release | Integration surface |
| - | - |
| `0.1.0` | Hosted pop-up, branded buttons, Payframes, fraud-session creation, attribution helpers, and public TypeScript declarations |

## The lifetimes are different

| Resource | Lifetime and responsibility |
| - | - |
| Pinned SDK files | Reuse across page loads; upgrade deliberately by changing the version |
| Publishable and secret keys | Managed credentials; maintain permissions and rotate or revoke them through your account |
| SDK instance | Reuse within a browser page for the same key; recreate when your application changes credentials |
| Mounted button | Keep while its page/component is displayed; call `unmount()` when removing it |
| Open pop-up | One checkout invocation; completes with a result or detects the window closing |
| Payframes fields | Keep for the current form; call `destroy()` when removing it |
| Fraud session | Short-lived authorization context; use the returned `expiresAt`, not a hard-coded duration |
| Tokenized card values | Submit promptly for the authorized donation; do not treat them as a reusable customer wallet |
| Idempotency key | Identifies one backend payment attempt; retain it and the exact request while resolving the outcome |
| Recurring plan | A server-side schedule that continues independently of the page or SDK instance until it ends or is cancelled |

## Pop-up lifecycle

Initialize the SDK, then call `mountButton()` or `open()` from a user interaction.
The pop-up handles the donor flow and returns one terminal SDK result:
`success`, `pending`, `scheduled`, `cancel`, or `error`.

A result promise and its corresponding callback describe the **same** checkout.
Use one primary completion handler to avoid duplicate application side effects.
`pending` means payment is awaiting confirmation; `scheduled` means a recurring
plan was created without an initial payment. Neither means a payment settled.

Closing the window or receiving `cancel` is not proof that an already submitted
payment did not reach WeGive. If the donor closes checkout during processing,
check the recorded result before inviting a replacement donation.

Removing the button only removes that button and its listener. It does not cancel
an open checkout, refund a transaction, or stop a recurring plan. The SDK does not
expose a programmatic payment-cancellation or refund method.

## Payframes and fraud-session lifecycle

Mounting Payframes establishes the browser context for tokenization. Calling
`tokenize()` returns card values and, when available, a `fraudSessionId`. Include a
valid fraud-session handle in your backend processing request.

A form can remain open longer than its fraud session. Tokenizing an already
mounted form does not guarantee the original session was refreshed. For a
long-lived form, obtain a fresh session near the **first submission**:

```js theme={null}
const tokenized = await fields.tokenize();
const session = await pay.createFraudSession();

const submission = {
  tokenized: { ...tokenized, fraudSessionId: session.id },
};
// Send submission to your backend for a new, donor-authorized attempt.
// session.expiresAt is the session's expiration timestamp.
```

Session creation performs verification and can fail. Stop submission and show an
appropriate retry/support message if it fails; never bypass it. Do not store
fraud sessions across donors or reuse them for unrelated donation attempts.

After your backend submits a payment, freeze that attempt's original payload.
Do **not** obtain a replacement session, retokenize, or change the body when
retrying an uncertain request under the same idempotency key. Follow the
[processing API retry rules](/external/onboarding/wegive-pay/processing-api#idempotency-and-retries).

## Cleanup in a single-page application

Keep the handles returned by SDK methods and release them in your framework's
unmount hook:

```js theme={null}
const button = pay.mountButton('#donate', { amount: 5000, label: 'Donate' });
// When removing the component:
button.unmount();
```

Payframes mounting is asynchronous. If navigation can happen while mounting,
destroy a handle that arrives after its component was removed:

```js theme={null}
let removed = false;
let fields;

async function mountFields() {
  const handle = await pay.payframes.mount({
    cardNumber: '#card-number',
    cardExpiry: '#card-expiry',
    cardCvv: '#card-cvv',
  });
  if (removed) handle.destroy();
  else fields = handle;
}

function cleanup() {
  removed = true;
  fields?.destroy();
  fields = undefined;
}
```

Also remove your own event listeners and timers. Handle errors from `mountFields()`
in your component's error state. Mounting again requires fresh field entry;
`destroy()` does not cancel any backend request already sent.


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