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
failUrlstringRedirect URL on failure
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.

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,
    "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)
deadlinestringPayment deadline (Unix timestamp); pay() must be called before this time. Default: 5 minutes (300s)
expiresAtdatetimePayment expiry (5 minutes from creation)
tokenPermitSupportedbooleanWhether the token supports EIP-2612 Permit
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 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,
    "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.

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.