Skip to main content

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.

Render the Add Card frame in your app so the customer can save a new credit or debit card. Card data is captured inside a PCI-compliant MoonPay-hosted UI rendered in a react-native-webview and never touches your app code.
Unlike the Apple Pay and Google Pay frames, the Add Card frame does not emit a ready event. The card form renders immediately when the frame is set up.
Setup Add Card
import {
  useMoonPay,
  type AddCardEvent,
} from "@moonpay/platform-sdk-react-native";

export function AddCardScreen() {
  const { client } = useMoonPay();

  const start = async () => {
    const addCardResult = await client.setupAddCard({
      onEvent: (event: AddCardEvent) => {
        switch (event.kind) {
          case "complete":
            // Card added. Use event.payload.card.id to get a quote.
            console.log(event.payload.card);
            break;
          case "error":
            console.error(event.payload.code, event.payload.message);
            break;
        }
      },
    });

    if (!addCardResult.ok) {
      // Handle error
      console.error(addCardResult.error.kind, addCardResult.error.message);
      return;
    }

    const addCard = addCardResult.value;
  };

  // ...
}

Parameters

PropertyTypeRequiredDescription
onEvent(event: AddCardEvent) => voidCallback invoked for Add Card flow events. See AddCardEvent.
This method does not require a separate auth token. The client uses stored credentials from an active connection.

AddCardEvent

onEvent receives events as the Add Card flow progresses. Use event.kind to decide how to handle each event.
kindPayloadWhen you receive it
"complete"{ card: CardResponse }The card was saved successfully.
"error"AddCardEventErrorThe flow encountered an error.
The Add Card frame does not emit a ready event — the card form is visible as soon as the frame is set up.

CardResponse

The card object returned when the customer finishes adding a card. Use id directly in getQuote — there is no need to re-fetch payment methods.
FieldTypeRequiredDescription
idstringThe stored card identifier.
typestringThe payment method type, typically "card".
cardTypestringThe card sub-type (for example, "credit" or "debit").
brandstringThe card network brand (for example, "visa", "mastercard").
last4stringThe last four digits of the card number.
expirationMonthstringThe card expiration month, as a two-digit string (for example, "04").
expirationYearstringThe card expiration year, as a four-digit string (for example, "2030").
availability{ active: true }The card is available for new transactions when the frame returns it.

AddCardEventError

FieldTypeRequiredDescription
code"configurationError" | "generic"The error category.
messagestringDeveloper-friendly details.

Result

client.setupAddCard() returns a Result<AddCardFrame, SetupAddCardError>.

Result envelope

Result<AddCardFrame, SetupAddCardError>
FieldTypeRequiredDescription
okbooleanWhether the operation succeeded.
valueAddCardFramePresent when ok is true.
errorSetupAddCardErrorPresent when ok is false.

AddCardFrame

FieldTypeRequiredDescription
dispose() => voidUnmounts the frame. After you call this, no further events are dispatched to your onEvent callback.
The Add Card frame does not expose a setQuote method — quotes are issued after the card is saved.

SetupAddCardError

FieldTypeRequiredDescription
kind"configurationError" | "genericError"The error category.
messagestringDeveloper-friendly details.

Example: Add a card, then buy

After the complete event fires, pass card.id to getQuote and use the returned signature with setupBuy to execute the transaction. For the full end-to-end walkthrough, see the Pay with card guide.
Add card, then buy
import {
  useMoonPay,
  type AddCardEvent,
  type BuyEvent,
} from "@moonpay/platform-sdk-react-native";

export function AddCardThenBuy() {
  const { client } = useMoonPay();

  const start = async () => {
    const addCardResult = await client.setupAddCard({
      onEvent: async (event: AddCardEvent) => {
        if (event.kind !== "complete") return;

        const cardId = event.payload.card.id;

        // Tear down the Add Card frame — we have the card we need.
        addCardResult.value.dispose();

        // Request a quote for the new card.
        const quoteResult = await client.getQuote({
          source: "USD",
          destination: "ETH",
          sourceAmount: "100.00",
          walletAddress: "0x1234567890abcdef1234567890abcdef12345678",
          paymentMethod: { type: "card", id: cardId },
        });

        if (!quoteResult.ok) {
          // Handle error
          return;
        }

        // Execute the transaction with the headless buy frame.
        const buyResult = await client.setupBuy({
          quote: quoteResult.value.data.signature,
          onEvent: (event: BuyEvent) => {
            // Handle buy events (see the Pay with card guide).
          },
        });

        if (!buyResult.ok) {
          // Handle error
          return;
        }
      },
    });

    if (!addCardResult.ok) {
      // Handle error
      return;
    }
  };

  // ...
}
types.ts
type AddCardFrame = {
  dispose: () => void;
};

type CardResponse = {
  id: string;
  /** Payment method type, typically "card". */
  type: string;
  /** Card sub-type, for example "credit" or "debit". */
  cardType: string;
  /** Card network brand, for example "visa" or "mastercard". */
  brand: string;
  last4: string;
  /** Two-digit month string, for example "04". */
  expirationMonth: string;
  /** Four-digit year string, for example "2030". */
  expirationYear: string;
  availability: { active: true };
};

type AddCardEvent =
  | {
      kind: "complete";
      payload: {
        card: CardResponse;
      };
    }
  | {
      kind: "error";
      payload: AddCardEventError;
    };

type AddCardEventError = {
  code: "configurationError" | "generic";
  /** A developer-facing error message. Not intended to be rendered in UI. */
  message: string;
};

type SetupAddCardError = {
  kind: "configurationError" | "genericError";
  message: string;
};