Skip to content

Payments

Complete API reference for SoloPay payments.

Create Payment

Create a payment and receive a unique payment ID.

Overview

When using the SoloPay widget, payment creation is handled automatically by the widget. This page is a reference API spec for understanding the internals or for custom implementations.

Created payments expire automatically after 5 minutes.

  • Auth: x-public-key header required (pk_xxx)
  • Chain and recipient address are determined by merchant configuration
  • tokenAddress must be whitelisted and enabled for the merchant

REST API

bash
curl -X POST https://gateway.dev.solonetwork.io/api/v1/payments \
  -H "x-public-key: pk_xxxxx" \
  -H "Origin: https://yourshop.com" \
  -H "Content-Type: application/json" \
  -d '{
    "orderId": "order-001",
    "amount": 10.5,
    "tokenAddress": "0xE4C687167705Abf55d709395f92e254bdF5825a2",
    "successUrl": "https://example.com/success",
    "failUrl": "https://example.com/fail"
  }'

Request Parameters

FieldTypeReq.Description
orderIdstringMerchant order ID (no duplicates per merchant)
amountnumberPayment amount (token units or fiat units). Max 2 decimal places
tokenAddressaddressERC-20 token contract address (whitelisted & enabled for merchant)
successUrlstringRedirect URL on success (accepts solopay:none)
failUrlstringRedirect URL on failure (accepts solopay:none)
currencystringFiat currency code (e.g., USD, KRW). Triggers price conversion

currency option

When currency is provided, amount is treated as a fiat amount. The server automatically converts it using the latest 1-hour average price (TWAP) to determine the token amount. Example: amount: 10, currency: "USD" → pays the token amount equivalent to 10 USD based on the past 1-hour average price.

The 1-hour average dampens short-term price swings. The tokenPrice field in the response reflects the 1-hour average used for the conversion.

amount decimal restriction

amount allows a maximum of 2 decimal places (e.g., 10.50 ✓, 10.123 ✗). Without currency, the value is used directly as the token amount. With currency, the fiat amount is converted to token units and truncated to 2 decimal places. The minimum token amount is 0.01.

Payments with nowhere to return to (QR, kiosk, POS)

When a customer scans a QR shown in the store and pays on their own phone, that browser never came from your site. Pass solopay:none in both successUrl and failUrl instead. The widget stops on its completion screen rather than redirecting. Confirm the result through a webhook or GET /payments/:id.

Response

Success (201 Created)

json
{
  "success": true,
  "data": {
    "paymentId": "0xabc123def456...",
    "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
  }
}

Error Responses

HTTPCodeCause
400TOKEN_NOT_ENABLEDToken is not enabled for this merchant
404TOKEN_NOT_FOUNDToken not in whitelist
400UNSUPPORTED_CHAINUnsupported chain
400CHAIN_NOT_CONFIGUREDMerchant has no chain configured
400RECIPIENT_NOT_CONFIGUREDMerchant recipient address not configured
400CHAIN_MISMATCHToken does not belong to merchant chain
400UNSUPPORTED_TOKENToken not supported on this chain
400PRICE_SERVICE_NOT_CONFIGUREDCurrency conversion unavailable
400VALIDATION_ERRORInput validation failed
409DUPLICATE_ORDERorderId already used

Response Fields

FieldTypeDescription
paymentIdstringUnique payment identifier (bytes32 hash)
amountstringAmount in wei
gatewayAddressaddressPaymentGateway contract address
forwarderAddressaddressERC2771 Forwarder address (for Gasless)
merchantIdstringMerchant ID (bytes32)
deadlinestringServer signature deadline (Unix timestamp); required for pay() and gasless. Default: 1 hour (3600s)
expiresAtdatetimePayment expiry (5 minutes from creation)
tokenPermitSupportedbooleanWhether the token supports EIP-2612 Permit
isFaucetEnabledbooleanWhether the merchant can use the gas faucet (gas-status / request-gas) before approve
currencystringFiat currency code (included only when requested)
fiatAmountnumberOriginal fiat amount (included only when requested)
tokenPricenumberLatest 1-hour average token price (TWAP) used for conversion (included only when requested)

When isFaucetEnabled is true, custom integrations may call the gas faucet before approve. See Gasless Implementation.

When Using the Widget

When using the widget (@solo-pay/widget-js / @solo-pay/widget-react), there is no need to call this API directly — the widget handles it automatically.

See Widget Integration Guide


Payment Status

Query the current status of a payment.

  • Auth: x-public-key header required
  • For GET requests, use x-origin header instead of Origin in proxy environments

REST API

bash
curl https://gateway.dev.solonetwork.io/api/v1/payments/0xabc123... \
  -H "x-public-key: pk_xxxxx"

Response

Success (200 OK)

