Skip to content

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)
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.

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. Redirecting it sends the customer to a page they have never seen.

Pass solopay:none in both fields instead. The widget stops on its own completion screen rather than redirecting, and its button closes the tab instead of returning to the merchant. The cancel button is not shown at all.

Both fields are required and must parse as URLs, so an empty string or a bare none is rejected. solopay:none is a valid URI and passes validation.

With no redirect there is no callback URL. Confirm the result through a webhook or the status API.

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
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
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

Next Steps

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