Skip to main content
This integration is currently in preview and subject to change.
Frames communicate with your app using postMessage. Each frame defines its own events and payloads. If you use the MoonPay SDK, it handles message serialization, validation, and dispatch for you. If you integrate frames directly (for example, with your own WebView or iframe wrapper), this page documents the shared protocol so you know what to implement.

Libraries

Coming soon! If you’re not using the SDK, MoonPay libraries can help you manage postMessage communication on web and mobile (via WebViews). Until those ship, use the protocol details below to build your own bridge.

Frames protocol

Messages

Frames use an event-driven model. You and the frame exchange events using a strongly typed message structure. Treat these messages like an API contract between two parties: the parent window (or app) and the frame.

Transport

In both web and mobile apps, frames send and receive messages over postMessage as stringified JSON. If you integrate directly, you handle serialization and validation yourself. If you use the SDK, it handles this for you.

Format

Every message follows the same envelope format. The kind tells you what event you’re handling, and the payload shape depends on that kind.
FieldTypeRequiredDescription
version2✅The frames protocol version.

This value will always be 2.
metaobject✅Transport metadata for the message.
meta.channelIdstring✅A unique identifier for messages between frames.
kindenum<FrameEventKind>✅The name of the event.
payloadobjectAn object containing the data for different events. This value depends on the kind.
{
  "version": 2,
  "meta": {
    "channelId": "some_unique_value"
  },
  "kind": "example",
  "payload": {
    "example": "an example payload"
  }
}

Validation and safety checks

You’ll have an easier time (and fewer mysterious bugs) if you validate messages like you would any external input:
  • Check the origin and sender: only accept messages from the frame origin(s) you expect, and ignore everything else.
  • Parse defensively: postMessage delivers strings; treat JSON parsing as fallible and handle errors.
  • Verify the envelope: reject messages that don’t match the expected version, don’t include a meta.channelId, or use an unknown kind.
  • Route by channelId: if you can have multiple frames open at once, use meta.channelId to keep messages from crossing streams.

Lifecycle

Each frame follows the same basic handshake lifecycle to establish a bi-directional channel with your app. The SDK manages this automatically and gives you an events callback; in a direct integration, you implement these steps yourself. In practice, you’ll typically: generate a channel, wait for the handshake, ack it, then start handling kind events for that channel. If the handshake doesn’t arrive quickly, fail fast and show a useful error to the developer (or retry, if that fits your app).