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

> Details on working with the headless Buy frame used in the [Pay with card](/platform/guides/pay-with-card) flow.

The Buy frame is a headless frame. It evaluates transaction requirements, creates
the transaction, and completes post-transaction processing — all without
rendering any UI. Your confirmation screen, loading states, and purchase button
remain fully under your control.

## URL

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

## Requirements

### Size

The frame is headless. Mount it with zero dimensions so it does not affect your
layout:

```tsx Example theme={null}
<iframe
  src="https://blocks.moonpay.com/platform/v1/buy?..."
  style="position: absolute; width: 0; height: 0; border: none; overflow: hidden;"
/>
```

## 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). Below are the
event payloads specific to the Buy frame.

### 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 buy pipeline is starting. Use this to show a loading indicator in your UI.

<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 BuyCompleteEvent = 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 BuyChallengeEvent = 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 BuyErrorEvent = 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>
