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:

1{
2 "company": {
3 "id": "01KZ2WJKWVFPCVAB6MY106QRZV",
4 "name": "Acme Ltd",
5 "status": "Pending",
6 "swap": {
7 "kycUrl": "https://public-api.demo.alphax.asia/kyc/9f2c1d84e7b6a5309c8f",
8 "kycStatus": "not_started",
9 "tosUrl": "https://public-api.demo.alphax.asia/kyc/9f2c1d84e7b6a5309c8f/terms",
10 "tosAccepted": false
11 }
12 }
13}

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 approvedcompany.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
USDswiftaccountNumber, bic
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"
1{
2 "paymentRoute": {
3 "id": "01KZ2RT4Q8N7YB3D5F6G7H8J9K",
4 "type": "offramp",
5 "status": "active",
6 "currency": "USD",
7 "feePercent": 0.9,
8 "depositAddress": "TTRRSXZza9kJuv1fSUeehfkJsZntqUQSqp",
9 "source": {
10 "type": "crypto",
11 "currency": "USDT",
12 "paymentRail": "tron",
13 "address": "TTRRSXZza9kJuv1fSUeehfkJsZntqUQSqp"
14 },
15 "destination": {
16 "type": "bank",
17 "currency": "USD",
18 "paymentRail": "ach",
19 "bankName": "Example Bank",
20 "bankAccountNumber": "1234567890",
21 "bankRoutingNumber": "021000021",
22 "bankBeneficiaryName": "Acme Ltd"
23 },
24 "createdAt": "2026-08-13T09:41:22.000000Z"
25 }
26}

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:

1{
2 "type": "PaymentRoute",
3 "transaction": {
4 "id": "01KZ2TXN4Q8N7YB3D5F6G7H8J9",
5 "direction": "Credit",
6 "amount": "99.10",
7 "currency": "USD",
8 "description": "[payment route] 100.00 USDT",
9 "counterpartyName": "TFrom...",
10 "createdAt": "2026-08-13T10:02:11.000000Z"
11 },
12 "data": {
13 "routeId": "01KZ2RT4Q8N7YB3D5F6G7H8J9K",
14 "routeType": "offramp",
15 "incomingAmount": "100.00",
16 "convertedAmount": "99.10",
17 "totalFees": "0.90",
18 "sourceTxHash": "0x...",
19 "destinationTxHash": "0x...",
20 "source": { "paymentRail": "tron", "currency": "USDT", "fromAddress": "TFrom..." },
21 "destination": { "paymentRail": "ach", "currency": "USD", "bankName": "Example Bank" }
22 }
23}

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.