json
{
  "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 — Pay transaction hash. Present once payment is PAID or later.
  • isFaucetEnabled — Whether the gas faucet is available for this merchant. See Gasless Implementation when true.

Status Flow

CREATED ──► PAID ──► REFUND_SUBMITTED ──► REFUNDED
CREATED ──► EXPIRED
CREATED ──► FAILED
CREATED ──► INVALID

Status Descriptions

StatusDescriptionNext Action
CREATEDPayment created, awaiting on-chain transactionUser initiates payment
PAIDPayment confirmed on-chainNone (terminal for normal flow)
REFUND_SUBMITTEDRefund transaction submittedWait for REFUNDED
REFUNDEDRefund completed, funds returned to buyerNone (terminal)
INVALIDPayment validation failedCreate new payment
FAILEDTransaction failedCreate new payment
EXPIREDExpired (5 minutes exceeded)Create new payment

On-chain Sync

GET /payments/:id syncs blockchain and database status in real-time. For a successful payment, status is PAID (payment confirmed on-chain, funds transferred directly to the merchant).


Payment History

Query merchant payment history. Requires API Key authentication.

Both endpoints are currently available. /merchants/me/payments is recommended. /merchant/payments is a legacy endpoint and may be removed in the future.

REST API

bash
# Query by orderId (recommended)
curl "https://gateway.dev.solonetwork.io/api/v1/merchants/me/payments?orderId=order-001" \
  -H "x-api-key: sk_xxxxx"

# Query by orderId (legacy)
curl "https://gateway.dev.solonetwork.io/api/v1/merchant/payments?orderId=order-001" \
  -H "x-api-key: sk_xxxxx"

# Query by paymentId (recommended)
curl "https://gateway.dev.solonetwork.io/api/v1/merchants/me/payments/0xabc123..." \
  -H "x-api-key: sk_xxxxx"

# Query by paymentId (legacy)
curl "https://gateway.dev.solonetwork.io/api/v1/merchant/payments/0xabc123..." \
  -H "x-api-key: sk_xxxxx"

Response

json
{
  "success": true,
  "data": {
    "paymentId": "0xabc123...",
    "orderId": "order-001",
    "status": "PAID",
    "amount": "10500000000000000000",
    "tokenSymbol": "SUT",
    "tokenDecimals": 18,
    "txHash": "0xdef789...",
    "payerAddress": "0x1234...",
    "createdAt": "2024-01-26T12:30:00Z",
    "confirmedAt": "2024-01-26T12:35:42Z",
    "expiresAt": "2024-01-26T12:35:00Z"
  }
}

Response Fields

FieldTypeDescription
paymentIdstringUnique payment identifier (bytes32 hash)
orderIdstringMerchant order ID
statusstringCREATED, PAID, REFUND_SUBMITTED, REFUNDED, INVALID, EXPIRED, FAILED
amountstringAmount in wei
tokenSymbolstringToken symbol
tokenDecimalsnumberToken decimals
txHashstringOn-chain transaction hash (present after confirmation)
payerAddressstringPayer wallet address (present after confirmation)
confirmedAtstringPayment confirmation timestamp
expiresAtstringPayment expiry timestamp

Price Query

Query the current price or hourly average price of a token. API Key authentication is required.

Use the type parameter to select the query method. When type is hourly-average, the price in the response represents the average price for the previous full hour.

REST API

bash
# Current price
curl "https://gateway.dev.solonetwork.io/api/v1/prices?chainId=80002&tokenAddress=0xE4C687167705Abf55d709395f92e254bdF5825a2&type=current&currency=USD" \
  -H "x-api-key: sk_xxxxx"

# Hourly average price
curl "https://gateway.dev.solonetwork.io/api/v1/prices?chainId=80002&tokenAddress=0xE4C687167705Abf55d709395f92e254bdF5825a2&type=hourly-average&currency=USD" \
  -H "x-api-key: sk_xxxxx"

Request Parameters

FieldTypeRequiredDescription
chainIdstringEIP-155 chain ID (e.g. 80002)
tokenAddressstringToken contract address
typestringcurrent (default) or hourly-average
currencystringFiat currency code (default: USD)

Response

json
{
  "success": true,
  "data": {
    "type": "current",
    "chain_id": 80002,
    "token_address": "0xE4C687167705Abf55d709395f92e254bdF5825a2",
    "currency": "USD",
    "price": 1.0002,
    "symbol": "SUT"
  }
}

Response Fields

FieldTypeDescription
typestringcurrent or hourly-average
chain_idnumberChain ID
token_addressstringToken contract address
currencystringFiat currency code
pricenumberToken price. When type is hourly-average, this is the average price for the previous full hour
symbolstringToken symbol

Difference in price by type

  • current: The most recently collected token price (updated every 5 minutes)
  • hourly-average: The average price for the previous full hour. For example, at 4:20 PM, this returns the average of prices collected between 3:00 PM and 4:00 PM.

Error Responses

HTTPCodeCause
401UNAUTHORIZEDMissing or invalid API Key
404TOKEN_NOT_FOUNDToken not found or no price data
500INTERNAL_ERRORInternal server error

Non-custodial Web3 payment infrastructure for ERC-20 checkout, sponsored gas, and wallet-to-wallet settlement.