Overview
A Payment Intent represents a customer's intent to make a payment. It tracks the entire payment lifecycle from creation to completion, handling all the complexity of cryptocurrency payments behind a simple API.
What is a Payment Intent?
A Payment Intent is a server-side object that:
- 💰 Stores payment amount and currency (USD)
- 🔄 Tracks payment status through its lifecycle
- 👤 Links to customer information
- 🏷️ Holds metadata for order tracking
- 💳 Accepts USDC and USDT as payment methods
💡 Key Concept: Think of a Payment Intent as a "payment request" that persists on the server. Once created, you guide your customer through the payment process, and the Payment Intent automatically updates as the payment progresses.
How It Works
Create Intent → Customer Pays → Payment Confirms → Funds Settled
↓ ↓ ↓ ↓
pending → requires_action → processing → succeeded
Key Benefits
| Benefit | Description |
|---|---|
| Unified Interface | Consistent API across all payment scenarios |
| Status Tracking | Real-time payment status updates |
| Automatic Retries | Built-in handling for failed payments |
| Webhook Support | Notifications for every status change |
| Currency Flexibility | Accept USDC/USDT while pricing in USD |
| Metadata Support | Attach custom data for order tracking |
Creation Methods
MartianPay offers three ways to create Payment Intents:
| Method | Best For | Integration Effort |
|---|---|---|
| Direct API | Custom checkout flows | High (full control) |
| Payment Links | Quick setup, no coding | Low (hosted page) |
| Client SDK | Web/mobile apps | Medium (pre-built UI) |
💡 Getting Started: New to payments? Start with Payment Links for the quickest setup. Need custom integration? Use Direct API below.
API Reference
1. Create Payment Intent
Creates a new payment intent for processing a cryptocurrency transaction.
📌 Note: Currently only USD is supported as the payment intent currency. Customers can pay using USDC or USDT stablecoins.
Method 1: Direct API Call ⭐ Most Flexible
Best For: Custom checkout experiences, full control over payment flow
For detailed API reference, see: Create Payment Intent API
Request Parameters:
amount(required): Amount to be charged in the specified currencycurrency(required): ISO 4217 currency code (currently only "USD" is supported)customer(optional): Customer ID this payment intent belongs todescription(optional): Description of the payment intentmetadata(optional): Key-value pairs for additional informationmerchant_order_id(required): Your unique order identifierreceipt_email(optional): Email address to send the receipt toreturn_url(optional): URL to redirect the customer after paymentpayment_method_id(optional): ID of a saved payment method (Stripe only)complete_on_first_payment(optional): Complete payment immediately when first transaction arrives, regardless of amount
Request:
curl --location --request POST 'https://api.martianpay.com/v1/payment_intents' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--data-raw '{
"amount": "10.00",
"currency": "USD",
"customer": "cus_7p51tXM7GBi7sz5J",
"description": "Payment for Order #123",
"metadata": {
"order_id": "order_123",
"customer_name": "John Doe"
},
"merchant_order_id": "order_1234"
}'
Response:
{
"error_code": "success",
"msg": "success",
"data": {
"id": "pi_vfk7mLTHPs7Cf0UbU38tGiKq",
"object": "payment_intent",
"amount": {
"asset_id": "USD",
"amount": "10"
},
"payment_details": {
"amount_captured": {
"asset_id": "USD",
"amount": "0"
},
"amount_refunded": {
"asset_id": "USD",
"amount": "0"
},
"tx_fee": {
"asset_id": "USD",
"amount": "0"
},
"tax_fee": {
"asset_id": "USD",
"amount": "0"
},
"frozen_amount": {
"asset_id": "USD",
"amount": "0"
},
"net_amount": {
"asset_id": "USD",
"amount": "0"
},
"gas_fee": {},
"network_fee": {
"asset_id": "USD",
"amount": "0"
}
},
"canceled_at": 0,
"cancellation_reason": "",
"client_secret": "pi_vfk7mLTHPs7Cf0UbU38tGiKq_secret_QN30gkdjG1BQuFIqKgObDhXHl",
"created": 1748575946,
"updated": 1748575946,
"currency": "USD",
"customer": {
"id": "cus_7p51tXM7GBi7sz5J",
"object": "customer",
"total_expense": 490,
"total_payment": 580,
"total_refund": 90,
"currency": "USD",
"created": 1737964162,
"name": "John Doe",
"email": "john@example.com",
"description": "VIP customer",
"metadata": {
"source": "web",
"user_id": "123"
},
"phone": "+1234567890"
},
"description": "Payment for Order #123",
"livemode": false,
"metadata": {
"customer_name": "John Doe",
"order_id": "order_123"
},
"payment_link_details": null,
"merchant_order_id": "order_1234",
"payment_method_type": "",
"charges": [],
"receipt_email": "",
"return_url": "",
"status": "RequiresPaymentMethod",
"payment_intent_status": "Created",
"complete_on_first_payment": false,
"permanent_deposit": false,
"permanent_deposit_asset_id": "",
"expired_at": 0
}
}
Method 2: Direct Payment Link Payment
For simple payment scenarios, you can use payment links created for products. Customers select products/variants and complete payment through a hosted checkout page. A payment intent is automatically created when the customer initiates checkout.
For detailed information on creating payment links, see: How to Use Payment Links
Workflow:
- Create a product with variants (if needed)
- Create a payment link for the product
- Share the payment link URL with customers
- Customer selects options and completes payment
- Payment intent is automatically created upon checkout initiation
- Track payment status via webhooks or API
Payment Link URL Format:
https://buy.martianpay.com/{payment_link_id}
Benefits:
- No backend integration required for payment flow
- Hosted checkout UI provided by MartianPay
- Automatic payment intent creation
- Support for product variants and add-ons
- Mobile-optimized payment experience
Method 3: Payment Link with Ephemeral Token (Third-Party Auth Integration)
For seamless integration with external authentication systems (Instagram, WhatsApp, your own platform), you can use ephemeral tokens to authenticate customers automatically without requiring them to log in again.
For detailed implementation guide, see: Payment Link with Ephemeral Token
Step 1: Generate Ephemeral Token
curl --location --request POST 'https://api.martianpay.com/v1/customers/ephemeral_tokens' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--data '{
"allow_create": true,
"channel_metadata": {
"platform_user_id": "user_12345",
"source": "instagram_dm"
},
"idp_key": "email",
"idp_subject": "customer@example.com",
"issued_by": "instagram_commerce_bot",
"provider": "instagram",
"order_id": "order_123",
"return_url": "https://example.com/payment/success"
}'
Response:
{
"expires_at": 1735689600,
"token": "eph_abc123xyz789"
}
Step 2: Share Payment Link with Token
Append the ephemeral token to your payment link URL:
https://buy.martianpay.com/{payment_link_id}?ephemeral_token=eph_abc123xyz789
Step 3: Customer Completes Payment
When the customer clicks the link:
- They're automatically authenticated (no login required)
- They see the product and select options
- They complete payment through the hosted checkout
- Payment intent is automatically created upon checkout initiation
Step 4: Track Payment Status
After successful payment, you have two ways to track the created payment intent:
-
Via Webhook (Recommended):
- Listen for
payment_intent.succeededwebhook event - Extract
merchant_order_idfrom the payment intent payload - Use this
merchant_order_idto map the payment to your order system
- Listen for
-
Via Get Payment Intent API:
- Query payment intent using the
merchant_order_id - Example:
curl --location --request GET 'https://api.martianpay.com/v1/payment_intents?merchant_order_id={order_id}' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'- This returns the payment intent associated with the specified order ID
- Useful for reconciliation and status checking after payment
- Query payment intent using the
Benefits:
- No additional login step - seamless customer experience
- Works with any external identity provider (email, phone, or UUID-based)
- Supports anonymous tokens for order-only tracking (without customer identity)
- Secure with short-lived tokens (5-15 minutes)
- Auto-creates new customers if they don't exist
- Tracks platform-specific data through
channel_metadata
Use Cases:
- Instagram Commerce: Send payment links in DMs with auto-authentication
- WhatsApp Business: Share payment links without customer login
- Telegram Bots: Offer one-click checkout
- Custom Platforms: Integrate MartianPay into your existing user system
Understanding the Response
Success Check: error_code: "success" ✅ Payment intent created
Key Fields:
id: Payment intent identifier (use for updates/queries)client_secret: Use in frontend for checkout (MartianPay JS SDK)status: Payment status (Created, Processing, Completed, etc.)payment_url: Hosted checkout page URL
Next Steps:
- Use
client_secretwith MartianPay JS SDK for embedded checkout - OR share
payment_urlfor hosted checkout - Poll status or use webhooks to monitor payment completion
2. Update Payment Intent
Modifies an existing payment intent, allowing changes to its properties. You can update the payment method and specify crypto or fiat payment options.
Integration Methods:
- Using MartianPay JS SDK (
@martianpay/js): If you're integrating with our JavaScript SDK, you do not need to call this API directly. The SDK handles payment method updates automatically. See MartianPay JS Usage Guide for details. - Custom Web Implementation: If you're building your own custom payment interface without the SDK, you need to call this API to update payment methods. See Custom Payment Interface Guide for implementation details.
For detailed API reference, see:
- Backend API: Update Payment Intent API
- Frontend API: Update Payment Intent Link API
Payment Method Options:
- Crypto: Specify the
asset_idfor cryptocurrency payments (e.g., "USDC-Ethereum-TEST"). Asset IDs can be obtained from the List Assets API. - Fiat: Specify the
currencyfor fiat payments (e.g., "USD"). Optionally includepayment_method_idfor saved payment methods (Stripe) andsave_payment_methodto save the card for future use.
Request Example (Crypto):
Backend API (using secret key):
curl --location --request POST 'https://api.martianpay.com/v1/payment_intents/:id' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--data-raw '{
"payment_method_type": "crypto",
"payment_method_options": {
"crypto": {
"asset_id": "USDC-Ethereum-TEST"
}
}
}'
Frontend API (using public key, for custom payment interface):
curl --location --request POST 'https://api.martianpay.com/v1/payment_intents/link/:id/update' \
--header 'Content-Type: application/json' \
--data-raw '{
"payment_method_type": "crypto",
"payment_method_options": {
"crypto": {
"asset_id": "USDC-Ethereum-TEST"
}
},
"key": "public_key",
"client_secret": "client_secret"
}'
Request Example (Fiat with new card):
Backend API (using secret key):
curl --location --request POST 'https://api.martianpay.com/v1/payment_intents/:id' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--data-raw '{
"payment_method_type": "cards",
"payment_method_options": {
"fiat": {
"currency": "USD",
"save_payment_method": true
}
}
}'
Frontend API (using public key, for custom payment interface):
curl --location --request POST 'https://api.martianpay.com/v1/payment_intents/link/:id/update' \
--header 'Content-Type: application/json' \
--data-raw '{
"payment_method_type": "cards",
"payment_method_options": {
"fiat": {
"currency": "USD",
"save_payment_method": true
}
},
"key": "public_key",
"client_secret": "client_secret"
}'
Request Example (Fiat with saved payment method):
Before using a saved payment method, you need to fetch the customer's saved payment methods using the List Payment Methods API and let the user select one.
Backend API (using secret key):
curl --location --request POST 'https://api.martianpay.com/v1/payment_intents/:id' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--data-raw '{
"payment_method_type": "cards",
"payment_method_options": {
"fiat": {
"currency": "USD",
"payment_method_id": "pm_1234567890"
}
}
}'
Frontend API (using public key, for custom payment interface):
curl --location --request POST 'https://api.martianpay.com/v1/payment_intents/link/:id/update' \
--header 'Content-Type: application/json' \
--data-raw '{
"payment_method_type": "cards",
"payment_method_options": {
"fiat": {
"currency": "USD",
"payment_method_id": "pm_1234567890"
}
},
"key": "public_key",
"client_secret": "client_secret"
}'
Note: The payment_method_id should be obtained from the customer's saved payment methods list. See the Payment Methods API documentation for details on how to retrieve saved payment methods.
Response:
{
"error_code": "success",
"msg": "success",
"data": {
"id": "pi_vfk7mLTHPs7Cf0UbU38tGiKq",
"object": "payment_intent",
"amount": {
"asset_id": "USD",
"amount": "10"
},
"payment_details": {
"amount_captured": {
"asset_id": "USD",
"amount": "0"
},
"amount_refunded": {
"asset_id": "USD",
"amount": "0"
},
"tx_fee": {
"asset_id": "USD",
"amount": "0"
},
"tax_fee": {
"asset_id": "USD",
"amount": "0"
},
"frozen_amount": {
"asset_id": "USD",
"amount": "0"
},
"net_amount": {
"asset_id": "USD",
"amount": "0"
},
"gas_fee": {},
"network_fee": {
"asset_id": "USD",
"amount": "0"
}
},
"canceled_at": 0,
"cancellation_reason": "",
"client_secret": "pi_vfk7mLTHPs7Cf0UbU38tGiKq_secret_QN30gkdjG1BQuFIqKgObDhXHl",
"created": 1748575946,
"updated": 1748575946,
"currency": "USD",
"customer": {
"id": "cus_7p51tXM7GBi7sz5J",
"object": "customer",
"total_expense": 490,
"total_payment": 580,
"total_refund": 90,
"currency": "USD",
"created": 1737964162,
"name": "John Doe",
"email": "john@example.com",
"description": "VIP customer",
"metadata": {
"source": "web",
"user_id": "123"
},
"phone": "+1234567890"
},
"description": "Payment for Order #123",
"livemode": false,
"metadata": {
"customer_name": "John Doe",
"order_id": "order_123"
},
"payment_link_details": null,
"merchant_order_id": "order_1234",
"payment_method_type": "crypto",
"charges": [
{
"id": "ch_c9tR5aQRdtmkKwCQDji9Z6ST",
"object": "charge",
"amount": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "10"
},
"payment_details": {
"amount_captured": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0"
},
"amount_refunded": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0"
},
"tx_fee": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0"
},
"tax_fee": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0"
},
"frozen_amount": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0"
},
"net_amount": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0"
},
"gas_fee": {},
"network_fee": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0"
}
},
"exchange_rate": "1.0",
"calculated_statement_descriptor": "",
"captured": false,
"created": 0,
"customer": "",
"description": "",
"disputed": false,
"failure_code": "",
"failure_message": "",
"fraud_details": null,
"livemode": false,
"metadata": null,
"paid": false,
"payment_intent": "pi_vfk7mLTHPs7Cf0UbU38tGiKq",
"payment_method_type": "crypto",
"payment_method_options": {
"crypto": {
"amount": "10000000",
"token": "USDC",
"asset_id": "USDC-Ethereum-TEST",
"network": "Ethereum Sepolia",
"decimals": 6,
"exchange_rate": "1.0",
"deposit_address": "0x736e84F695504f9A65FD1B76c3E3cf01Eb43802f",
"expired_at": 1748577793
}
},
"transactions": [],
"receipt_email": "",
"return_url": "",
"receipt_url": "",
"refunded": false,
"refunds": [],
"review": null,
"payer_max_payload": null,
"stripe_payload": null,
"payment_provider": ""
}
],
"receipt_email": "",
"return_url": "",
"status": "Processing",
"payment_intent_status": "Waiting",
"complete_on_first_payment": false,
"permanent_deposit": false,
"permanent_deposit_asset_id": "",
"expired_at": 0
}
}
Understanding the Response
Success Check: error_code: "success" ✅ Payment intent updated
What You Can Update:
- Payment method (crypto/fiat selection)
- Payment method details
Common Updates: Select crypto (USDC, USDT) or fiat (card) payment method.
Next Steps: Customer completes payment via selected method, monitor status via webhooks.
3. Customer Pay the Payment Intent
To complete the payment, customers can choose between crypto and fiat payment methods:
Crypto Payment
For cryptocurrency payments, the customer should follow these steps:
- Open their preferred cryptocurrency wallet that supports the selected asset (e.g., USDC on Ethereum Sepolia network)
- Initiate a transaction to send the required amount to the provided deposit address
Example:
0x736e84F695504f9A65FD1B76c3E3cf01Eb43802f - Ensure the transaction is sent before the expiration time (check
expired_atfield) - Wait for the transaction to be confirmed on the blockchain network
Fiat Payment (Card Payment)
For fiat card payments, there are two integration options:
Option 1: Using MartianPay JS SDK (Recommended)
- The SDK automatically handles the payment UI and flow
- Customers enter card details in a secure, pre-built interface
- Supports saving cards for future payments
- See MartianPay JS Usage Guide for implementation
Option 2: Custom Integration
- Build your own payment interface using Stripe.js
- Load Stripe Elements and handle card input
- See Custom Payment Interface Guide for detailed implementation
Card payment features:
- Support for saved payment methods (returning customers)
- PCI-compliant card handling through Stripe
- Real-time payment confirmation
- Optional card saving for future use
Payment Status Tracking
Once the payment is successfully processed, the payment intent status will be updated accordingly.
MartianPay sends webhook notifications for all payment intent status changes, including:
payment_intent.created- Payment intent createdpayment_intent.processing- Payment processing startedpayment_intent.succeeded- Payment completed successfullypayment_intent.payment_failed- Payment failedpayment_intent.partially_paid- Partial payment received (crypto only)payment_intent.canceled- Payment canceled
These webhook events allow you to track the payment lifecycle in real-time and automate order fulfillment. For detailed webhook setup, event schemas, and best practices, see Section 7: Webhook Events.
4. Get Payment Intent
Retrieves details of a specific payment intent.
For detailed API reference, see: Get Payment Intent API
Request:
curl --location --request GET 'https://api.martianpay.com/v1/payment_intents/:id' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'
Response:
{
"error_code": "success",
"msg": "success",
"data": {
"id": "pi_vfk7mLTHPs7Cf0UbU38tGiKq",
"object": "payment_intent",
"amount": {
"asset_id": "USD",
"amount": "10"
},
"payment_details": {
"amount_captured": {
"asset_id": "USD",
"amount": "10"
},
"amount_refunded": {
"asset_id": "USD",
"amount": "0"
},
"tx_fee": {
"asset_id": "USD",
"amount": "0.1"
},
"tax_fee": {
"asset_id": "USD",
"amount": "0"
},
"frozen_amount": {
"asset_id": "USD",
"amount": "0"
},
"net_amount": {
"asset_id": "USD",
"amount": "9.9"
},
"gas_fee": {},
"network_fee": {
"asset_id": "USD",
"amount": "0"
}
},
"canceled_at": 0,
"cancellation_reason": "",
"client_secret": "pi_vfk7mLTHPs7Cf0UbU38tGiKq_secret_QN30gkdjG1BQuFIqKgObDhXHl",
"created": 1748575946,
"updated": 1748576345,
"currency": "USD",
"customer": {
"id": "cus_7p51tXM7GBi7sz5J",
"object": "customer",
"total_expense": 490,
"total_payment": 580,
"total_refund": 90,
"currency": "USD",
"created": 1737964162,
"name": "John Doe",
"email": "john@example.com",
"description": "VIP customer",
"metadata": {
"source": "web",
"user_id": "123"
},
"phone": "+1234567890"
},
"description": "Payment for Order #123",
"livemode": false,
"metadata": {
"customer_name": "John Doe",
"order_id": "order_123"
},
"payment_link_details": null,
"merchant_order_id": "order_1234",
"payment_method_type": "crypto",
"charges": [
{
"id": "ch_c9tR5aQRdtmkKwCQDji9Z6ST",
"object": "charge",
"amount": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "10"
},
"payment_details": {
"amount_captured": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "10"
},
"amount_refunded": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0"
},
"tx_fee": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0.1"
},
"tax_fee": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0"
},
"frozen_amount": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0"
},
"net_amount": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "9.9"
},
"gas_fee": {},
"network_fee": {
"asset_id": "USDC-Ethereum-TEST",
"amount": "0"
}
},
"exchange_rate": "1.0",
"calculated_statement_descriptor": "",
"captured": false,
"created": 0,
"customer": "",
"description": "",
"disputed": false,
"failure_code": "",
"failure_message": "",
"fraud_details": null,
"livemode": false,
"metadata": null,
"paid": false,
"payment_intent": "pi_vfk7mLTHPs7Cf0UbU38tGiKq",
"payment_method_type": "crypto",
"payment_method_options": {
"crypto": {
"amount": "10000000",
"token": "USDC",
"asset_id": "USDC-Ethereum-TEST",
"network": "Ethereum Sepolia",
"decimals": 6,
"exchange_rate": "1.0",
"deposit_address": "0x736e84F695504f9A65FD1B76c3E3cf01Eb43802f",
"expired_at": 1748577793
}
},
"transactions": [
{
"tx_id": "4efe48fd-3b81-422a-8913-163d04d8c835",
"source_address": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9",
"destination_address": "0x736e84F695504f9A65FD1B76c3E3cf01Eb43802f",
"tx_hash": "0x85b9b9b2fcd8b149a79efa6eee0d94f0d81c6d3172d1335fed897a374e81210c",
"amount": "10000000",
"decimals": 6,
"asset_id": "USDC-Ethereum-TEST",
"token": "USDC",
"network": "Ethereum Sepolia",
"type": "deposit",
"created_at": 1748576344,
"status": "confirmed",
"aml_status": "approved",
"aml_info": "",
"charge_id": "ch_c9tR5aQRdtmkKwCQDji9Z6ST",
"refund_id": "",
"fee_info": "network_fee:\"0.00009323898359702\"",
"fee_currency": "ETH_TEST5"
}
],
"receipt_email": "",
"return_url": "",
"receipt_url": "",
"refunded": false,
"refunds": [],
"review": null,
"payer_max_payload": null,
"stripe_payload": null,
"payment_provider": ""
}
],
"receipt_email": "",
"return_url": "",
"status": "Success",
"payment_intent_status": "Confirmed",
"complete_on_first_payment": false,
"permanent_deposit": false,
"permanent_deposit_asset_id": "",
"expired_at": 0,
"unfreeze_withdraws": [],
"invoice": null,
"invoice_details": null,
"subscription": null,
"subscription_details": null
}
}
After successfully querying the payment intent and receiving a "Success" status, it indicates that the payment has been received. You can then examine the "transactions" array within the response to view detailed information about each transaction associated with the payment intent. This includes important details such as transaction IDs, blockchain addresses, transaction hashes, amounts, and confirmation statuses.
Additional Payment Intent Fields:
unfreeze_withdraws: Array of unfreeze withdrawal records for previously frozen funds. When a payment is initially rejected by AML (anti-money laundering) checks and later approved, this field contains the withdrawal records for releasing those frozen funds.invoice: Invoice ID if this payment intent is associated with an invoice (used for subscription billing). This field is populated when the payment intent is created for a subscription invoice.invoice_details: Expanded invoice details when using theexpand=invoicequery parameter. Contains full invoice information including line items, subscription details, and billing information.subscription: Subscription ID resolved through the associated invoice. Only present when the payment intent is part of a subscription payment flow.subscription_details: Expanded subscription details when using theexpand=invoice.subscriptionquery parameter. Includes subscription plan information, billing cycle, status, and related metadata.
Additional Charge Fields:
payer_max_payload: Contains PayerMax payment provider specific data when using PayerMax as the payment method. Includes fields likecashier_url(payment page URL),status,session_key, andclient_keyfor handling PayerMax payments.stripe_payload: Contains Stripe payment provider specific data when using Stripe as the payment method. Includes fields likeclient_secret(for Stripe Elements),public_key,status, and optionalcustomer_idfor saved payment methods.payment_provider: Identifies the payment provider handling this charge. Can be values like "stripe", "payer_max", or empty for crypto payments. This helps determine which payload fields to use for payment processing.
Understanding the Response
Success Check: error_code: "success" ✅
Key Status Fields:
status: Overall payment status (Processing, Success, Failed, Canceled)payment_intent_status: Detailed status (Waiting, Confirmed, etc.)
Payment Confirmation:
- Status "Success" = Payment received
- Check
transactionsarray for blockchain details - Use
receipt_urlfor customer receipt
Next Steps: Fulfill order if status is Success, retry/refund if Failed, monitor if Processing.
5. List Payment Intents
Fetches a list of payment intents, with options for filtering and pagination. The customer parameter is optional and can be used to filter payment intents by a specific customer. You can also filter by merchant order ID, permanent deposit status and asset ID.
For detailed API reference, see: List Payment Intents API
Request:
curl --location --request GET 'https://api.martianpay.com/v1/payment_intents?page=0&page_size=10&customer=cus_7p51tXM7GBi7sz5J' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}'
Query Parameters:
page(required): Page number, starting from 0page_size(required): Number of items per pagecustomer(optional): Filter by customer IDcustomer_email(optional): Filter by customer emailmerchant_order_id(optional): Filter by merchant order IDpermanent_deposit(optional): Filter by permanent deposit status (true/false)permanent_deposit_asset_id(optional): Filter by permanent deposit asset ID
Response:
{
"error_code": "success",
"msg": "success",
"data": {
"payment_intents": [
{
"id": "pi_vfk7mLTHPs7Cf0UbU38tGiKq",
"object": "payment_intent",
"amount": {
"asset_id": "USD",
"amount": "10"
},
"payment_details": {
"amount_captured": {"asset_id": "USD", "amount": "10"},
"amount_refunded": {"asset_id": "USD", "amount": "0"},
"tx_fee": {"asset_id": "USD", "amount": "0.1"},
...
},
"canceled_at": 0,
"cancellation_reason": "",
"client_secret": "",
"created": 1748575946,
"updated": 1748576345,
"currency": "USD",
"customer": {
"id": "cus_7p51tXM7GBi7sz5J",
"object": "customer",
"total_expense": 490,
"total_payment": 580,
"total_refund": 90,
...
},
"description": "Payment for Order #123",
"livemode": false,
"metadata": null,
"payment_link_details": null,
"merchant_order_id": "order_1234",
"payment_method_type": "crypto",
"charges": [
{
"id": "ch_c9tR5aQRdtmkKwCQDji9Z6ST",
"object": "charge",
"amount": {"asset_id": "USDC-Ethereum-TEST", "amount": "10"},
"payment_details": {...},
"exchange_rate": "1.0",
...
"payment_method_options": {
"crypto": {
"amount": "10000000",
"token": "USDC",
"asset_id": "USDC-Ethereum-TEST",
"network": "Ethereum Sepolia",
"decimals": 6,
"exchange_rate": "1.0",
"deposit_address": "0x736e84F695504f9A65FD1B76c3E3cf01Eb43802f",
"expired_at": 1748577793
}
},
"transactions": [
{
"tx_id": "4efe48fd-3b81-422a-8913-163d04d8c835",
"source_address": "0x36279Ac046498bF0cb742622cCe22F3cE3c2AfD9",
"destination_address": "0x736e84F695504f9A65FD1B76c3E3cf01Eb43802f",
"tx_hash": "0x85b9b9b2fcd8b149a79efa6eee0d94f0d81c6d3172d1335fed897a374e81210c",
"amount": "10000000",
"decimals": 6,
"asset_id": "USDC-Ethereum-TEST",
"token": "USDC",
"network": "Ethereum Sepolia",
"type": "deposit",
"created_at": 1748576344,
"status": "confirmed",
...
}
],
...
}
],
"receipt_email": "",
"return_url": "",
"status": "Success",
"payment_intent_status": "Confirmed",
"complete_on_first_payment": false,
"permanent_deposit": false,
"permanent_deposit_asset_id": "",
"expired_at": 0,
"unfreeze_withdraws": [],
"invoice": null,
"invoice_details": null,
"subscription": null,
"subscription_details": null
},
...
],
"total": 8,
"page": 0,
"page_size": 10
}
}
Understanding the Response
Success Check: error_code: "success" ✅
Key Fields:
payment_intents: Array of payment intent objectstotal: Total count matching filterpage,page_size: Pagination info
Filtering: Use customer, merchant_order_id, permanent_deposit parameters to narrow results.
Next Steps: Loop through payment intents, check status, fulfill completed orders.
6. Cancel Payment Intent
Only payment intents with a status of "RequiresPaymentMethod" or those that have exceeded their payment timeout can be canceled. Attempts to cancel payment intents in any other status will result in a failure response.
For detailed API reference, see: Cancel Payment Intent API
Request:
curl --location --request POST 'https://api.martianpay.com/v1/payment_intents/:id/cancel' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {BASE64_ENCODE(api_key + ":")}' \
--data-raw '{
"reason": "Customer requested cancellation"
}'
Response:
{
"error_code": "success",
"msg": "success",
"data": {
"id": "pi_dqj7qywdZQ5Rk5R5nEJIJ7VF",
"object": "payment_intent",
"amount": {
"asset_id": "USD",
"amount": "10"
},
"payment_details": {
"amount_captured": {
"asset_id": "USD",
"amount": "0"
},
"amount_refunded": {
"asset_id": "USD",
"amount": "0"
},
"tx_fee": {
"asset_id": "USD",
"amount": "0"
},
"tax_fee": {
"asset_id": "USD",
"amount": "0"
},
"frozen_amount": {
"asset_id": "USD",
"amount": "0"
},
"net_amount": {
"asset_id": "USD",
"amount": "0"
},
"gas_fee": {},
"network_fee": {
"asset_id": "USD",
"amount": "0"
}
},
"canceled_at": 1748577604,
"cancellation_reason": "",
"client_secret": "pi_dqj7qywdZQ5Rk5R5nEJIJ7VF_secret_78V6DrBGY15GsPE4EljjEMZJB",
"created": 1748577592,
"updated": 1748577592,
"currency": "USD",
"customer": {
"id": "cus_7p51tXM7GBi7sz5J",
"object": "customer",
"total_expense": 490,
"total_payment": 580,
"total_refund": 90,
"currency": "USD",
"created": 1737964162,
"name": "John Doe",
"email": "john@example.com",
"description": "VIP customer",
"metadata": {
"source": "web",
"user_id": "123"
},
"phone": "+1234567890"
},
"description": "Payment for Order #123",
"livemode": false,
"metadata": {
"customer_name": "John Doe",
"order_id": "order_123"
},
"payment_link_details": null,
"merchant_order_id": "order_1234",
"payment_method_type": "",
"charges": [],
"receipt_email": "",
"return_url": "",
"status": "Canceled",
"payment_intent_status": "Cancelled",
"complete_on_first_payment": false,
"permanent_deposit": false,
"permanent_deposit_asset_id": "",
"expired_at": 0
}
}
Error Response:
{
"code": 190,
"error_code": "status unexpected",
"msg": "status unexpected"
}
Understanding the Response
Success Check: error_code: "success" ✅ | status: "Canceled"
Cancellation Requirements:
- ✅ Status must be "RequiresPaymentMethod"
- ✅ OR payment timeout exceeded
- ❌ Cannot cancel completed/processing payments
Error 190: Status unexpected = Cannot cancel this payment intent
Next Steps: Verify cancellation, issue refund separately if payment already completed.
7. Webhook Events for Payment Intents
MartianPay sends webhook notifications for payment intent events, enabling you to track the complete payment lifecycle in real-time.
7.1 Payment Intent Events
| Event Type | Description | Triggered When |
|---|---|---|
payment_intent.created | Payment intent created | A new payment intent is initially created |
payment_intent.processing | Payment processing started | Payment attempt begins (customer submitted payment) |
payment_intent.succeeded | Payment completed successfully | Full payment amount received and confirmed |
payment_intent.payment_failed | Payment attempt failed | Payment failed due to insufficient funds, network issues, or card declined |
payment_intent.partially_paid | Partial payment received | Only portion of amount received (crypto payments only) |
payment_intent.canceled | Payment intent canceled | Payment intent canceled manually or expired |
7.2 Webhook Payload Example
Here's an example of a payment intent webhook event payload:
{
"id": "evt_056qw9fr9PndljykFUqSIf6t",
"object": "event",
"api_version": "2025-01-22",
"created": 1748576345,
"data": {
"object": {
"id": "pi_vfk7mLTHPs7Cf0UbU38tGiKq",
"object": "payment_intent",
"amount": {
"asset_id": "USD",
"amount": "10"
},
"currency": "USD",
"status": "Success",
"payment_intent_status": "Confirmed",
"created": 1748575946,
"updated": 1748576345,
"customer": {
"id": "cus_7p51tXM7GBi7sz5J",
"name": "John Doe",
"email": "john@example.com"
},
"merchant_order_id": "order_1234",
"payment_method_type": "crypto",
"description": "Payment for Order #123",
"metadata": {
"order_id": "order_123",
"customer_name": "John Doe"
}
},
"previous_attributes": {
"status": "Processing",
"payment_intent_status": "Waiting",
"updated": 1748576000
}
},
"livemode": false,
"pending_webhooks": 0,
"type": "payment_intent.succeeded"
}
7.3 Webhook Event Flow
Typical Payment Intent Event Sequence:
For Crypto Payments:
payment_intent.created- Payment intent createdpayment_intent.processing- Customer sends crypto paymentpayment_intent.succeeded- Payment confirmed on blockchain- OR
payment_intent.partially_paid- Partial amount received - OR
payment_intent.payment_failed- Payment failed or expired
- OR
For Card Payments:
payment_intent.created- Payment intent createdpayment_intent.processing- Card payment processingpayment_intent.succeeded- Card charged successfully- OR
payment_intent.payment_failed- Card declined or processing error
- OR
Status Transitions:
created → processing → succeeded (SUCCESS)
↘ payment_failed (FAILURE)
↘ partially_paid (CRYPTO ONLY, PARTIAL)
created → canceled (MANUAL CANCELLATION or EXPIRATION)
7.4 Best Practices
-
Monitor payment_intent.succeeded events - This is your confirmation that payment is complete:
- Fulfill orders immediately
- Update order status to "paid"
- Send confirmation emails to customers
- Update inventory if applicable
-
Alert on payment_intent.payment_failed events - Take action when payments fail:
- Notify customers of failed payment
- Provide alternative payment options
- Log failure reasons for analysis
- Send retry payment links if appropriate
-
Handle partial payments (crypto) - Monitor
payment_intent.partially_paidevents:- Notify customers they sent insufficient amount
- Provide instructions to complete payment
- Consider refunding partial amounts or accepting as partial fulfillment
-
Track processing status - Use
payment_intent.processingto:- Show real-time status to customers ("Processing your payment...")
- Track time from submission to completion
- Identify slow processing for investigation
-
Handle idempotency - Store the event ID (
evt_*) to prevent duplicate order fulfillment -
Reconcile with merchant_order_id - Use the
merchant_order_idfield to:- Match webhook events to your internal orders
- Update order status in your system
- Prevent duplicate processing
-
Monitor canceled payments - Track
payment_intent.canceledevents:- Clean up abandoned checkouts
- Release reserved inventory
- Analyze cancellation reasons
-
Extract transaction details - When
payment_intent.succeededis received:- Store transaction hashes from
charges[].transactions[] - Provide blockchain explorer links to customers
- Keep records for accounting and reconciliation
- Store transaction hashes from
For more details on webhook setup, signature verification, and complete event schemas, see the Webhook Events documentation.