# Using the Platform API Source: https://dev.moonpay.com/api-reference/platform/documentation/using-the-api Get started with the MoonPay Platform API Looking for the widget API? Take a look at the [reference here](/api-reference/widget). ## Base URL ```bash theme={null} https://api.moonpay.com ``` Test mode vs live mode is determined by the API key you use, not the URL. Use test API key (`sk_test_...`) for test mode and live API keys (`sk_live_...`) for production. ## Authentication Authentication depends on whether you’re calling an endpoint from your server or from the client. ### Server-side Authentication For server-side requests, send your [secret key](/platform/guides/api-and-sdk-credentials#secret-key) in the `Authorization` header. ```ts fetch theme={null} const URL = "https://api.moonpay.com/platform/v1/sessions"; const res = await fetch(URL, { headers: { "Content-Type": "application/json", Authorization: "Api-Key sk_test_123", }, method: "POST", body: JSON.stringify({ externalCustomerId: "your_user_id", deviceIp: "203.0.113.1", }), }); ``` ```sh curl theme={null} curl -X POST "https://api.moonpay.com/platform/v1/sessions" \ -H "Content-Type: application/json" \ -H "Authorization: Api-Key sk_test_123" \ -d '{ "externalCustomerId": "customer1", "deviceIp": "203.0.113.1" }' ``` ### Client-side Authentication For client-side API requests, use the [`accessToken`](/platform/guides/api-and-sdk-credentials#access-token) returned from a connection as a [Bearer token](https://swagger.io/docs/specification/v3_0/authentication/bearer-authentication/). ```ts fetch theme={null} await fetch("https://api.moonpay.com/platform/v1/quotes", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${accessToken}`, }, body: JSON.stringify({ // ... request body ... }), }); ``` ## Response Format Responses are returned as `JSON` with the `content-type: application/json` header. ## Pagination Some requests, like [listing transactions](/api-reference/platform/endpoints/transactions/list), return paginated results using cursor-based pagination. Each response includes a cursor string that you pass to the next request to fetch the next page. The response includes a `pageInfo` object. If `pageInfo.nextCursor` is `null`, there are no more pages. For example: ```json theme={null} { "data": [], "pageInfo": { "nextCursor": "tr_123e4567-e89b-12d3-a456-426614174000" } } ``` ## Rate limits Currently, requests for this integration are limited to 30 per second. ## Debugging Each API response includes a request ID header. Use this ID when working with support: ```bash Example theme={null} X-Request-Id: some-value ``` ## Error Handling When a request fails (4xx), the API returns an error object with details: ```json Example error response theme={null} { "code": 400, "type": "Invalid request", "message": "Invalid request. sourceAmount must be greater than 0." } ``` ## OpenAPI The API follows the [OpenAPI 3.1](https://swagger.io/specification/) specification. You can use the spec to generate typed clients for any language. See the [OpenAPI Spec](/platform/guides/openapi-codegen) page for the full specification and code generation instructions. # Delete a payment method Source: https://dev.moonpay.com/api-reference/platform/endpoints/payment-methods/delete DELETE /platform/v1/payment-methods/{paymentMethodId} Remove a stored payment method for a customer # List payment methods Source: https://dev.moonpay.com/api-reference/platform/endpoints/payment-methods/list GET /platform/v1/payment-methods Get available payment method configurations for a user # Get a quote Source: https://dev.moonpay.com/api-reference/platform/endpoints/quotes/get POST /platform/v1/quotes/buy Build quotes for fiat->crypto transactions # Create a session Source: https://dev.moonpay.com/api-reference/platform/endpoints/sessions/create POST /platform/v1/sessions Create a session token to initialize a connection # Revoke a session Source: https://dev.moonpay.com/api-reference/platform/endpoints/sessions/revoke DELETE /platform/v1/sessions Revoke an active session token # Get a transaction Source: https://dev.moonpay.com/api-reference/platform/endpoints/transactions/get GET /platform/v1/transactions/{id} Get details for a single transaction by ID # List transactions Source: https://dev.moonpay.com/api-reference/platform/endpoints/transactions/list GET /platform/v1/transactions List transactions for the connected user with optional date filtering and pagination # Asset Source: https://dev.moonpay.com/api-reference/platform/objects-and-types/asset A fiat currency or crypto token ## Properties | Property | Type | Required | Description | | ----------- | ------- | -------- | ------------------------------------------------------------- | | `code` | string | Yes | The currency code or token symbol (e.g., `USD`, `ETH`, `BTC`) | | `name` | string | No | The human-readable name (e.g., `US Dollar`, `Ethereum`) | | `precision` | integer | No | The number of supported decimal places | ## Example ```json theme={null} { "code": "ETH", "name": "Ethereum", "precision": 18 } ``` ## Common Assets ### Fiat Currencies | Code | Name | Precision | | ----- | ------------- | --------- | | `USD` | US Dollar | 2 | | `EUR` | Euro | 2 | | `GBP` | British Pound | 2 | ### Cryptocurrencies | Code | Name | Precision | | ------ | -------- | --------- | | `BTC` | Bitcoin | 8 | | `ETH` | Ethereum | 18 | | `USDC` | USD Coin | 6 | # Fees Source: https://dev.moonpay.com/api-reference/platform/objects-and-types/fees Fee breakdown for an operation ## Properties | Property | Type | Required | Description | | ----------- | ------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------- | | `network` | [MonetaryAmount](/api-reference/platform/objects-and-types/fees#monetaryamount) | No | The network fee (e.g., gas fee for blockchain transactions) | | `moonpay` | [MonetaryAmount](/api-reference/platform/objects-and-types/fees#monetaryamount) | No | The MoonPay processing fee | | `ecosystem` | [MonetaryAmount](/api-reference/platform/objects-and-types/fees#monetaryamount) | No | The ecosystem fee, if applicable | | `partner` | [MonetaryAmount](/api-reference/platform/objects-and-types/fees#monetaryamount) | No | **Deprecated.** Use `ecosystem` instead. This field will be removed in a future release. The partner's fee, if applicable | ## MonetaryAmount Each fee is represented as a monetary amount: | Property | Type | Required | Description | | -------------- | ------ | -------- | ---------------------------------------------------- | | `amount` | string | Yes | The numeric amount as a string to preserve precision | | `currencyCode` | string | Yes | The currency code (e.g., `USD`) | ## Example ```json theme={null} { "network": { "amount": "2.50", "currencyCode": "USD" }, "moonpay": { "amount": "3.99", "currencyCode": "USD" }, "ecosystem": { "amount": "1.00", "currencyCode": "USD" }, "partner": { "amount": "1.00", "currencyCode": "USD" } } ``` All fee amounts are strings to preserve decimal precision. Parse them appropriately in your application. # Payment Method Source: https://dev.moonpay.com/api-reference/platform/objects-and-types/payment-method A payment method configuration with its capabilities and availability ## Properties | Property | Type | Required | Description | | -------------- | ------ | -------- | -------------------------------------------------- | | `type` | string | Yes | Payment method type (e.g., `apple_pay`) | | `capabilities` | object | Yes | What this payment method supports | | `availability` | object | Yes | Whether this payment method is currently available | ## Capabilities | Property | Type | Required | Description | | --------------------------- | --------- | -------- | ----------------------------------------------------- | | `supportedCurrencies` | string\[] | Yes | Currencies supported (e.g., `["USD", "EUR"]`) | | `supportedTransactionTypes` | string\[] | Yes | Transaction types supported (e.g., `["buy", "sell"]`) | ## Availability | Property | Type | Required | Description | | ------------------- | ------- | -------- | ------------------------------------------------- | | `active` | boolean | Yes | Whether the payment method is currently available | | `unavailableReason` | string | No | Reason for unavailability, if applicable | ## Payment Method Types | Type | Description | | ----------- | ----------- | | `apple_pay` | Apple Pay | ## Example ```json theme={null} { "type": "apple_pay", "capabilities": { "supportedCurrencies": ["USD", "EUR", "GBP"], "supportedTransactionTypes": ["buy"] }, "availability": { "active": true } } ``` ## Checking Availability Always check `availability.active` before offering a payment method to users. If `active` is `false`, check `unavailableReason` for details: ```json theme={null} { "type": "apple_pay", "capabilities": { "supportedCurrencies": ["USD"], "supportedTransactionTypes": ["buy"] }, "availability": { "active": false, "unavailableReason": "Payment method is in maintenance" } } ``` # Quote Source: https://dev.moonpay.com/api-reference/platform/objects-and-types/quote A quote for a buy transaction with locked rate, fees, and expiry ## Properties | Property | Type | Required | Description | | --------------- | ------------------------------------------------------------------ | -------- | ------------------------------------------------------------------- | | `source` | object | Yes | Source amount and asset (fiat currency) you send | | `destination` | object | Yes | Destination amount and asset (cryptocurrency) the customer receives | | `fees` | [Fees](/api-reference/platform/objects-and-types/fees) | Yes | Breakdown of network, MoonPay, and ecosystem fees | | `wallet` | [Wallet](/api-reference/platform/objects-and-types/wallet) \| null | Yes | Wallet address where crypto will be sent. Null if not yet provided | | `paymentMethod` | object \| null | Yes | Payment method used for this quote. Null if not specified | | `expiresAt` | string (date-time) | Yes | ISO 8601 datetime when the quote expires | | `executable` | boolean | Yes | Whether the quote can be executed | | `signature` | string | Yes | Signature for mounting a payment frame | ## Source / Destination Both `source` and `destination` have the same structure: | Property | Type | Required | Description | | -------- | -------------------------------------------------------- | -------- | -------------------------------------------- | | `amount` | string | Yes | The amount as a string to preserve precision | | `asset` | [Asset](/api-reference/platform/objects-and-types/asset) | Yes | The currency or token | ## Using the Quote Pass the `signature` to the payment frame when you mount it. The frame uses this signature along with the quote data to execute the payment and create the transaction. Quotes expire. Check `expiresAt` and create the transaction before this time. If `executable` is `false`, the customer must provide additional information before you can use this quote. ## Example ```json theme={null} { "source": { "amount": "100.00", "asset": { "code": "USD", "name": "US Dollar", "precision": 2 } }, "destination": { "amount": "0.0025", "asset": { "code": "ETH", "name": "Ethereum", "precision": 18 } }, "fees": { "network": { "amount": "2.50", "currencyCode": "USD" }, "moonpay": { "amount": "3.99", "currencyCode": "USD" } }, "wallet": { "address": "0x1234...abcd" }, "paymentMethod": { "type": "apple_pay" }, "expiresAt": "2026-01-29T14:35:50.000Z", "executable": true, "signature": "eyJhbGciOiJIUzI1NiIs..." } ``` # Transaction Source: https://dev.moonpay.com/api-reference/platform/objects-and-types/transaction A transaction representing a crypto purchase or sale ## Properties | Property | Type | Required | Description | | --------------- | ---------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------- | | `id` | string | Yes | The MoonPay ID of the transaction | | `createdAt` | string (date-time) | Yes | [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) timestamp of when the transaction was created | | `updatedAt` | string (date-time) | Yes | [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) timestamp of when the transaction was last updated | | `status` | string | Yes | The current status: `completed`, `failed`, or `pending` | | `source` | object | Yes | The source amount and asset (fiat currency) | | `destination` | object | Yes | The destination amount and asset (cryptocurrency) | | `fees` | [Fees](/api-reference/platform/objects-and-types/fees) | Yes | Fee breakdown for the transaction | | `wallet` | [Wallet](/api-reference/platform/objects-and-types/wallet) | Yes | The wallet where crypto was delivered | | `customer` | object | Yes | The customer who made the transaction | | `paymentMethod` | object | No | The payment method used | | `stages` | array | No | The stages of the transaction lifecycle | ## Source / Destination Both `source` and `destination` have the same structure: | Property | Type | Required | Description | | -------- | -------------------------------------------------------- | -------- | -------------------------------------------- | | `amount` | string | Yes | The amount as a string to preserve precision | | `asset` | [Asset](/api-reference/platform/objects-and-types/asset) | Yes | The currency or token | ## Customer | Property | Type | Required | Description | | -------- | ------ | -------- | ------------------------------ | | `id` | string | Yes | The MoonPay ID of the customer | ## Transaction Status | Value | Description | | ----------- | ---------------------------------- | | `pending` | Transaction is in progress | | `completed` | Transaction completed successfully | | `failed` | Transaction failed | ## Example ```json theme={null} { "id": "tr_abc123", "createdAt": "2026-01-29T14:30:50.000Z", "updatedAt": "2026-01-29T15:30:50.000Z", "status": "completed", "source": { "amount": "100.00", "asset": { "code": "USD" } }, "destination": { "amount": "0.0025", "asset": { "code": "ETH" } }, "fees": { "network": { "amount": "2.50", "currencyCode": "USD" }, "moonpay": { "amount": "3.99", "currencyCode": "USD" } }, "wallet": { "address": "0x1234...abcd" }, "customer": { "id": "cust_xyz789" }, "paymentMethod": { "type": "apple_pay" } } ``` # Wallet Source: https://dev.moonpay.com/api-reference/platform/objects-and-types/wallet A blockchain wallet address ## Properties | Property | Type | Required | Description | | --------- | ------ | -------- | ---------------------------------------------------------------------------- | | `address` | string | Yes | The wallet address | | `tag` | string | No | An optional memo or destination tag (used by some blockchains like XRP, XLM) | ## Example ### Standard Wallet ```json theme={null} { "address": "0x1234567890abcdef1234567890abcdef12345678" } ``` ### Wallet with Memo/Tag Some blockchains like XRP and XLM require a destination tag or memo to route funds to the correct account: ```json theme={null} { "address": "rN7n3473SaZBCG4dFL83w7a1RXtXtbk2D9", "tag": "12345678" } ``` For blockchains that require tags/memos (XRP, XLM, etc.), always include the `tag` field when provided. Missing tags can result in lost funds. # Widget API Reference Source: https://dev.moonpay.com/api-reference/widget API reference for the MoonPay widget integration. The MoonPay widget integration is powered by two APIs: * **Ramps & Swaps** — buy, sell, and swap quotes; transaction lookups; supported countries, currencies, and payment methods. * **Virtual Accounts** — programmatic on-ramp and off-ramp via virtual bank accounts, plus the associated transaction history. Buy quotes, currency limits, network fees, and transaction lookups. Sell quotes and sell transaction lookups. Swap pairs, quotes, execution, and transaction lookups. Supported countries, currencies, payment methods, and IP-address checks. Token data and token lists for DeFi assets. Programmatic on-ramp and off-ramp via virtual bank accounts. Receive asynchronous notifications when transaction status changes. ## Authentication Most endpoints require an API key. Pass it as the `apiKey` query parameter, or use the `Authorization: Api-Key ` header where indicated. ## Base URL ``` https://api.moonpay.com ``` # Cancel Sell transaction Source: https://dev.moonpay.com/api-reference/widget/cancelselltransaction DELETE /v3/sell_transactions/{transactionId}) # Execute Swap quote Source: https://dev.moonpay.com/api-reference/widget/executeswapquote POST /v4/swap/execute_quote Executes a given swap quote. Refer to our Recipes section for more detailed examples. # Get Real-time Buy quote Source: https://dev.moonpay.com/api-reference/widget/getbuyquote GET /v3/currencies/{currencyCode}/buy_quote Get detailed real-time quote based on the provided currency code, base amount, your extra fee percentage, payment method, and the inclusion of the fees. # Get Buy transaction Source: https://dev.moonpay.com/api-reference/widget/getbuytransaction GET /v1/transactions/{transactionId} Retrieve a transaction by id. This call will return an error if no transaction with the supplied identifier exists. # Get Buy transaction by External identifier Source: https://dev.moonpay.com/api-reference/widget/getbuytransactionbyexternalid GET /v1/transactions/ext/{externalTransactionId} Retrieve a transaction by its externalTransactionId. This is the identifier you assigned the transaction when creating it. This endpoint returns an array of objects because we cannot ensure the uniqueness of externalTransactionId. # List Buy transactions Source: https://dev.moonpay.com/api-reference/widget/getbuytransactions GET /v1/transactions Returns an array of successful Buy transactions which fulfill criteria supplied in the query parameters. Each entry in the array is a separate transaction object. Transactions will be listed from newest to oldest. # List supported countries Source: https://dev.moonpay.com/api-reference/widget/getcountries GET /v3/countries Returns the list of countries currently supported by MoonPay. # List supported currencies Source: https://dev.moonpay.com/api-reference/widget/getcurrencies GET /v3/currencies Returns the list of currencies supported by MoonPay. # Get Crypto Currency limits Source: https://dev.moonpay.com/api-reference/widget/getcurrencylimits GET /v3/currencies/{currencyCode}/limits Returns an object containing minimum and maximum buy amounts including or excluding fees for base and quote currencies. It takes into account the payment method if it's provided, **otherwise it defaults to the payment method with the lowest fees.** # Get customer Source: https://dev.moonpay.com/api-reference/widget/getcustomer GET /v1/customers/{customerId} Returns very basic information about a customer based on their MoonPay ID. For you to be able to retrieve a customer, they must have at least one session initiated with your `Api-Key`. # Get customer by externalId Source: https://dev.moonpay.com/api-reference/widget/getcustomerbyexternalid GET /v1/customers/ext/{customerId} Returns very basic information about a customer based on their external customer ID. For you to be able to retrieve a customer, they must have at least one session initiated with your `API-Key`. Please note that this endpoint returns an array of objects because we cannot ensure the uniqueness of the external customer ID. # Get DeFi token Source: https://dev.moonpay.com/api-reference/widget/getdefitoken GET /v1/defi/token Retrieve defi token for a specific contractAddress and network code # List DeFi tokens Source: https://dev.moonpay.com/api-reference/widget/getdefitokens GET /v1/defi/tokens Search and retrieve a paginated list of defi tokens # Check Customer's IP address Source: https://dev.moonpay.com/api-reference/widget/getipaddress GET /v3/ip_address Returns information about an IP address. If the `isAllowed` flag is set to false, it means that MoonPay accepts citizens of this country but not residents. # Get Crypto network fees Source: https://dev.moonpay.com/api-reference/widget/getnetworkfees GET /v3/currencies/network_fees Returns a set of key-value pairs representing the current network fees of cryptocurrencies against fiat currencies. Supply the codes of the crypto and fiat currencies you are interested in, and MoonPay will return the relevant network fees. # Get off ramp transaction Source: https://dev.moonpay.com/api-reference/widget/getofframptransaction GET /v1/virtual-accounts/transactions/offramp/{transactionId} # Get off ramp transactions Source: https://dev.moonpay.com/api-reference/widget/getofframptransactions GET /v1/virtual-accounts/transactions/offramp # Get on ramp transaction Source: https://dev.moonpay.com/api-reference/widget/getonramptransaction GET /v1/virtual-accounts/transactions/onramp/{transactionId} # Get on ramp transactions Source: https://dev.moonpay.com/api-reference/widget/getonramptransactions GET /v1/virtual-accounts/transactions/onramp # Get Sell quote Source: https://dev.moonpay.com/api-reference/widget/getsellquote GET /v3/currencies/{currencyCode}/sell_quote Returns a set of key-value pairs representing a real-time sell quote for a currency. Supply the currency code, the base amount, your extra fee percentage, the payment method and whether the base amount is inclusive of fees, and MoonPay will return a detailed sell quote. # Get Sell transaction Source: https://dev.moonpay.com/api-reference/widget/getselltransaction GET /v3/sell_transactions/{transactionId} # Get Sell transaction by External identifier Source: https://dev.moonpay.com/api-reference/widget/getselltransactionbyexternalid GET /v3/sell_transactions/ext/{externalTransactionId} Retrieve a transaction by its externalTransactionId. This is the identifier you assigned the transaction when creating it. This endpoint returns an array of objects because we cannot ensure the uniqueness of externalTransactionId. # List Sell transactions Source: https://dev.moonpay.com/api-reference/widget/getselltransactions GET /v1/sell_transactions # Get Swap pairs Source: https://dev.moonpay.com/api-reference/widget/getswappairs GET /v4/swap/pairs Returns the list of swap pairs available to the account. # Get Swap quote Source: https://dev.moonpay.com/api-reference/widget/getswapquote GET /v4/swap/{PAIR}/quote Returns the swap quote for a specific swap pair. # Get Swap requote Source: https://dev.moonpay.com/api-reference/widget/getswaprequote GET /v4/swap/transaction/{transactionId}/requote Returns a swap transaction re quote by id. Refer to our Recipes section for more detailed examples. # Get Swap transaction Source: https://dev.moonpay.com/api-reference/widget/getswaptransaction GET /v4/swap/transaction/{transactionId} Returns a swap transaction by id. Refer to our Recipes section for more detailed examples. # Get virtual accounts Source: https://dev.moonpay.com/api-reference/widget/getvirtualaccounts GET /v1/virtual-accounts # List available payment methods Source: https://dev.moonpay.com/api-reference/widget/listpaymentmethods GET /payments/v1/payment-method-config # Reject Swap requote Source: https://dev.moonpay.com/api-reference/widget/rejectswaprequote POST /v4/swap/reject_requote Rejects a given swap requote. Refer to our Recipes section for more detailed examples. # Update on ramp virtual account Source: https://dev.moonpay.com/api-reference/widget/updateonrampvirtualaccount PATCH /v1/virtual-accounts/onramp/{id} # Buy Source: https://dev.moonpay.com/api-reference/widget/webhooks/buy Currently supported Buy events ## Supported events `transaction_created` `transaction_failed` `transaction_updated` Please note that duplicate events MAY occur and in some occasions, may arrive out of order. We ask partners to de-dupe these events. This is a process of removing identical webhook responses. A complete list of transaction object parameters and values can be found [here](/api-reference/widget/getbuytransaction). ## Examples ```json transaction_created theme={null} { "data": { "isFromQuote": true, "isRecurring": false, "isTicketPayment": false, "id": "bda09e91-559f-4e7a-807a-cdec1a903d9d", "createdAt": "2022-08-31T10:00:03.640Z", "updatedAt": "2022-08-31T10:00:31.251Z", "baseCurrencyAmount": 295.45, "quoteCurrencyAmount": 0.1819, "feeAmount": 3.99, "extraFeeAmount": 0, "networkFeeAmount": 0.56, "areFeesIncluded": true, "flow": "principal", "status": "completed", "walletAddress": "0xc216eD2D6c295579718dbd4a797845CdA70B3C36", "walletAddressTag": null, "cryptoTransactionId": "0x6751c8fce2e0fb5d57bb4801b31b35a7160fa362e0c5703d44cfd508317ee2f8", "failureReason": null, "redirectUrl": "", "returnUrl": "", "widgetRedirectUrl": null, "bankTransferReference": null, "baseCurrencyId": "71435a8d-211c-4664-a59e-2a5361a6c5a7", "currencyId": "8d305f63-1fd7-4e01-a220-8445e591aec4", "customerId": "2fcbcea3-6b62-49f1-b9d1-026d9bfd00b6", "cardId": "de063279-203f-4e31-83c3-e51aa844d8c4", "bankAccountId": null, "eurRate": 1, "usdRate": 0.99812, "gbpRate": 0.85823, "bankDepositInformation": null, "externalTransactionId": null, "feeAmountDiscount": null, "paymentMethod": "credit_debit_card", "baseCurrency": { "id": "71435a8d-211c-4664-a59e-2a5361a6c5a7", "createdAt": "2019-04-22T15:12:07.861Z", "updatedAt": "2022-08-16T13:42:26.618Z", "type": "fiat", "name": "Euro", "code": "eur", "precision": 2, "maxAmount": 10000, "minAmount": 30, "minBuyAmount": 30, "maxBuyAmount": 10000 }, "currency": { "id": "8d305f63-1fd7-4e01-a220-8445e591aec4", "createdAt": "2018-09-28T10:47:49.801Z", "updatedAt": "2022-08-25T16:57:25.823Z", "type": "crypto", "name": "Ethereum", "code": "eth", "precision": 4, "maxAmount": 3, "minAmount": 0.01, "minBuyAmount": 0.01078, "maxBuyAmount": null, "addressRegex": "^[0x](0-9A-Fa-f){40}$", "testnetAddressRegex": "^[0x](0-9A-Fa-f){40}$", "supportsAddressTag": false, "addressTagRegex": null, "supportsTestMode": true, "supportsLiveMode": true, "isSuspended": false, "isSupportedInUS": true, "notAllowedUSStates": ["HI", "NY", "VI"], "notAllowedCountries": [], "isSellSupported": true, "confirmationsRequired": 12, "minSellAmount": 0.025, "maxSellAmount": 8.5, "metadata": { "contractAddress": "0x0000000000000000000000000000000000000000", "chainId": "1", "networkCode": "ethereum" } }, "nftTransaction": null, "stages": [ { "stage": "stage_one_ordering", "status": "success", "actions": [], "failureReason": null }, { "stage": "stage_two_verification", "status": "success", "actions": [], "failureReason": null }, { "stage": "stage_three_processing", "status": "failed", "actions": [], "failureReason": "error" }, { "stage": "stage_four_delivery", "status": "not_started", "actions": [], "failureReason": null } ], "country": "USA", "state": "NJ", "cardType": "card", "cardPaymentType": "debit", "externalCustomerId": "27346528354888", "nftToken": null }, "type": "transaction_created", "externalCustomerId": "27346528354888" } ``` ```json transaction_updated theme={null} { "data": { "isFromQuote": true, "isRecurring": false, "isTicketPayment": false, "id": "bda09e91-559f-4e7a-807a-cdec1a903d9d", "createdAt": "2022-08-31T10:00:03.640Z", "updatedAt": "2022-08-31T10:00:31.251Z", "baseCurrencyAmount": 295.45, "quoteCurrencyAmount": 0.1819, "feeAmount": 3.99, "extraFeeAmount": 0, "networkFeeAmount": 0.56, "areFeesIncluded": true, "flow": "principal", "status": "completed", "walletAddress": "0xc216eD2D6c295579718dbd4a797845CdA70B3C36", "walletAddressTag": null, "cryptoTransactionId": "0x6751c8fce2e0fb5d57bb4801b31b35a7160fa362e0c5703d44cfd508317ee2f8", "failureReason": null, "redirectUrl": "https://api.moonpay.io/v3/three_d_secure?transactionId=bda09e91-559f-4e7a-807a-cdec1a903d9d&sid=6b3652b0-088c-444f-b706-affcdc1ca4db&iframe=true", "returnUrl": "https://buy-sandbox.moonpay.com/transaction_receipt", "widgetRedirectUrl": null, "bankTransferReference": null, "baseCurrencyId": "71435a8d-211c-4664-a59e-2a5361a6c5a7", "currencyId": "8d305f63-1fd7-4e01-a220-8445e591aec4", "customerId": "2fcbcea3-6b62-49f1-b9d1-026d9bfd00b6", "cardId": "de063279-203f-4e31-83c3-e51aa844d8c4", "bankAccountId": null, "eurRate": 1, "usdRate": 0.99812, "gbpRate": 0.85823, "bankDepositInformation": null, "externalTransactionId": null, "feeAmountDiscount": null, "paymentMethod": "credit_debit_card", "baseCurrency": { "id": "71435a8d-211c-4664-a59e-2a5361a6c5a7", "createdAt": "2019-04-22T15:12:07.861Z", "updatedAt": "2022-08-16T13:42:26.618Z", "type": "fiat", "name": "Euro", "code": "eur", "precision": 2, "maxAmount": 10000, "minAmount": 30, "minBuyAmount": 30, "maxBuyAmount": 10000 }, "currency": { "id": "8d305f63-1fd7-4e01-a220-8445e591aec4", "createdAt": "2018-09-28T10:47:49.801Z", "updatedAt": "2022-08-25T16:57:25.823Z", "type": "crypto", "name": "Ethereum", "code": "eth", "precision": 4, "maxAmount": 3, "minAmount": 0.01, "minBuyAmount": 0.01078, "maxBuyAmount": null, "addressRegex": "^(0x)[0-9A-Fa-f]{40}$", "testnetAddressRegex": "^(0x)[0-9A-Fa-f]{40}$", "supportsAddressTag": false, "addressTagRegex": null, "supportsTestMode": true, "supportsLiveMode": true, "isSuspended": false, "isSupportedInUS": true, "notAllowedUSStates": ["HI", "NY", "VI"], "notAllowedCountries": [], "isSellSupported": true, "confirmationsRequired": 12, "minSellAmount": 0.025, "maxSellAmount": 8.5, "metadata": { "contractAddress": "0x0000000000000000000000000000000000000000", "chainId": "1", "networkCode": "ethereum" } }, "nftTransaction": null, "country": "USA", "state": "NJ", "externalCustomerId": "27346528354888", "nftToken": null }, "type": "transaction_updated", "externalCustomerId": "27346528354888" } ``` ```json transaction_failed theme={null} { "data": { "isFromQuote": true, "isRecurring": false, "isTicketPayment": false, "id": "621d21ce-13cc-4e95-af0d-771ae156f92a", "createdAt": "2022-09-13T10:23:26.751Z", "updatedAt": "2022-09-13T10:23:37.505Z", "baseCurrencyAmount": 25.74, "quoteCurrencyAmount": 0.0144, "feeAmount": 3.99, "extraFeeAmount": 0, "networkFeeAmount": 0.27, "areFeesIncluded": true, "flow": "principal", "status": "failed", "walletAddress": "0x00BDBFC6B0584771c28B9092c16AEB31Ad677283", "walletAddressTag": null, "cryptoTransactionId": null, "failureReason": "Failed testnet withdrawal", "redirectUrl": "https://api.moonpay.io/v3/payment?transactionId=621d21ce-13cc-4e95-af0d-771ae156f92a&sid=4ed76ab0-65e1-4624-b0d9-9fce62e41f0b", "returnUrl": "https://buy-sandbox.moonpay.com/transaction_receipt", "widgetRedirectUrl": "https://www.myurl.com", "bankTransferReference": null, "baseCurrencyId": "edd81f1f-f735-4692-b410-6def107f17d2", "currencyId": "8d305f63-1fd7-4e01-a220-8445e591aec4", "customerId": "2fcbcea3-6b62-49f1-b9d1-026d9bfd00b6", "cardId": "de063279-203f-4e31-83c3-e51aa844d8c4", "bankAccountId": null, "eurRate": 0.98363, "usdRate": 1, "gbpRate": 0.8542, "bankDepositInformation": null, "externalTransactionId": null, "feeAmountDiscount": null, "paymentMethod": "credit_debit_card", "baseCurrency": { "id": "edd81f1f-f735-4692-b410-6def107f17d2", "createdAt": "2019-04-29T16:55:28.647Z", "updatedAt": "2022-08-16T13:42:26.618Z", "type": "fiat", "name": "US Dollar", "code": "usd", "precision": 2, "maxAmount": 12000, "minAmount": 30, "minBuyAmount": 30, "maxBuyAmount": 12000 }, "currency": { "id": "8d305f63-1fd7-4e01-a220-8445e591aec4", "createdAt": "2018-09-28T10:47:49.801Z", "updatedAt": "2022-08-25T16:57:25.823Z", "type": "crypto", "name": "Ethereum", "code": "eth", "precision": 4, "maxAmount": 3, "minAmount": 0.01, "minBuyAmount": 0.01078, "maxBuyAmount": null, "addressRegex": "^(0x)[0-9A-Fa-f]{40}$", "testnetAddressRegex": "^(0x)[0-9A-Fa-f]{40}$", "supportsAddressTag": false, "addressTagRegex": null, "supportsTestMode": true, "supportsLiveMode": true, "isSuspended": false, "isSupportedInUS": true, "notAllowedUSStates": ["HI", "NY", "RI", "VI"], "notAllowedCountries": [], "isSellSupported": true, "confirmationsRequired": 12, "minSellAmount": 0.025, "maxSellAmount": 8.5, "metadata": { "contractAddress": "0x0000000000000000000000000000000000000000", "chainId": "1", "networkCode": "ethereum" } }, "nftTransaction": null, "stages": [ { "stage": "stage_one_ordering", "status": "success", "actions": [], "failureReason": null }, { "stage": "stage_two_verification", "status": "success", "actions": [], "failureReason": null }, { "stage": "stage_three_processing", "status": "failed", "actions": [], "failureReason": "error" }, { "stage": "stage_four_delivery", "status": "not_started", "actions": [], "failureReason": null } ], "country": "USA", "state": "NJ", "cardType": "card", "cardPaymentType": "debit", "externalCustomerId": "27346528354888", "nftToken": null }, "type": "transaction_failed", "externalCustomerId": "27346528354888" } ``` ## Properties ```json theme={null} { "event": { "method": "POST", "headers": { "moonpay-signature": "t=1663064622,s=cdd18ef9d85c004638f0e9f770231909d24053b503a8f281991e33280a7a9ba9", "moonpay-signature-v2": "t=1663064622,s=44d8318c5ad1720959799062280f5f0030658776c13804d9edd04fd2c4012f14" } } } ``` # Cancel Sell transaction by externalId Source: https://dev.moonpay.com/api-reference/widget/webhooks/cancelselltransactionbyexternalid DELETE /v3/sell_transactions/ext/{transactionId}) # Overview Source: https://dev.moonpay.com/api-reference/widget/webhooks/overview ## When to utilize Webhooks Webhooks are essential for managing behind-the-scenes transactions. They allow you to receive alerts for asynchronous updates to transaction statuses. MoonPay can send webhook events that notify your application whenever an activity occurs on your account. This feature is particularly valuable for tracking changes like transaction status updates, that are not triggered by a direct API request. These notifications are delivered through HTTP POST requests to any endpoint URLs you've specified in your account's [Webhooks settings](https://dashboard.moonpay.com/developers/#webhooks). MoonPay is capable of sending a single event to multiple webhook endpoints. ## Configuring your Webhook Settings Webhooks are configured in your MoonPay dashboard's [Webhook settings](https://dashboard.moonpay.com/developers/#webhooks). Click Add Endpoint to reveal a form where you can add a new URL for receiving webhooks. Webhooks dashboard You can enter any URL as the destination for events. However, this should be a dedicated page on your server that is set up to receive webhook notifications. You can choose to be notified of all event types, or only specific ones. Using test or live API keys determines whether test events or live events are sent to your configured URL. If you want to send both live and test events to the same URL, you need to create two separate settings. You can add as many URLs as you like. ## Receiving a Webhook Notification Setting up an endpoint to receive webhook HTTP POST requests in the JSON request body can vary based on your backend stack and hosting environment. Below are some methods to achieve this using different technologies: ### Python with Flask Flask is a lightweight WSGI web application framework in Python. ```python theme={null} from flask import Flask, request, jsonify app = Flask(**name**) @app.route('/webhook', methods=['POST']) def webhook(): # Flask automatically parses JSON if the Content-Type is application/json data = request.json print(f"Received data: {data}") return jsonify({"status": "success"}), 200 if **name** == '**main**': app.run(port=5000) ``` ### Node.js with Express Node.js is widely used for server-side development, and Express is one of the most popular frameworks for Node.js. ```typescript theme={null} const express = require("express"); const bodyParser = require("body-parser"); const app = express(); // Middleware to parse JSON payload from incoming POST request app.use(bodyParser.json()); app.post("/webhook", (req, res) => { // req.body contains the parsed JSON payload const data = req.body; console.log(`Received data: ${JSON.stringify(data)}`); res.status(200).json({ status: "success" }); }); app.listen(3000, () => { console.log("Server started on "); }); ``` ### Ruby with Sinatra Sinatra is a DSL (Domain Specific Language) for quickly creating web applications in Ruby with minimal effort. ```ruby theme={null} require 'sinatra' require 'json' post '/webhook' do # Reading and parsing the JSON payload from the request body data = JSON.parse(request.body.read) puts "Received data: #{data}" [200, { 'Content-Type' => 'application/json' }, { status: 'success' }.to_json] end ``` ### Deployment After setting up your webhook endpoint, you'll need to deploy it. You can use cloud services like AWS, Google Cloud, Heroku, or any VPS provider for this purpose. ### Secure your Webhook You may validate incoming requests to ensure they are coming from a trusted source. Visit our [webhooks signature](/api-reference/widget/webhooks/signature) for more information. This is a recommended best practice. ### Test your Webhook After deployment, you can test your webhook endpoint using Postman or curl to send a simulated POST request. # Sell Source: https://dev.moonpay.com/api-reference/widget/webhooks/sell Currently supported Sell events ## Supported events * `sell_transaction_created` * `sell_transaction_updated` * `sell_transaction_failed` Complete list of sell transaction object parameters and descriptions can be found [here](https://moonpay.readme.io/reference/getselltransaction). ## Examples ```json sell_transaction_created theme={null} { "data": { "id": "b8606f16-5518-4425-8076-87067a291ddf", "createdAt": "2023-05-12T17:30:50.390Z", "updatedAt": "2023-05-12T17:30:50.390Z", "baseCurrencyAmount": 500, "feeAmount": 3.99, "extraFeeAmount": 0, "quoteCurrencyAmount": 38.79, "flow": "principal", "status": "waitingForDeposit", "accountId": "7c565d78-10d9-47d8-aa4b-ed28aa1177dc", "customerId": "66eed1c8-e12e-4d77-85f6-008b7b3eeeab", "quoteCurrencyId": "edd81f1f-f735-4692-b410-6def107f17d2", "baseCurrencyId": "c8b1ef20-3703-4a66-9ea1-c13ce0d893bf", "eurRate": 0.9211, "usdRate": 1, "gbpRate": 0.8027, "depositWalletId": null, "bankAccountId": "eb5e7e71-087d-40ec-b508-33c6fab38175", "refundWalletAddress": "", "refundWalletAddressRequestedAt": null, "externalTransactionId": null, "failureReason": null, "depositHash": null, "refundHash": null, "widgetRedirectUrl": null, "confirmations": null, "quoteExpiresAt": "2023-05-12T17:50:50.389Z", "quoteExpiredEmailSentAt": null, "refundApprovalStatus": null, "cancelledById": null, "blockedById": null, "depositMatchedManuallyById": null, "createdById": null, "incomingCustomerCryptoDepositId": null, "payoutMethod": "ach_bank_transfer", "integratedSellDepositInfo": null, "baseCurrency": { "id": "c8b1ef20-3703-4a66-9ea1-c13ce0d893bf", "createdAt": "2019-04-10T15:58:46.394Z", "updatedAt": "2023-03-08T14:38:22.686Z", "type": "crypto", "name": "Stellar", "code": "xlm", "precision": 0, "maxAmount": 2000, "minAmount": 20, "minBuyAmount": 44, "maxBuyAmount": null, "isSellSupported": true, "addressRegex": "^G[A-D]{1}[A-Z2-7]{54}$", "testnetAddressRegex": "^G[A-D]{1}[A-Z2-7]{54}$", "supportsAddressTag": true, "addressTagRegex": "^[0-9A-Za-z]{1,28}$", "supportsTestMode": true, "supportsLiveMode": true, "isSuspended": false, "isSupportedInUS": true, "notAllowedUSStates": ["HI", "NY", "RI", "VI"], "notAllowedCountries": [], "confirmationsRequired": 1, "minSellAmount": 200, "maxSellAmount": 100000, "metadata": { "contractAddress": null, "coinType": "148", "chainId": null, "networkCode": "stellar" } }, "depositWallet": null, "quoteCurrency": { "id": "edd81f1f-f735-4692-b410-6def107f17d2", "createdAt": "2019-04-29T16:55:28.647Z", "updatedAt": "2023-03-06T10:11:49.284Z", "type": "fiat", "name": "US Dollar", "code": "usd", "precision": 2, "maxAmount": 12000, "minAmount": 30, "minBuyAmount": 30, "maxBuyAmount": 12000, "isSellSupported": true }, "country": "USA", "state": "NJ", "externalCustomerId": null }, "type": "sell_transaction_created" } ``` ```json sell_transaction_updated theme={null} { "data": { "id": "b8606f16-5518-4425-8076-87067a291ddf", "createdAt": "2023-05-12T17:30:50.390Z", "updatedAt": "2023-05-12T17:31:04.590Z", "baseCurrencyAmount": 500, "feeAmount": 3.99, "extraFeeAmount": 0, "quoteCurrencyAmount": 38.79, "flow": "principal", "status": "waitingForDeposit", "accountId": "7c565d78-10d9-47d8-aa4b-ed28aa1177dc", "customerId": "66eed1c8-e12e-4d77-85f6-008b7b3eeeab", "quoteCurrencyId": "edd81f1f-f735-4692-b410-6def107f17d2", "baseCurrencyId": "c8b1ef20-3703-4a66-9ea1-c13ce0d893bf", "eurRate": 0.9211, "usdRate": 1, "gbpRate": 0.8027, "depositWalletId": "226f77bf-d061-4d88-9830-8a58c1094ab1", "bankAccountId": "eb5e7e71-087d-40ec-b508-33c6fab38175", "refundWalletAddress": "", "refundWalletAddressRequestedAt": null, "externalTransactionId": null, "failureReason": null, "depositHash": null, "refundHash": null, "widgetRedirectUrl": null, "confirmations": null, "quoteExpiresAt": "2023-05-12T17:50:50.389Z", "quoteExpiredEmailSentAt": null, "refundApprovalStatus": null, "cancelledById": null, "blockedById": null, "depositMatchedManuallyById": null, "createdById": null, "incomingCustomerCryptoDepositId": null, "payoutMethod": "ach_bank_transfer", "integratedSellDepositInfo": null, "baseCurrency": { "id": "c8b1ef20-3703-4a66-9ea1-c13ce0d893bf", "createdAt": "2019-04-10T15:58:46.394Z", "updatedAt": "2023-03-08T14:38:22.686Z", "type": "crypto", "name": "Stellar", "code": "xlm", "precision": 0, "maxAmount": 2000, "minAmount": 20, "minBuyAmount": 44, "maxBuyAmount": null, "isSellSupported": true, "addressRegex": "^G[A-D]{1}[A-Z2-7]{54}$", "testnetAddressRegex": "^G[A-D]{1}[A-Z2-7]{54}$", "supportsAddressTag": true, "addressTagRegex": "^[0-9A-Za-z]{1,28}$", "supportsTestMode": true, "supportsLiveMode": true, "isSuspended": false, "isSupportedInUS": true, "notAllowedUSStates": ["HI", "NY", "RI", "VI"], "notAllowedCountries": [], "confirmationsRequired": 1, "minSellAmount": 200, "maxSellAmount": 100000, "metadata": { "contractAddress": null, "coinType": "148", "chainId": null, "networkCode": "stellar" } }, "depositWallet": { "id": "226f77bf-d061-4d88-9830-8a58c1094ab1", "createdAt": "2023-05-12T17:31:04.527Z", "updatedAt": "2023-05-12T17:31:04.527Z", "walletAddress": "GDPVBFETVZRQRVFUIDN7I55X5HDXS2NVZ5S62DKFUSNKJ5XWUOU2Q3TM", "walletAddressTag": null, "customerId": "66eed1c8-e12e-4d77-85f6-008b7b3eeeab", "currencyId": "c8b1ef20-3703-4a66-9ea1-c13ce0d893bf", "btcLegacyAddress": null, "type": "Fireblocks", "encryptedPrivateKey": null }, "quoteCurrency": { "id": "edd81f1f-f735-4692-b410-6def107f17d2", "createdAt": "2019-04-29T16:55:28.647Z", "updatedAt": "2023-03-06T10:11:49.284Z", "type": "fiat", "name": "US Dollar", "code": "usd", "precision": 2, "maxAmount": 12000, "minAmount": 30, "minBuyAmount": 30, "maxBuyAmount": 12000, "isSellSupported": true }, "country": "USA", "state": "NJ", "externalCustomerId": null }, "type": "sell_transaction_updated" } ``` ```json sell_transaction_failed theme={null} { "data": { "id": "b8606f16-5518-4425-8076-87067a291ddf", "createdAt": "2023-05-12T17:30:50.390Z", "updatedAt": "2023-05-19T17:31:00.042Z", "baseCurrencyAmount": 500, "feeAmount": 3.99, "extraFeeAmount": 0, "quoteCurrencyAmount": 38.79, "flow": "principal", "status": "failed", "accountId": "7c565d78-10d9-47d8-aa4b-ed28aa1177dc", "customerId": "66eed1c8-e12e-4d77-85f6-008b7b3eeeab", "quoteCurrencyId": "edd81f1f-f735-4692-b410-6def107f17d2", "baseCurrencyId": "c8b1ef20-3703-4a66-9ea1-c13ce0d893bf", "eurRate": 0.9211, "usdRate": 1, "gbpRate": 0.8027, "depositWalletId": "226f77bf-d061-4d88-9830-8a58c1094ab1", "bankAccountId": "eb5e7e71-087d-40ec-b508-33c6fab38175", "refundWalletAddress": "", "refundWalletAddressRequestedAt": null, "externalTransactionId": null, "failureReason": "Deposit timeout", "depositHash": null, "refundHash": null, "widgetRedirectUrl": null, "confirmations": null, "quoteExpiresAt": "2023-05-12T17:50:50.389Z", "quoteExpiredEmailSentAt": "2023-05-12T17:51:00.044Z", "refundApprovalStatus": null, "cancelledById": null, "blockedById": null, "depositMatchedManuallyById": null, "createdById": null, "incomingCustomerCryptoDepositId": null, "payoutMethod": "ach_bank_transfer", "integratedSellDepositInfo": null, "baseCurrency": { "id": "c8b1ef20-3703-4a66-9ea1-c13ce0d893bf", "createdAt": "2019-04-10T15:58:46.394Z", "updatedAt": "2023-03-08T14:38:22.686Z", "type": "crypto", "name": "Stellar", "code": "xlm", "precision": 0, "maxAmount": 2000, "minAmount": 20, "minBuyAmount": 44, "maxBuyAmount": null, "isSellSupported": true, "addressRegex": "^G[A-D]{1}[A-Z2-7]{54}$", "testnetAddressRegex": "^G[A-D]{1}[A-Z2-7]{54}$", "supportsAddressTag": true, "addressTagRegex": "^[0-9A-Za-z]{1,28}$", "supportsTestMode": true, "supportsLiveMode": true, "isSuspended": false, "isSupportedInUS": true, "notAllowedUSStates": ["HI", "NY", "RI", "VI"], "notAllowedCountries": [], "confirmationsRequired": 1, "minSellAmount": 200, "maxSellAmount": 100000, "metadata": { "contractAddress": null, "coinType": "148", "chainId": null, "networkCode": "stellar" } }, "depositWallet": { "id": "226f77bf-d061-4d88-9830-8a58c1094ab1", "createdAt": "2023-05-12T17:31:04.527Z", "updatedAt": "2023-05-12T17:31:04.527Z", "walletAddress": "GDPVBFETVZRQRVFUIDN7I55X5HDXS2NVZ5S62DKFUSNKJ5XWUOU2Q3TM", "walletAddressTag": null, "customerId": "66eed1c8-e12e-4d77-85f6-008b7b3eeeab", "currencyId": "c8b1ef20-3703-4a66-9ea1-c13ce0d893bf", "btcLegacyAddress": null, "type": "Fireblocks", "encryptedPrivateKey": null }, "quoteCurrency": { "id": "edd81f1f-f735-4692-b410-6def107f17d2", "createdAt": "2019-04-29T16:55:28.647Z", "updatedAt": "2023-03-06T10:11:49.284Z", "type": "fiat", "name": "US Dollar", "code": "usd", "precision": 2, "maxAmount": 12000, "minAmount": 30, "minBuyAmount": 30, "maxBuyAmount": 12000, "isSellSupported": true }, "country": "USA", "state": "NJ", "externalCustomerId": null }, "type": "sell_transaction_failed" } ``` ## Properties ```json theme={null} { "event": { "method": "POST", "headers": { "moonpay-signature": "t=1663064622,s=cdd18ef9d85c004638f0e9f770231909d24053b503a8f281991e33280a7a9ba9", "moonpay-signature-v2": "t=1663064622,s=44d8318c5ad1720959799062280f5f0030658776c13804d9edd04fd2c4012f14" } } } ``` # Request signing Source: https://dev.moonpay.com/api-reference/widget/webhooks/signature ## Checking a Webhook Signature MoonPay signs the webhook events and requests we send to your endpoints. We do so by including a signature in each event’s `Moonpay-Signature-V2` header. This allows you to validate that the events and requests were sent by MoonPay, not by a third party. Before you can verify `Moonpay-Signature-V2` signatures for webhook events, you need to retrieve your webhook API key from the [Developers page](https://dashboard.moonpay.com/developers/) on the MoonPay dashboard. The `Moonpay-Signature-V2` header contains a timestamp and one signature. The timestamp is prefixed by t=, and the signature is prefixed by s=. ```bash bash Moonpay-Signature-V2: theme={null} t=1492774577,s=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd ``` MoonPay generates signatures using a hash-based message authentication code ([HMAC](https://en.wikipedia.org/wiki/HMAC)) with [SHA-256](https://en.wikipedia.org/wiki/SHA-2). Split the header, using the , character as the separator, to get a list of elements. Then split each element, using the = character as the separator, to get a prefix and value pair. The value for the prefix `t` corresponds to the timestamp, and `s` corresponds to the signature. You achieve this by concatenating: * The timestamp (as a string) * The character . and * For a `POST` request, the actual JSON payload (i.e., the request's body). For a `GET` request, the search string (e.g., ?externalCustomerId=adbb317d-cde9-4ebb-93a3-1b271812de06). Compute a HMAC with the SHA-256 hash function. Use your account's webhook API key as the key, and use the `signed_payload` string as the message in both cases. Compare the signature in the header to the expected signature. # Swap Source: https://dev.moonpay.com/api-reference/widget/webhooks/swap Currently supported Swap events ## Supported events * `swap_asset_delivery_initiated` * `swap_transaction_created` `swap_quote_expired` * `swap_quote_invalid` * `swap_deposit_wallet_created` * `swap_deposit_received` * `swap_transaction_completed` * `swap_transaction_failed` * `swap_refund_asset_delivery_initiated` * `swap_refund_completed` # Virtual Accounts Source: https://dev.moonpay.com/api-reference/widget/webhooks/virtual-accounts Currently supported Virtual Accounts events ## Events ### `virtual_account_status_updated` Triggered when the status of a virtual account changes. ```json Example payload theme={null} { "virtualAccountId": "9bc86a06-8300-41c8-8cef-d2eaa852164f", "externalCustomerId": "external_customer_id_123", "status": "completed", "timestamp": 1678901234567 } ``` | Field | Type | Description | | -------------------- | ------- | ------------------------------------------------------------------------ | | `virtualAccountId` | string | Unique identifier (uuid) of the virtual account | | `externalCustomerId` | string | External identifier of the customer | | `status` | string | Current status of the virtual account (`pending`, `completed`, `failed`) | | `timestamp` | integer | Unix timestamp (milliseconds) when the event was triggered | ### `virtual_account_transaction_status_updated` Triggered when the status of a transaction within a virtual account changes. ```json Example payload theme={null} { "virtualAccountId": "9bc86a06-8300-41c8-8cef-d2eaa852164f", "externalCustomerId": "external_customer_id_123", "transactionId": "7a2cbc6f-ddef-4071-9628-a6559cb4ad89", "status": "Completed", "timestamp": 1678901234567 } ``` | Field | Type | Description | | -------------------- | ------- | -------------------------------------------------------------------- | | `virtualAccountId` | string | Unique identifier (uuid) of the virtual account | | `externalCustomerId` | string | External identifier provided for the customer | | `transactionId` | string | Unique identifier (uuid) of the transaction | | `status` | string | Current status of the transaction (`Pending`, `Completed`, `Failed`) | | `timestamp` | integer | Unix timestamp (milliseconds) when the event was triggered | # Changelog Source: https://dev.moonpay.com/platform/changelog Updates to the MoonPay developer platform **Preview removed** — the Developer Platform is now generally available. The "currently in preview" notice has been removed from all docs pages. **Card payments** — new [Pay with card](/platform/guides/pay-with-card) guide and frame references for [Add Card](/platform/frames/add-card), [Buy](/platform/frames/buy), and [Challenge](/platform/frames/challenge). Covers the full integration: listing and managing stored cards, getting a card quote, executing transactions via the headless buy frame, and handling verification challenges (SCA, 3DS, CVC re-entry, KYC). Also adds the [Delete payment method](/api-reference/platform/endpoints/payment-methods/delete) API endpoint. **Reset frame** — new headless frame at `/platform/v1/reset` that lets you log a customer out by clearing their authentication state on MoonPay's domain. Reports completion via postMessage. See [Reset](/platform/frames/reset). **Unified docs site** — Platform and Widget docs now live under a single Mintlify site with separate top-level tabs. Legacy `/overview/*`, `/guides/*`, `/frames/*`, `/sdk-reference/*`, and `/api-reference/*` URLs redirect to their new `/platform/*` paths. **Manual integration fixes** — corrected the WebView samples to post the payload as a string, base64-decode credentials, and handle JS dialogs. Affects [web](/platform/guides/manual-integration/web), [iOS](/platform/guides/manual-integration/ios), [Android](/platform/guides/manual-integration/android), [React Native](/platform/guides/manual-integration/react-native), and [Flutter](/platform/guides/manual-integration/flutter) guides. **Fee language** updated across guides to clarify partner vs. ecosystem fees. **Revoke session** — `DELETE /platform/v1/sessions` invalidates an active session token. See [Revoke a session](/api-reference/platform/endpoints/sessions/revoke). **Sessions endpoint renamed** — `POST /platform/v1/session` is now `POST /platform/v1/sessions` (plural). The old path continues to work; new integrations should use the plural form. **Apple Pay going-live guide** — added production-readiness details for the Apple Pay frame, including merchant verification and domain registration steps. See [Pay with Apple Pay](/platform/guides/pay-with-apple-pay). **`customerId` in connect/check payload** — the `complete` postMessage event now documents `customer.id`, and the session-create request documents the `customerId` field for returning users (skip the connect flow when you already have one). **Manual integration credentials** — the manual integration guides now use `clientToken` (not `sessionToken`) to initialize frames, matching the early-credential-issuance flow. **Payment-disclosure rails narrowed** — the `paymentDisclosures` capability is now documented as scoped to NY and WA only. Customers in other US states will not receive a `paymentDisclosures` requirement. **HKDF examples** — manual integration code samples consistently pass `undefined` for the `info` parameter of `hkdf()`. **Acceptance criteria page** — new compliance checklist outlining the requirements for going live. See [Going live](/platform/overview/going-live). **Manual integration moved** — the per-platform manual integration pages now live under [Guides → Manual Integration](/platform/guides/manual-integration/overview). **Using agents** — new page covering MCP client setup for Claude Code and Codex, so you can wire your agent to MoonPay's developer docs. See [Using agents](/platform/overview/using-agents). **Manual integration docs** — initial documented integrations for web, iOS, Android, React Native, and Flutter (graduated from hidden drafts). **Early credential issuance** — the credentials-flow guide now reflects that `clientToken` and `accessToken` are issued before authentication completes, so partners can initialize sensitive frames sooner. **Connect-flow low-friction callout** — added guidance to the connect-flow guide about minimizing handoffs back to MoonPay-hosted UI. **Apple Pay frame height** — corrected the documented frame height for the Apple Pay frame. Quote API: `fees.partner` field renamed to `fees.ecosystem`. Apple Pay: documented test-mode and frame sandbox requirements, plus a corrected frame size. Customer capabilities and payment-disclosure requirements expanded. New widget-fallback frame and integration guide. Frames protocol: documented `version: 2` and added the versioning section. Frame URLs migrated from `/v2/*` to `/platform/*` across all docs. OpenAPI now served live from `https://api.moonpay.com/platform/openapi.json` rather than checked into the repo. Removed historical `pk_test` / `pk_live` references in favor of the new credential model. Initial Apple Pay frame size and frame sandbox requirements published. Mintlify upgrade and a content-style-guide pass across guides and frames docs. # Add Card Source: https://dev.moonpay.com/platform/frames/add-card Details on working with the Add Card frame used in the [Pay with card](/platform/guides/pay-with-card) flow. ## URL ``` https://blocks.moonpay.com/platform/v1/add-card ``` ## Requirements ### Size Render the frame in a modal or sheet. Width and height are flexible — size the container to fit your UI. The Add Card frame uses MoonPay's existing card input UI. A redesign is planned to streamline the experience and explore hosted fields for full design customization. ## 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.

