API Reference
Full SoloPay REST API specification.
Base URL
| Environment | URL |
|---|---|
| Production | https://gateway.solonetwork.io/api/v1 |
| Staging | https://gateway.dev.solonetwork.io/api/v1 |
| Development | http://localhost:3001/api/v1 |
Authentication
| Method | Header | Endpoints |
|---|---|---|
| Public Key | x-public-key | POST /payments, GET /payments/:id, POST /payments/:id/relay, GET /payments/:id/relay, GET /payments/:id/gas-status, POST /payments/request-gas |
| API Key | x-api-key | GET /merchant/*, POST /merchant/payment-methods, POST /refunds |
| None | - | GET /chains, GET /chains/tokens |
Payments
POST /payments
Create a payment. Auth: x-public-key + Origin
{
"orderId": "order-001",
"amount": 10.5,
"tokenAddress": "0xE4C687167705Abf55d709395f92e254bdF5825a2",
"successUrl": "https://example.com/success",
"failUrl": "https://example.com/fail",
"currency": "USD"
}Response (201)
{
"success": true,
"data": {
"paymentId": "0xabc123...",
"orderId": "order-001",
"chainId": 80002,
"tokenAddress": "0xE4C687167705Abf55d709395f92e254bdF5825a2",
"tokenSymbol": "SUT",
"tokenDecimals": 18,
"gatewayAddress": "0x...",
"forwarderAddress": "0x...",
"amount": "10500000000000000000",
"recipientAddress": "0xMerchantWallet...",
"merchantId": "0x...",
"deadline": "1706281200",
"successUrl": "https://example.com/success",
"failUrl": "https://example.com/fail",
"expiresAt": "2024-01-26T12:35:00.000Z",
"tokenPermitSupported": true,
"isFaucetEnabled": true,
"currency": "USD",
"fiatAmount": 10.5,
"tokenPrice": 1.0
}
}GET /payments/:id
Get payment status. Auth: x-public-key
Status values: CREATED, PAID, REFUND_SUBMITTED, REFUNDED, INVALID, EXPIRED, FAILED. Payment success = PAID (funds transferred directly to merchant).
Response (200)
{
"success": true,
"data": {
"paymentId": "0xabc123...",
"orderId": "order-001",
"status": "PAID",
"chainId": 80002,
"tokenAddress": "0xE4C687167705Abf55d709395f92e254bdF5825a2",
"tokenSymbol": "SUT",
"tokenDecimals": 18,
"tokenPermitSupported": true,
"isFaucetEnabled": true,
"gatewayAddress": "0x...",
"forwarderAddress": "0x...",
"amount": "10500000000000000000",
"recipientAddress": "0xMerchantWallet...",
"merchantId": "0x...",
"deadline": "1706281200",
"successUrl": "https://example.com/success",
"failUrl": "https://example.com/fail",
"expiresAt": "2024-01-26T12:35:00.000Z",
"txHash": "0xdef789...",
"payerAddress": "0x...",
"createdAt": "2024-01-26T12:30:00Z",
"currency": "USD",
"fiatAmount": 10.5,
"tokenPrice": 1.0
}
}- txHash — Hash of the pay transaction. Present once the payment is PAID or later.
- deadline — Signature deadline (Unix timestamp) for the payment request; used when status is not yet terminal.
POST /payments/:id/relay
Submit a Gasless payment (ERC-2771). Auth: x-public-key + Origin
{
"paymentId": "0xabc123...",
"forwarderAddress": "0x...",
"forwardRequest": {
"from": "0x...",
"to": "0x...",
"value": "0",
"gas": "200000",
"nonce": "1",
"deadline": "1706281200",
"data": "0x...",
"signature": "0x..."
}
}Response (202)
{
"success": true,
"data": {
"status": "submitted",
"message": "Gasless transaction submitted"
}
}GET /payments/:id/relay
Get relay status. Auth: x-public-key
{
"success": true,
"data": {
"status": "CONFIRMED",
"transactionHash": "0xdef789...",
"errorMessage": null,
"createdAt": "2024-01-26T12:34:00Z",
"updatedAt": "2024-01-26T12:35:42Z"
}
}Status values: QUEUED → SUBMITTED → CONFIRMED (or FAILED)
GET /payments/:id/gas-status
Check whether a wallet can receive a one-time native-token grant for the token approval transaction. Auth: x-public-key
curl "https://gateway.dev.solonetwork.io/api/v1/payments/0xabc123.../gas-status?walletAddress=0xPayer..." \
-H "x-public-key: pk_xxxxx"{
"needsGas": true,
"hasEnoughTokenBalance": true,
"alreadyGranted": false,
"canReceiveGas": true
}The merchant must have the faucet enabled (isFaucetEnabled: true on the payment response). A wallet can receive at most one grant per chain, and a payment can fund at most one grant.
| Field | Description |
|---|---|
needsGas | Native balance is below the estimated approve cost |
hasEnoughTokenBalance | Wallet holds at least the payment token amount |
alreadyGranted | This wallet already received a grant on this chain |
canReceiveGas | needsGas && !alreadyGranted && hasEnoughTokenBalance |
canReceiveGas is wallet-level only
canReceiveGas does not detect whether this payment already funded a grant for another wallet. A subsequent request-gas call may still return PAYMENT_ALREADY_GRANTED. Handle that error when calling POST /payments/request-gas.
Error responses
| HTTP | Code | Cause |
|---|---|---|
| 403 | FAUCET_DISABLED | Faucet is not enabled for this merchant (not a 200 with canReceiveGas: false) |
| 404 | NOT_FOUND | Payment does not exist or does not belong to the authenticated merchant |
See Error Codes for all gas faucet errors.
POST /payments/request-gas
Request the one-time native-token grant used to submit an ERC-20 approve transaction. Auth: x-public-key + Origin
curl -X POST https://gateway.dev.solonetwork.io/api/v1/payments/request-gas \
-H "x-public-key: pk_xxxxx" \
-H "Origin: https://yourshop.com" \
-H "Content-Type: application/json" \
-d '{
"paymentId": "0xabc123...",
"walletAddress": "0xPayer..."
}'{
"txHash": "0xdef789...",
"amount": "10000000000000000",
"chainId": 80002
}A grant is issued only when the payment belongs to the authenticated merchant, the wallet has enough payment tokens, and its native balance is below the estimated approval cost. The response is returned after the grant transaction is confirmed on-chain, so you can submit approve as soon as this call succeeds.
When ALLOWED_WIDGET_ORIGIN is set on the gateway, Origin must match that value exactly. Browsers set Origin automatically on fetch; server-side callers must set it explicitly. See Authentication.
Error responses
| HTTP | Code | Cause |
|---|---|---|
| 403 | FAUCET_DISABLED | Faucet is not enabled for this merchant |
| 403 | FORBIDDEN | Origin does not match ALLOWED_WIDGET_ORIGIN |
| 404 | NOT_FOUND | Payment does not exist or does not belong to the authenticated merchant |
| 400 | INSUFFICIENT_TOKEN_BALANCE | Wallet token balance is below the payment amount |
| 400 | ALREADY_HAS_GAS | Wallet already has enough native token for approve |
| 400 | ALREADY_GRANTED | Wallet already received a grant on this chain |
| 400 | PAYMENT_ALREADY_GRANTED | This payment already funded a grant |
| 409 | GRANT_IN_PROGRESS | Another grant request for this payment is in progress |
See Error Codes for details.
Merchant
GET /merchant
Get merchant info. Auth: x-api-key
{
"success": true,
"data": {
"merchant": {
"id": 1,
"merchant_key": "my-store",
"name": "My Store",
"chain_id": 80002,
"chain": { "id": 1, "network_id": 80002, "name": "Polygon Amoy", "is_testnet": true },
"webhook_url": null,
"public_key": "pk_xxx",
"is_enabled": true,
"payment_methods": [...]
},
"chainTokens": [...]
}
}GET /merchant/payment-methods
List payment methods. Auth: x-api-key
POST /merchant/payment-methods
Add a payment method. Auth: x-api-key
{ "tokenAddress": "0x...", "is_enabled": true }PATCH /merchant/payment-methods/:id
Update a payment method. Auth: x-api-key
{ "is_enabled": false }GET /merchant/payments
List payments. Auth: x-api-key. Query: orderId
GET /merchant/payments/:id
Get payment detail. Auth: x-api-key
Chains
GET /chains
Get supported chains. No auth required.
{
"success": true,
"data": {
"chains": [
{ "id": 1, "network_id": 80002, "name": "Polygon Amoy", "is_testnet": true },
{ "id": 2, "network_id": 97, "name": "BSC Testnet", "is_testnet": true },
{ "id": 3, "network_id": 11155111, "name": "Sepolia", "is_testnet": true }
]
}
}GET /chains/tokens
Get all chains with their tokens. No auth required.
Health
GET /health
Server health check. No auth required.
{ "status": "ok", "timestamp": "2024-01-26T12:00:00.000Z" }Next Steps
- Error Codes - Error handling