Standalone Charges
Create billable charges for your customers with a single HTTP call. You always send the final amount you want to bill – Meshpay does not calculate prices.
Standalone charges don't require a billing flow, making them perfect for most use cases.
High-Level Flow
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ │ │ │ │ │ │ │
│ Create Charge │ ──▶ │ x402_requirements│ ──▶ │ User Pays │ ──▶ │ Confirmed │
│ (Button 1) │ │ (Response) │ │ (Button 2) │ │ (Webhook) │
│ │ │ │ │ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘ └─────────────────┘
- Create Charge - Your backend calls
POST /v1/chargesto create a billable charge - x402 Requirements - Meshpay returns formatted payment requirements with network, asset, and address
- User Pays - The buyer/agent executes payment on-chain using the x402 requirements
- Confirmed - Facilitator webhook confirms the payment and transaction status updates to
succeeded
Endpoint
/v1/chargesAuthorization: Bearer <MESHPAY_API_KEY>
Content-Type: application/json
Request Body
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
| amount | number | Required | Final amount to charge (e.g. 100 = $100.00) | 100 |
| currency | string | Required | ISO currency code (3 characters) | USD |
| customer_ref | string | null | Optional | Your internal customer ID or reference | user_123 |
| resource_ref | string | null | Optional | Resource being purchased (for verification matching) | article:premium-guide-42 |
| reference | string | null | Optional | Optional reference for this charge (order ID, job ID, etc.) | order_456 |
| metadata | object | null | Optional | Free-form JSON object stored with the transaction | {"order_id": "456", "tier": "pro"} |
| receiver_config_id | string | null | Optional | ID of payment receiver config to use (see Receiver Configs) | config_abc123 |
| network | string | null | Optional | Blockchain network (e.g., 'solana-mainnet', 'base-mainnet') | solana-mainnet |
| asset | string | null | Optional | Asset/token (e.g., 'USDC', 'USDT') | USDC |
| pay_to_address | string | null | Optional | Wallet address to receive payment (required if network/asset provided) | 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb |
| escrow_address | string | null | Optional | Meshpay settlement wallet (required if collection_mode is 'escrow') | 0xMeshpaySettlement... |
| facilitator | string | null | Optional | Facilitator endpoint URL for payment confirmation | https://facilitator.example.com/webhook |
| max_timeout_seconds | number | null | Optional | Maximum timeout for payment in seconds (default: 60) | 60 |
| collection_mode | string | null | Optional | Collection mode: 'direct' (payments go to pay_to_address) or 'escrow' (payments go to escrow_address) | direct |
🔄 Detailed Step-by-Step Flow
What happens behind the scenes when a payment is made.
① Developer Creates a Charge
When a user/agent accesses a paid endpoint, the developer's backend calls Meshpay API to create a charge with the amount and currency.
POST /v1/charges
{
"amount": 100,
"currency": "USD",
"customer_ref": "user_123",
"resource_ref": "api:premium-endpoint",
"reference": "api_request_456"
}
② Meshpay Resolves x402 Configuration
Meshpay resolves the payment configuration using the fallback chain:
- Charge request x402 fields
- Receiver config ID (if provided)
- Default receiver config
- Connected Solana wallet
- Error (no config found)
③ Returns Formatted x402 Requirements
Meshpay creates a pending transaction and returns formatted x402 payment requirements.
What you provided: network, asset, pay_to_address
What Meshpay added: x402 protocol structure, transaction tracking
{
"id": "txn_abc123",
"status": "pending",
"x402_requirements": {
"rail_config": {
"scheme": "exact",
"network": "solana-mainnet",
"asset": "USDC",
"pay_to_address": "0x742d...",
"max_timeout_seconds": 60
},
"amount": "100.00",
"currency": "USD",
"external_ref": "billing:txn_abc123"
}
}
④ Buyer/Agent Executes Payment
The buyer's wallet (or AI agent's automated wallet) reads the x402 requirements and executes an on-chain transaction:
- Sends 100 USDC
- To the pay_to_address
- On solana-mainnet
- With reference to
billing:txn_abc123
⑤ Transaction Confirmed
The blockchain network confirms the transaction and generates a unique transaction hash (tx_hash) that serves as immutable proof of payment.
// Transaction Hash
"0x7f3a8b2c4d5e6f..."
⑥ Facilitator Sends Confirmation
The facilitator monitors the blockchain and detects the payment. It sends a webhook to Meshpay with the transaction ID and tx_hash.
POST /v1/billing/webhook/facilitator
{
"transaction_id": "txn_abc123",
"tx_hash": "0x7f3a8b2c4d5e6f...",
"status": "succeeded"
}
⑦ Transaction Status Updated
Meshpay updates the transaction status from pending to succeeded, stores the tx_hash, and records the confirmation timestamp.
{
"id": "txn_abc123",
"status": "succeeded", // ✅ Updated!
"tx_hash": "0x7f3a8b2c4d5e6f...",
"confirmed_at": "2025-01-15T10:35:00Z"
}
📊 What Data Flows Where
Understanding the data exchange at each step:
| Step | From → To | Data | |------|-----------|------| | 1 | Developer → Meshpay | Amount, currency, customer reference, optional metadata, and payment receiver config | | 2 | Meshpay → Developer | Transaction ID, pending status, and x402_requirements (network, asset, pay_to_address, amount) | | 3 | Developer → Buyer/Agent | The x402_requirements object that contains all payment instructions | | 4 | Buyer → Blockchain | Signed transaction with amount, destination address, and memo/reference | | 5 | Blockchain → Facilitator | Transaction confirmation event with tx_hash | | 6 | Facilitator → Meshpay | Webhook with transaction_id, tx_hash, and status (succeeded/failed) |
Payment Configuration Options
You have three ways to provide x402 payment configuration:
Option A: Receiver Configs (Recommended)
Create reusable payment configs that can be referenced across charges. Best for production use.
Create a receiver config:
curl -X POST "https://api.orvion.sh/v1/billing/receiver-configs" \-H "Authorization: Bearer $MESHPAY_API_KEY" \-H "Content-Type: application/json" \-d '{"name": "Main Wallet","network": "solana-mainnet","asset": "USDC","pay_to_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb","is_default": true}'
Then create charges:
# Reference specific configcurl -X POST "https://api.orvion.sh/v1/charges" \-H "Authorization: Bearer $MESHPAY_API_KEY" \-H "Content-Type: application/json" \-d '{"amount": 100,"currency": "USD","receiver_config_id": "config_abc123"}'# Or use default config (no receiver_config_id needed)curl -X POST "https://api.orvion.sh/v1/charges" \-H "Authorization: Bearer $MESHPAY_API_KEY" \-H "Content-Type: application/json" \-d '{"amount": 100,"currency": "USD"}'
See Receiver Configs for complete documentation.
Option B: Direct x402 Fields
Provide payment details directly in each charge request:
curl -X POST "https://api.orvion.sh/v1/charges" \-H "Authorization: Bearer $MESHPAY_API_KEY" \-H "Content-Type: application/json" \-d '{"amount": 100,"currency": "USD","network": "solana-mainnet","asset": "USDC","pay_to_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"}'
Option C: Connected Solana Wallet (Automatic)
If you have a Solana wallet connected in the dashboard, it's used automatically:
- Network:
solana-mainnet - Asset:
USDC - Address: Your primary connected wallet
curl -X POST "https://api.orvion.sh/v1/charges" \-H "Authorization: Bearer $MESHPAY_API_KEY" \-H "Content-Type: application/json" \-d '{"amount": 100,"currency": "USD"}'
Note: Only works if you have a connected Solana wallet and no default receiver config.
x402 Configuration Resolution
When creating a charge, Meshpay resolves x402 payment configuration using this priority:
- Charge request x402 fields - If
network,asset, andpay_to_addressare provided directly - Receiver config - If
receiver_config_idis provided - Default receiver config - If a config with
is_default: trueexists - Connected Solana wallet - If you have a primary Solana wallet connected
- Error - If no configuration can be resolved
See Receiver Configs for details.
Collection Modes
Direct Mode
- Description: Payments go directly to
pay_to_address - Use Case: Simple flows, fast settlement
- Requirement:
pay_to_addressmust be provided
Escrow Mode
- Description: Payments go to
escrow_addressfirst, then distributed according to payout splits - Use Case: Splits, complex payout logic
- Requirement:
escrow_addressis required
Error Codes
400 Bad Request
- Invalid request (amount ≤ 0, missing fields, invalid JSON)
- Invalid currency format
- x402 configuration required (no receiver config, default config, or connected wallet found)
escrow_addressrequired whencollection_modeisescrow
401 Unauthorized
- Invalid or missing API key
404 Not Found
- Receiver config not found (if
receiver_config_idprovided)
500 Internal Server Error
- Internal error (retry may succeed)
Transaction Status Lifecycle
| Status | Description |
|--------|-------------|
| pending | Charge created, x402 requirements returned, awaiting payment |
| succeeded | Payment confirmed via facilitator webhook |
| failed | Payment failed (network error, insufficient funds, etc.) |
Charges start as pending. After the buyer pays on-chain, the facilitator webhook confirms the payment and status updates to succeeded.
After Payment: Verification
Once a charge is paid, use the Payment Verification endpoint to confirm payment before showing content:
POST /v1/charges/verify
{
"transaction_id": "txn_abc123",
"customer_ref": "user_123",
"resource_ref": "api:premium-endpoint"
}
Returns verified: true if payment is confirmed and references match.
See the Seller Integration Guide for complete examples.
Key Takeaways
- One-time setup: Create a receiver config with your wallet address and mark it as default
- Simple API: Just POST to /v1/charges with amount and currency
- x402 Protocol: Meshpay generates standardized payment requirements that any compatible wallet can execute
- Async confirmation: Charges start as "pending" and update to "succeeded" via webhook
- Flexible configs: Use default config, specific config ID, or provide payment details directly per charge
- AI Agent ready: The x402 requirements format allows autonomous AI agents to make payments programmatically
Best Practices
- Use Receiver Configs - Create reusable payment configs instead of hardcoding per charge
- Set a Default Config - Mark your primary config as
is_default: truefor automatic use - Always include
customer_ref- Helps track charges per customer and enables verification matching - Always include
resource_ref- Identifies what's being purchased, prevents payment reuse - Use
referencefor traceability - Link charges to your internal order IDs, job IDs, etc. - Store context in
metadata- Include any additional data you might need later - Handle
pendingstatus - Charges start aspending, wait for webhook confirmation - Verify before showing content - Always call
/v1/charges/verifybefore granting access - Use
x402_requirements- Pass the returned requirements to the buyer's wallet - Test with small amounts first - Verify your integration before processing real charges
Related Documentation
- Seller Integration Guide - Complete guide for sellers
- Payment Verification - Verify payments before showing content
- Webhooks - Receive payment notifications
- Flow-Based Charges - Create charges within billing flows
- Receiver Configs - Configure where to receive payments
- Billing Flows - Creating flows (advanced grouping coming soon)
- Transactions - Viewing and filtering charges
- SDK Examples - Using SDKs to create charges