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

# Buy Button

> Details on working with the Buy Button frame, an express-checkout payment button that runs the same buy orchestration as the headless [Buy frame](/platform/frames/buy).

The Buy Button frame renders a compact express-checkout payment button. It shows
the available payment options — Apple Pay, Google Pay, and card — and opens a
confirmation sheet when the customer taps to pay. Behind the UI, it runs the same
buy orchestration pipeline as the headless [Buy frame](/platform/frames/buy):
it evaluates transaction requirements, creates the transaction, and completes
post-transaction processing.

The difference is the experience. The Buy frame is headless and leaves every
screen under your control. The Buy Button frame provides a visible payment button
and confirmation sheet, so you can offer express checkout without building that UI
yourself. The message protocol is identical to the Buy frame, so you handle the
same events either way.

## URL

```
https://blocks.moonpay.com/platform/v1/buy-button
```

## Initialization parameters

| Property                | Type     | Required | Description                                                                                                                                                                                    |
| ----------------------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `clientToken`           | `string` | ✅        | The [client token](/platform/guides/api-and-sdk-credentials#client-token) returned from the [connect flow](/platform/guides/connect-a-customer).                                               |
| `channelId`             | `string` | ✅        | A unique identifier for the frame generated on your client. This value is attached to each `postMessage` payload to help identify messages.<br /><br />The format of this string is up to you. |
| `signature`             | `string` | ✅        | The quote `signature` from the [quote endpoint](/api-reference/platform/endpoints/quotes/get). Pass `signature` as returned.                                                                   |
| `externalTransactionId` | `string` |          | Your own identifier for the transaction. Stored and associated with the MoonPay transaction for correlation.                                                                                   |

## Events

All events are dispatched using the message pattern described in the [frames
protocol](/platform/frames/overview#frames-protocol#messages). The Buy Button frame
uses the same event payloads as the [Buy frame](/platform/frames/buy); only the
experience differs.

### Outbound events

<Badge size="md" className="px-2" color="purple">
  frame->parent
</Badge>

These events are sent from this frame to the parent window.

#### `handshake`

The frame requests that you open a message channel.

<CodeGroup>
  ```json Example theme={null}
  {
    "version": 2,
    "meta": { "channelId": "ch_1" },
    "kind": "handshake"
  }
  ```

  ```ts twoslash TypeScript definition theme={null}
  type Message<T> = T & {
    version: 2;
    meta: { channelId: string };
  };

  type HandshakeEvent = Message<{
    kind: "handshake";
  }>;
  ```
</CodeGroup>

#### `ready`

The frame finished loading and the payment button is rendered. Use this to
coordinate UI transitions if needed.

<CodeGroup>
  ```json Example theme={null}
  {
    "version": 2,
    "meta": { "channelId": "ch_1" },
    "kind": "ready"
  }
  ```

  ```ts twoslash TypeScript definition theme={null}
  type Message<T> = T & {
    version: 2;
    meta: { channelId: string };
  };

  type ReadyEvent = Message<{
    kind: "ready";
  }>;
  ```
</CodeGroup>

#### `complete`

The transaction is complete. Use the transaction ID to track final status via
polling.

<CodeGroup>
  ```json Example theme={null}
  {
    "version": 2,
    "meta": { "channelId": "ch_1" },
    "kind": "complete",
    "payload": {
      "transaction": {
        "id": "txn_01",
        "status": "pending"
      }
    }
  }
  ```

  ```ts twoslash TypeScript definition theme={null}
  type Message<T> = T & {
    version: 2;
    meta: { channelId: string };
  };

  type BuyButtonCompleteEvent = Message<{
    kind: "complete";
    payload: {
      transaction: {
        id: string;
        status: "pending" | "completed" | "failed";
      };
    };
  }>;
  ```
</CodeGroup>

#### `challenge`

Verification is required before the transaction can proceed. Render the
[challenge frame](/platform/frames/challenge) at the provided URL. Do not
construct the URL yourself — use it as-is.

<CodeGroup>
  ```json Example theme={null}
  {
    "version": 2,
    "meta": { "channelId": "ch_1" },
    "kind": "challenge",
    "payload": {
      "kind": "frame",
      "url": "https://blocks.moonpay.com/platform/v1/challenge?challengeToken=..."
    }
  }
  ```

  ```ts twoslash TypeScript definition theme={null}
  type Message<T> = T & {
    version: 2;
    meta: { channelId: string };
  };

  type BuyButtonChallengeEvent = Message<{
    kind: "challenge";
    payload: {
      kind: string;
      /** Fully-formed URL to pass directly as the challenge frame src. */
      url: string;
    };
  }>;
  ```
</CodeGroup>

#### `error`

A terminal error occurred. Remove the frame and surface the message to the
developer.

<CodeGroup>
  ```json Example theme={null}
  {
    "version": 2,
    "meta": { "channelId": "ch_1" },
    "kind": "error",
    "payload": {
      "code": "invalidQuote",
      "message": "Unable to decode the quote signature."
    }
  }
  ```

  ```ts twoslash TypeScript definition theme={null}
  type Message<T> = T & {
    version: 2;
    meta: { channelId: string };
  };

  type BuyButtonErrorEvent = Message<{
    kind: "error";
    payload: {
      code: "configurationError" | "invalidQuote" | "generic";
      /** A developer-facing error message. Not intended to be rendered in UI. */
      message: string;
    };
  }>;
  ```
</CodeGroup>

| Code                 | Description                              |
| -------------------- | ---------------------------------------- |
| `configurationError` | Missing or invalid `signature` parameter |
| `invalidQuote`       | Unable to decode the quote signature     |
| `generic`            | Unspecified error                        |

### Inbound events

<Badge size="md" className="px-2">
  parent->frame
</Badge>

These events are sent from the parent window to this frame.

#### `ack`

Acknowledge the [handshake](#handshake).

<CodeGroup>
  ```json Example theme={null}
  {
    "version": 2,
    "meta": { "channelId": "ch_1" },
    "kind": "ack"
  }
  ```

  ```ts twoslash TypeScript definition theme={null}
  type Message<T> = T & {
    version: 2;
    meta: { channelId: string };
  };

  type AckEvent = Message<{
    kind: "ack";
  }>;
  ```
</CodeGroup>

#### `setQuote`

Provide a new quote to the frame. Send this when the current quote expires
before the customer completes the purchase. Pass `signature` as returned by the
quote endpoint.

<CodeGroup>
  ```json Example theme={null}
  {
    "version": 2,
    "meta": { "channelId": "ch_1" },
    "kind": "setQuote",
    "payload": {
      "quote": {
        "signature": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9..."
      }
    }
  }
  ```

  ```ts twoslash TypeScript definition theme={null}
  type Message<T> = T & {
    version: 2;
    meta: { channelId: string };
  };

  type SetQuoteEvent = Message<{
    kind: "setQuote";
    payload: {
      quote: {
        /** The signature from a valid quote. */
        signature: string;
      };
    };
  }>;
  ```
</CodeGroup>
