> For the complete documentation index, see [llms.txt](https://docs.antivamp.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.antivamp.io/for-launchpads/embed-reserve-widget.md).

# Hosted Reserve Widget

Embed the hosted AntiVamp Reserve widget in your launchpad so creators can reserve a name + ticker without you handling an API key or a wallet.

> **Creators reserve inside your UI. You never touch an API key, a private key, or a payment.**

The Reserve widget is an iframe hosted by AntiVamp. The creator connects their own wallet and signs the reservation transaction inside the frame, so no key of yours — and no key of theirs — ever crosses into your page. Reservations completed in the widget are attributed to your launchpad automatically for revenue share.

{% hint style="info" %}
🔑 There is **no browser API key**. Attribution is derived server-side from your allowlisted launchpad slug and origin. Never put an `av_live_…` key in front-end code.
{% endhint %}

## 📦 Install

```html
<div id="antivamp-reserve"></div>
<script src="https://antivamp.io/embed/reserve.js"></script>
<script>
  const widget = AntiVampReserve.mount("#antivamp-reserve", {
    launchpad: "your-launchpad-slug",
    chain: "solana",
    theme: "dark",
    onReady: () => console.log("widget ready"),
    onQuote: (quote) => console.log("quote", quote),
    onConfirmed: (result) => {
      // Fires only after the chain confirms inclusion.
      console.log(result.identityKey, result.txSig, result.protectedUntil);
    },
    onError: (err) => console.error(err),
  });
</script>
```

## ⚙️ Options

| Option            | Required                 | Notes                                                                                                                                                 |
| ----------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `launchpad`       | ✅                        | Your approved slug. Must be allowlisted for your origin, or the API returns `403 launchpad_not_allowed`.                                              |
| `chain`           | —                        | Initial chain: `solana`, `base`, `bnb`, `ethereum`, `robinhood`, `hyperliquid` (the id from `GET /v1/chains`; the alias `hyperevm` is also accepted). |
| `theme`           | —                        | `dark` (default) or `light`.                                                                                                                          |
| `primaryColor`    | —                        | Accent override, when enabled for your profile.                                                                                                       |
| `returnUrl`       | —                        | Must be on an allowlisted origin.                                                                                                                     |
| `signing`         | —                        | `parent` enables [parent signing](#-parent-signing-privy-and-embedded-wallets) for Privy / embedded wallets. Requires `signTransaction`.              |
| `signTransaction` | with `signing: "parent"` | Async callback that signs + sends the transaction with the creator's wallet on **your** page and returns the signature / hash.                        |
| `wallet`          | —                        | Creator wallet address. Only meaningful with `signing: "parent"` — in the default mode the creator connects inside the iframe and this is ignored.    |

## 📡 Events

| Event         | Payload                                                                       |
| ------------- | ----------------------------------------------------------------------------- |
| `onReady`     | —                                                                             |
| `onQuote`     | `{ chain, tier, amountAtomic, amountUi, asset, expiresAt }`                   |
| `onSigned`    | `{ reservationId, identityKey, txSig }`                                       |
| `onConfirmed` | `{ reservationId, identityKey, txSig, protectedUntil, protectedUntilSource }` |
| `onError`     | `{ code, message }`                                                           |
| `onCancel`    | —                                                                             |

`protectedUntilSource` is `onchain` when the value came from the settled on-chain expiry, or `estimate` when the settle call could not be reached and the tier duration was used as a fallback. Treat `estimate` as provisional and confirm with `GET /v1/reservations/status` or `GET /v1/identity/check`.

## 🔧 Methods

```js
widget.set({ name: "Green Robin", ticker: "ROBIN", chain: "base" }); // prefill
widget.destroy();                                                    // unmount
```

{% hint style="warning" %}
👤 In the default mode, `set()` cannot supply a wallet. The creator connects and signs inside the iframe, so a parent-supplied address could never sign — passing one has no effect. With `signing: "parent"` the wallet **is** settable (`widget.set({ wallet })`), because your page does the signing.
{% endhint %}

## 🔏 Parent signing (Privy and embedded wallets)

If your launchpad manages creator wallets with an embedded wallet provider such as **Privy**, the creator's wallet lives in **your** page's session — the AntiVamp iframe can never reach it (it is cross-origin by design). Opening a browser-extension wallet inside the frame would ask the creator to pay from the wrong wallet.

Parent-signing mode inverts the flow: the widget builds the unsigned payment transaction and hands it to your page over `postMessage`. Your page signs and sends it with the creator's Privy wallet, returns the signature, and the widget resumes its normal on-chain confirmation and settlement flow. AntiVamp never sees a private key, and your page never sees an API key.

```html
<div id="antivamp-reserve"></div>
<script src="https://antivamp.io/embed/reserve.js"></script>
<script>
  const widget = AntiVampReserve.mount("#antivamp-reserve", {
    launchpad: "your-launchpad-slug",
    chain: "solana",
    signing: "parent",
    wallet: creatorWalletAddress, // the creator's Privy wallet
    signTransaction: async (request) => {
      if (request.chain === "solana") {
        // request.transactionBase64 is the unsigned, serialized transaction.
        const tx = Transaction.from(Buffer.from(request.transactionBase64, "base64"));
        // Privy React: useSignAndSendTransaction / wallet.signAndSendTransaction
        const { signature } = await privyWallet.signAndSendTransaction(tx);
        return { signature };
      }
      // EVM chains: request has { to, data, value (hex wei), chainId }.
      const { hash } = await privyEvmWallet.sendTransaction({
        to: request.to,
        data: request.data,
        value: request.value,
        chainId: request.chainId,
      });
      return { txHash: hash };
    },
    onConfirmed: (result) => console.log(result.identityKey, result.txSig),
  });

  // If the creator switches Privy wallets, keep the widget in sync:
  widget.set({ wallet: newAddress });
</script>
```

Details that matter:

* `signTransaction` receives `{ requestId, chain, wallet, name, ticker }` plus `transactionBase64` (Solana) or `to` / `data` / `value` / `chainId` (EVM). Returning a bare string also works — it is treated as a Solana signature or an EVM hash based on the chain.
* The widget waits up to **3 minutes** for your callback, then fails the attempt safely (nothing is reserved until the chain confirms).
* The wallet address must match the active chain's format (base58 for Solana, `0x…` for EVM). On mismatch the widget falls back to the in-frame wallet pickers rather than dead-ending.
* Throwing inside `signTransaction` (e.g. the creator dismissed the Privy prompt) surfaces as a normal, retryable payment error in the widget.
* Confirmation is still verified by the widget against the chain — a bad or fabricated signature never produces an `onConfirmed`.

## 🔐 Origin and framing rules

* Your origin must be allowlisted for the launchpad slug. Requests from other origins get `403 origin_not_allowed`.
* The widget page sets `Content-Security-Policy: frame-ancestors` to your approved hosts, so only they can frame it.
* Every `postMessage` is origin-pinned in both directions. Validate `event.origin` in your own listener if you handle messages directly instead of using `reserve.js`.
* Staging hosts must be allowlisted explicitly. Arbitrary preview domains are **not** trusted in production.

## ✅ What the widget does and does not guarantee

| Guarantee                                                  | Status                                                                                                        |
| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| Creator pays on-chain and holds the identity               | ✅ after `onConfirmed`                                                                                         |
| Reservation attributed to your launchpad for revenue share | ✅ once settle verifies the transaction                                                                        |
| Copycats blocked on **your** launchpad                     | ⚠️ only if you also call [`POST /v1/launches/validate`](/for-launchpads/validate-every-launch.md) server-side |
| Copycats blocked on **other** launchpads                   | ⚠️ only on integrated launchpads that enforce AntiVamp decisions                                              |

{% hint style="danger" %}
🛡️ The widget sells and records protection — it does **not** enforce it. Enforcement happens when your backend validates every launch against a signed decision. See the [Enforcement guide](/for-launchpads/enforcement-guide.md).
{% endhint %}

## 🧪 Testing

Point the widget at a sandbox launchpad slug to exercise the flow without real payments. Sandbox reservations are labelled `simulated` and never imply production protection. See [Sandbox](/for-launchpads/sandbox.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.antivamp.io/for-launchpads/embed-reserve-widget.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
