MoonPay ๐
Leading fiat-to-crypto on-ramp. Buy crypto with cards, bank transfers, and mobile payments in 160+ countries.
Environment Variables
| Variable |
Description |
Required |
MOONPAY_API_KEY |
Publishable API Key |
Yes |
MOONPAY_SECRET_KEY |
Secret Key for signing |
Yes |
MOONPAY_ENV |
sandbox or production |
No |
Features
- ๐ณ Card Payments - Visa, Mastercard, Apple Pay, Google Pay
- ๐ฆ Bank Transfers - SEPA, ACH, Faster Payments
- ๐ฑ Mobile Payments - PIX, GCash, GrabPay
- ๐ Off-Ramp - Sell crypto to fiat
- ๐จ NFT Checkout - Fiat-to-NFT purchases
API Base URLs
- Sandbox:
https://api.moonpay.com (use test API key)
- Production:
https://api.moonpay.com
Get Supported Currencies
API_KEY="${MOONPAY_API_KEY}"
# Get crypto currencies
curl -s "https://api.moonpay.com/v3/currencies" \
-H "Authorization: Api-Key ${API_KEY}" | jq '.[] | select(.type == "crypto") | {code: .code, name: .name, minBuyAmount: .minBuyAmount}'
# Get fiat currencies
curl -s "https://api.moonpay.com/v3/currencies" \
-H "Authorization: Api-Key ${API_KEY}" | jq '.[] | select(.type == "fiat") | {code: .code, name: .name}'
Get Quote
API_KEY="${MOONPAY_API_KEY}"
BASE_CURRENCY="usd"
QUOTE_CURRENCY="eth"
BASE_AMOUNT="100"
curl -s "https://api.moonpay.com/v3/currencies/${QUOTE_CURRENCY}/buy_quote" \
-G \
--data-urlencode "apiKey=${API_KEY}" \
--data-urlencode "baseCurrencyCode=${BASE_CURRENCY}" \
--data-urlencode "baseCurrencyAmount=${BASE_AMOUNT}" | jq '{
quoteCurrencyAmount: .quoteCurrencyAmount,
feeAmount: .feeAmount,
networkFeeAmount: .networkFeeAmount,
totalAmount: .totalAmount,
extraFeeAmount: .extraFeeAmount
}'
Generate Widget URL
API_KEY="${MOONPAY_API_KEY}"
SECRET_KEY="${MOONPAY_SECRET_KEY}"
# Build widget URL
BASE_URL="https://buy.moonpay.com"
PARAMS="?apiKey=${API_KEY}¤cyCode=eth&walletAddress=<WALLET>&baseCurrencyAmount=100"
# Sign URL (required for production)
SIGNATURE=$(echo -n "${PARAMS}" | openssl dgst -sha256 -hmac "${SECRET_KEY}" -binary | base64 | tr '+/' '-_' | tr -d '=')
WIDGET_URL="${BASE_URL}${PARAMS}&signature=${SIGNATURE}"
echo "Widget URL: $WIDGET_URL"
Create Transaction (Server-Side)
API_KEY="${MOONPAY_API_KEY}"
SECRET_KEY="${MOONPAY_SECRET_KEY}"
curl -s -X POST "https://api.moonpay.com/v3/transactions" \
-H "Authorization: Api-Key ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"baseCurrencyCode": "usd",
"baseCurrencyAmount": 100,
"quoteCurrencyCode": "eth",
"walletAddress": "<WALLET_ADDRESS>",
"returnUrl": "https://your-app.com/success",
"externalCustomerId": "customer-123"
}' | jq '.'
Check Transaction Status
API_KEY="${MOONPAY_API_KEY}"
TX_ID="<TRANSACTION_ID>"
curl -s "https://api.moonpay.com/v3/transactions/${TX_ID}" \
-H "Authorization: Api-Key ${API_KEY}" | jq '{
status: .status,
cryptoTransactionId: .cryptoTransactionId,
quoteCurrencyAmount: .quoteCurrencyAmount,
walletAddress: .walletAddress
}'
Transaction Status Codes
| Status |
Description |
waitingPayment |
Awaiting payment |
pending |
Payment received, processing |
waitingAuthorization |
Awaiting 3DS/bank auth |
completed |
Successfully completed |
failed |
Transaction failed |
Supported Payment Methods
| Method |
Regions |
Speed |
| Credit/Debit Card |
Global |
Instant |
| Apple Pay |
Global |
Instant |
| Google Pay |
Global |
Instant |
| SEPA |
Europe |
1-2 days |
| ACH |
USA |
3-5 days |
| Faster Payments |
UK |
Instant |
| PIX |
Brazil |
Instant |
| iDEAL |
Netherlands |
Instant |
Supported Cryptocurrencies
| Category |
Tokens |
| Major |
BTC, ETH, SOL, MATIC, AVAX |
| Stablecoins |
USDT, USDC, DAI |
| L2 |
ARB, OP, BASE tokens |
| Meme |
DOGE, SHIB |
Webhook Events
# Webhook payload structure
{
"type": "transaction_updated",
"data": {
"id": "tx-123",
"status": "completed",
"cryptoTransactionId": "0x...",
"quoteCurrencyAmount": 0.05,
"walletAddress": "0x..."
}
}
Verify Webhook Signature
verify_webhook() {
local payload="$1"
local signature="$2"
local expected=$(echo -n "$payload" | openssl dgst -sha256 -hmac "$MOONPAY_SECRET_KEY" -binary | base64)
[[ "$signature" == "$expected" ]]
}
Widget Customization
# Widget parameters
PARAMS="?apiKey=${API_KEY}"
PARAMS+="¤cyCode=eth"
PARAMS+="&walletAddress=<WALLET>"
PARAMS+="&baseCurrencyAmount=100"
PARAMS+="&baseCurrencyCode=usd"
PARAMS+="&lockAmount=true" # Lock amount
PARAMS+="&colorCode=%23FF6B00" # Custom color
PARAMS+="&language=en" # Language
PARAMS+="&showWalletAddressForm=false" # Hide wallet input
Safety Rules
- ALWAYS sign widget URLs in production
- NEVER expose secret key client-side
- VERIFY webhook signatures
- CHECK transaction status before fulfilling
Error Codes
| Code |
Description |
invalid_api_key |
Invalid API key |
invalid_signature |
URL signature mismatch |
currency_not_supported |
Currency unavailable |
amount_too_low |
Below minimum |
amount_too_high |
Above maximum |
Links