The format of this string is up to you. | ## 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 Add Card frame. ### Outbound events frame->parent These events are sent from this frame to the parent window. #### `handshake` The frame requests that you open a message channel. ```json Example theme={null} { "version": 2, "meta": { "channelId": "ch_1" }, "kind": "handshake" } ``` ```ts twoslash TypeScript definition theme={null} type Message = T & { version: 2; meta: { channelId: string }; }; type HandshakeEvent = Message<{ kind: "handshake"; }>; ``` #### `ready` The frame finished loading and the card input UI is fully rendered. ```json Example theme={null} { "version": 2, "meta": { "channelId": "ch_1" }, "kind": "ready" } ``` ```ts twoslash TypeScript definition theme={null} type Message = T & { version: 2; meta: { channelId: string }; }; type ReadyEvent = Message<{ kind: "ready"; }>; ``` #### `complete` The card was added successfully. Use `card.id` to get a quote without re-fetching payment methods. ```json Example theme={null} { "version": 2, "meta": { "channelId": "ch_1" }, "kind": "complete", "payload": { "card": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "type": "card", "cardType": "credit", "brand": "visa", "last4": "4242", "expirationMonth": "12", "expirationYear": "2027", "availability": { "active": true } } } } ``` ```ts twoslash TypeScript definition theme={null} type Message = T & { version: 2; meta: { channelId: string }; }; type CardResponse = { id: string; type: "card"; cardType: "credit" | "debit" | "unknown"; brand: "visa" | "mastercard" | "maestro" | "american_express" | "other"; last4: string; expirationMonth: string; expirationYear: string; availability: { active: boolean }; }; type AddCardCompleteEvent = Message<{ kind: "complete"; payload: { card: CardResponse; }; }>; ``` #### `error` An error occurred during card addition. ```json Example theme={null} { "version": 2, "meta": { "channelId": "ch_1" }, "kind": "error", "payload": { "code": "generic", "message": "Card creation failed." } } ``` ```ts twoslash TypeScript definition theme={null} type Message = T & { version: 2; meta: { channelId: string }; }; type AddCardErrorEvent = Message<{ kind: "error"; payload: { code: "configurationError" | "generic"; /** A developer-facing error message. Not intended to be rendered in UI. */ message: string; }; }>; ``` | Code | Description | | -------------------- | -------------------------------- | | `configurationError` | Missing or invalid `clientToken` | | `generic` | Card creation failed | ### Inbound events parent->frame These events are sent from the parent window to this frame. #### `ack` Acknowledge the [handshake](#handshake). ```json Example theme={null} { "version": 2, "meta": { "channelId": "ch_1" }, "kind": "ack" } ``` ```ts twoslash TypeScript definition theme={null} type Message = T & { version: 2; meta: { channelId: string }; }; type AckEvent = Message<{ kind: "ack"; }>; ``` # Apple Pay Source: https://dev.moonpay.com/platform/frames/apple-pay Details on working with the [Apple Pay](/platform/guides/pay-with-apple-pay) frame. ## URL ```html theme={null} https://blocks.moonpay.com/platform/v1/apple-pay ``` ## Requirements ### Size The frame container **height must be 44px**. Width is flexible; the Apple Pay button inside the frame uses 100% of the container width. ### Permissions The `payment` [permission policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Permissions-Policy#iframes) is required. In [test mode](/platform/overview/test-mode#apple-pay), the frame uses `window.confirm` to simulate the Apple Pay payment. If your iframe uses the [`sandbox`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/iframe#sandbox) attribute, you will need to include `allow-modals`. ```tsx Example theme={null}