Create a payment (Alsopay)

The recommended integration: one signed call creates an order, supporting multiple networks and tokens.

Before you start

  1. Create an API key pair in the console under API keys: api_key_id and secret_key
  2. Configure your callback URL (callback_url) and IP allow-list

Endpoint

POST https://api.alsoluna.xyz/payments/v1/orders
The exact address (with your environment's API domain) is shown in the console under Payment setup → Integration docs.

Signing

  1. Take every parameter except signature
  2. Sort the parameter names in ASCII order and join as key1=value1&key2=value2...
  3. signature = hex(HMAC-SHA256(joined, secret_key)), lowercase
const crypto = require('crypto')

function sign(params, secretKey) {
  const sorted = Object.keys(params)
    .filter((k) => k !== 'signature')
    .sort()
    .map((k) => k + '=' + params[k])
    .join('&')

  return crypto.createHmac('sha256', secretKey).update(sorted).digest('hex')
}

const order = await fetch('https://api.alsoluna.xyz/payments/v1/orders', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    api_key_id: 'your api_key_id',
    reference: 'MERCHANT_ORDER_001',
    callback_url: 'https://merchant.example.com/notify',
    return_url: 'https://merchant.example.com/return',
    amount: '100.00',
    token: 'usdt',
    network: 'tron',
    signature: sign({ ... }, secretKey),
  }),
})

Request parameters

ParameterRequiredDescription
api_key_idYesAPI key id, created under API keys
referenceYesYour order id (customer transaction id); must be unique
callback_urlYesAsynchronous callback URL
amountYesOrder amount (fiat)
tokenNoToken, e.g. usdt / trx / ton
networkNoNetwork, e.g. tron / ton
return_urlNoRedirect URL after payment
payment_channelNoCompatibility marker; part of the signature
signatureYesHMAC-SHA256 signature (lowercase hex)

Response fields

FieldDescription
transaction_idPlatform transaction id (use it for status checks and reconciliation)
amount_dueAmount due — transfer this exact amount (the platform matches by address and amount; a different amount is treated as unpaid)
receiving_addressReceiving address
tokenToken (empty on status=4 placeholder orders)
networkNetwork (empty on status=4 placeholder orders)
statusOrder status, see "Check payment status" below
expires_atExpiry time (unix seconds)
checkout_urlCheckout URL (send the payer here by default)

Two ways to get paid

Option 1: redirect to the hosted checkout (recommended)

Open the payer at the checkout_url from the response. The QR code, countdown, network/token switching and manual top-ups are all handled by the checkout page — you do not need to render a payment UI.

Option 2: build your own payment page

Render your own QR from receiving_address + amount_due and poll the status endpoint to detect payment (that endpoint needs no signature, so poll it from your server).

Caveats for a self-built page:

  1. The payer must transfer the exact amount; a different amount is never matched
  2. Pass token and network explicitly when creating the order — otherwise you get a status=4 placeholder and must first call the switch endpoint to pick a network/token
  3. If the browser polls instead of your server, add your site origin to the platform's cross-origin allow-list

Check payment status

GET https://api.alsoluna.xyz/gateway/check-status/{transaction_id}

No signature required.

ValueMeaning
1Waiting for payment
2Paid (credited; a callback is sent at the same time)
3Expired
4Waiting for the payer to choose a network/token (placeholder order)

Domain split

  • Single-domain deployment: the endpoint above shares the domain with the checkout page — use it as is
  • Split deployment: your server talks only to the API domain; the checkout page lives on the checkout domain and its address comes from checkout_url in the order response — use it directly, never build it yourself. The checkout page calls the status endpoint cross-origin, and the allow-list is configured by the platform
  • The checkout page domain does not serve /payments/* merchant endpoints — never use the page address as the API address