Skip to navigation

Swap API quickstart

Onboard, verify, and open a payment route end to end
View as Markdown

This walks through the whole flow against the sandbox (https://public-api.demo.alphax.asia). Set your key once:

export ALPHAX_KEY="<YOUR_API_KEY>"
export BASE="https://public-api.demo.alphax.asia/v1"

1. Onboard a company onto swap

curl -X POST "$BASE/companies" \
-H "X-API-Key: $ALPHAX_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Ltd",
"countryCode": "HK",
"directorName": "Jane Director",
"directorEmail": "jane@acme.example",
"directorPhone": "+85251234567",
"addressLine1": "10 Queens Road",
"city": "Hong Kong",
"state": "Hong Kong",
"postalCode": "999077",
"products": ["Swap"],
"redirectUri": "https://your-app.example/onboarding/done"
}'

products defaults to ["Card"] when omitted — send ["Swap"] explicitly. Requesting a product you are not entitled to returns 403 PRODUCT_NOT_ENABLED.

The response carries the company id and a swap block:

{
"company": {
"id": "01KZ2WJKWVFPCVAB6MY106QRZV",
"name": "Acme Ltd",
"status": "Pending",
"swap": {
"kycUrl": "https://public-api.demo.alphax.asia/kyc/9f2c1d84e7b6a5309c8f",
"kycStatus": "not_started",
"tosUrl": "https://public-api.demo.alphax.asia/kyc/9f2c1d84e7b6a5309c8f/terms",
"tosAccepted": false
}
}
}

Export the company id — it is the X-Company-Id header on every call below.

export CID="01KZ2WJKWVFPCVAB6MY106QRZV"

2. Get the company verified

Send the director to kycUrl, or embed it in your own site — see the Verification page. You can re-read it any time:

curl "$BASE/kyc-link" \
-H "X-API-Key: $ALPHAX_KEY" -H "X-Company-Id: $CID"

Show tosUrl too — the company must accept the terms before it can be endorsed, and tosAccepted tells you whether that is still outstanding.

Wait for kycStatus to reach approved — company.kyc_status_changed tells you the moment it does, so you do not need to poll.

3. Open a payment route

curl -X POST "$BASE/payment-routes" \
-H "X-API-Key: $ALPHAX_KEY" -H "X-Company-Id: $CID" \
-H "Content-Type: application/json" \
-d '{
"type": "onramp",
"sourceCurrency": "USD",
"destinationCurrency": "USDC",
"destinationPaymentRail": "base",
"destinationAddress": "0xYourTreasuryAddress"
}'

Destination bank fields for off-ramp

Which fields are required depends on the currency and rail you pick. A rail that does not belong to the currency is rejected with a destinationPaymentRail validation error.

DestinationdestinationPaymentRailAlso required
USDach, wireaccountNumber, routingNumber, checkingOrSavings, state
EURsepaiban, bic, ibanCountry (or country)
GBPfpsaccountNumber (8 digits), sortCode (6 digits)

accountOwnerName, bankName, addressLine1, city and postalCode are always required.

4. Tell the payer where to send funds

export RID="<route id from the response>"
curl "$BASE/payment-routes/$RID" \
-H "X-API-Key: $ALPHAX_KEY" -H "X-Company-Id: $CID"
{
"paymentRoute": {
"id": "01KZ2RT4Q8N7YB3D5F6G7H8J9K",
"type": "offramp",
"status": "active",
"currency": "USD",
"feePercent": 0.9,
"depositAddress": "TTRRSXZza9kJuv1fSUeehfkJsZntqUQSqp",
"source": {
"type": "crypto",
"currency": "USDT",
"paymentRail": "tron",
"address": "TTRRSXZza9kJuv1fSUeehfkJsZntqUQSqp"
},
"destination": {
"type": "bank",
"currency": "USD",
"paymentRail": "ach",
"bankName": "Example Bank",
"bankAccountNumber": "1234567890",
"bankRoutingNumber": "021000021",
"bankBeneficiaryName": "Acme Ltd"
},
"createdAt": "2026-08-13T09:41:22.000000Z"
}
}

depositAddress is the short answer to “where does the payer send money” — the deposit account number for an on-ramp, the chain address for an off-ramp. The source and destination blocks carry the full detail; each is either type: "bank" or type: "crypto", so branch on that rather than on currency.

Two PDFs are available for the customer’s bank or counterparty:

# How to fund the route
curl "$BASE/payment-routes/$RID/payment-instructions" \
-H "X-API-Key: $ALPHAX_KEY" -H "X-Company-Id: $CID"
# Confirmation the deposit account belongs to the company
curl "$BASE/payment-routes/$RID/account-letter" \
-H "X-API-Key: $ALPHAX_KEY" -H "X-Company-Id: $CID"

Both return { "url": "…" }. The link is short-lived — fetch it when the customer asks rather than storing it.

5. Follow the money

# This route only
curl "$BASE/payment-routes/$RID/transactions" \
-H "X-API-Key: $ALPHAX_KEY" -H "X-Company-Id: $CID"
# Everything for the company, across every product
curl "$BASE/transactions?limit=25" \
-H "X-API-Key: $ALPHAX_KEY" -H "X-Company-Id: $CID"
# Narrowed to one route
curl "$BASE/transactions?paymentRouteId=$RID" \
-H "X-API-Key: $ALPHAX_KEY" -H "X-Company-Id: $CID"

Every item is a discriminated union — switch on type, then read data:

{
"type": "PaymentRoute",
"transaction": {
"id": "01KZ2TXN4Q8N7YB3D5F6G7H8J9",
"direction": "Credit",
"amount": "99.10",
"currency": "USD",
"description": "[payment route] 100.00 USDT",
"counterpartyName": "TFrom...",
"createdAt": "2026-08-13T10:02:11.000000Z"
},
"data": {
"routeId": "01KZ2RT4Q8N7YB3D5F6G7H8J9K",
"routeType": "offramp",
"incomingAmount": "100.00",
"convertedAmount": "99.10",
"totalFees": "0.90",
"sourceTxHash": "0x...",
"destinationTxHash": "0x...",
"source": { "paymentRail": "tron", "currency": "USDT", "fromAddress": "TFrom..." },
"destination": { "paymentRail": "ach", "currency": "USD", "bankName": "Example Bank" }
}
}

transaction is identical for every product; data is specific to type. On GET /v1/transactions you may also see Card, PaymentAcceptance and Account.

All three listings accept page, limit (5–50), type (Credit / Debit), orderBy (createdAt / amount) and orderDirection (ASC / DESC), and default to newest first.