Affiliate Service API Integration Guide
NOTE: API documentation is currently under development
1) Scope
AffiliateService - service for affiliate integration.
This API is dedicated to affiliate partners and designed for production integrations.
Key points:
- API is public/open (no auth headers required).
affiliateIdis generated by the service. It may look like an EVM wallet address, but is not the same value as the original wallet used during registration.affiliateIdis the primary identifier for all subsequent calls after registration.- After registration the affiliate is activated asynchronously (on-chain funding
- fee-pool registration). Use
isActivatedfrom register/lookup responses before relying on fee balance or withdrawals.
- fee-pool registration). Use
- Registration accepts
evmWallet,btcWallet, or both. At least one is required. - Withdrawal mode is chosen at registration:
- Omit
withdrawalModeto keep the previous behavior: EVM-only affiliates withdraw automatically inusdt_bnb; any registration that includesbtcWallet(Bitcoin-only or EVM + Bitcoin) is manual. - Pass
withdrawalModeto override that default.autoalso requirestoken.manualdoes not taketoken.
- Omit
- Automatic (
auto): when the fee balance reaches the configured threshold (default 100 USD), the service withdraws in the token chosen at registration.btcpaysbtcWallet; every other token paysevmWallet. The token must match a wallet supplied in the same request. - Manual (
manual): the partner callsPOST /affiliates/{affiliateId}/withdraw-feesand chooses the payout token (usdt_bnb,usdc_bnb,usdt_eth,usdc_eth,eth, orbtc) once the balance reaches the same threshold. The token must match a registered wallet.
2) Core terms
evmWallet: external EVM wallet. Optional whenbtcWalletis set. Used for every payout token exceptbtc.btcWallet: Bitcoin payout address (mainnet: legacy1…/3…or Bech32bc1q…/bc1p…). Optional whenevmWalletis set. Used forbtcpayouts.withdrawalMode: optionalautoormanual. When omitted, EVM-only registration isautowith tokenusdt_bnb, and a Bitcoin address selectsmanual.token: payout token for automatic withdrawal. Required only whenwithdrawalModeisauto. Must bebtcwhen onlybtcWalletis set, and must not bebtcwhen onlyevmWalletis set.affiliateId: service-generated affiliate identifier (external-facing ID for API calls).isActivated: whether on-chain activation finished successfully. Fee accrual and withdrawals require an activated affiliate.l1TxId: swap transaction identifier on L1 side.
3) Data format and transport conventions
- Base URL (example):
https://api-affiliate.pactswap.io/api/v1 - Content type:
application/json - Successful responses use
2xxstatus codes. - Error responses use
4xx/5xxstatus codes and unified error envelope. - Address/id fields are case-insensitive in requests, but response values should be treated as canonical (except Base58 BTC addresses, which keep original casing).
- Monetary values are returned as string decimals to avoid precision loss.
- For swap endpoints, numeric token amounts (for example,
amountFrom) are in the smallest token units (not human-readable units): satoshis for BTC, wei for ETH/BNB/POL, etc. Example:amountFrom=100for BTC means100 satoshis, not100 BTC.
4) Versioning policy
- API version is part of URL:
/api/v1. - Backward-compatible additions may include new optional fields.
- Breaking changes are released under a new version path (for example,
/api/v2).
5) Error response format
Unified error envelope (recommended):
{
"error": {
"code": "AFFILIATE_NOT_FOUND",
"message": "Affiliate does not exist",
"details": {}
}
}Common error codes:
INVALID_ARGUMENTAFFILIATE_ALREADY_EXISTSAFFILIATE_NOT_FOUNDAFFILIATE_NOT_ACTIVATEDMANUAL_WITHDRAWAL_NOT_ALLOWEDTOKEN_WALLET_MISMATCHBELOW_THRESHOLDSWAP_NOT_FOUNDRATE_LIMITEDINTERNAL_ERROR
6) REST endpoints
6.1 Register affiliate
- Method/Path:
POST /affiliates - Purpose: register a new affiliate by
evmWallet,btcWallet, or both, and generateaffiliateId. Activation starts asynchronously; new affiliates returnisActivated: false.
Request body (explicit mode):
{
"evmWallet": "0x1234567890abcdef1234567890abcdef12345678",
"btcWallet": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
"withdrawalMode": "auto",
"token": "btc"
}withdrawalMode and token are optional. Existing clients can keep sending
only wallets:
| Body | Result |
|---|---|
{ "evmWallet" } | auto withdrawal in usdt_bnb (unchanged) |
{ "evmWallet", "btcWallet" } | manual withdrawal (unchanged) |
{ "btcWallet" } | manual withdrawal, Bitcoin-only |
withdrawalMode: "auto" + token | automatic withdrawal in that token; the matching wallet must be in the body |
withdrawalMode: "manual" | manual withdrawal; do not send token |
token values are the same as for withdraw-fees (usdt_bnb, usdc_bnb,
usdt_eth, usdc_eth, eth, btc). btc requires btcWallet. Every other
token requires evmWallet.
Example to register a new affiliate by EVM wallet (optional BTC):
BASE_URL="https://api-affiliate.pactswap.io/api/v1"
curl -sS -X POST "$BASE_URL/affiliates" \
-H "Content-Type: application/json" \
-d '{
"evmWallet": "0x1234567890abcdef1234567890abcdef12345678",
"btcWallet": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"
}'Response 201:
{
"affiliateId": "0x9a8b7c6d5e4f3210abcdeffedcba012345678901",
"isActivated": false
}Possible errors:
400 INVALID_ARGUMENT(invalid wallet, missing wallet,tokenmissing or not allowed for the mode, ortokendoes not match the supplied wallet)409 AFFILIATE_ALREADY_EXISTS(EVM or BTC wallet already registered)
6.2 Get affiliate by wallet
- Method/Path:
GET /affiliates/by-wallet/{wallet} - Purpose: resolve existing
affiliateId(and activation status) by the EVM or Bitcoin wallet used at registration. EVM lookup is unchanged; Bitcoin addresses are accepted as well (needed for Bitcoin-only affiliates).
Example to resolve affiliateId by partner wallet:
BASE_URL="https://api-affiliate.pactswap.io/api/v1"
EVM_WALLET="0x1234567890abcdef1234567890abcdef12345678"
curl -sS "$BASE_URL/affiliates/by-wallet/$EVM_WALLET"Response 200:
{
"affiliateId": "0x9a8b7c6d5e4f3210abcdeffedcba012345678901",
"isActivated": true
}Possible errors:
400 INVALID_ARGUMENT(invalid wallet format)404 AFFILIATE_NOT_FOUND
6.3 Get fee balance
- Method/Path:
GET /affiliates/{affiliateId}/fee-balance - Purpose: get current fee balance in USD.
Example to get current affiliate fee balance:
BASE_URL="https://api-affiliate.pactswap.io/api/v1"
AFFILIATE_ID="0x9a8b7c6d5e4f3210abcdeffedcba012345678901"
curl -sS "$BASE_URL/affiliates/$AFFILIATE_ID/fee-balance"Response 200:
{
"balanceUsd": "1234.560000"
}Possible errors:
400 INVALID_ARGUMENT(invalidaffiliateIdformat)404 AFFILIATE_NOT_FOUND
6.4 Manual fee withdrawal
- Method/Path:
POST /affiliates/{affiliateId}/withdraw-fees - Purpose: manually withdraw accumulated fees. Only available for affiliates
registered in manual mode (the default when
btcWalletis sent andwithdrawalModeis omitted, or whenwithdrawalModeismanual). The affiliate must be activated, the fee balance must be at or above the withdrawal threshold, andtokenmust match a wallet stored for that affiliate.
Request body:
{
"token": "btc"
}Supported token values:
token | Payout chain | Destination wallet |
|---|---|---|
usdt_bnb | BNB | evmWallet |
usdc_bnb | BNB | evmWallet |
usdt_eth | ETH | evmWallet |
usdc_eth | ETH | evmWallet |
eth | ETH | evmWallet |
btc | BTC | btcWallet |
Example:
BASE_URL="https://api-affiliate.pactswap.io/api/v1"
AFFILIATE_ID="0x9a8b7c6d5e4f3210abcdeffedcba012345678901"
curl -sS -X POST "$BASE_URL/affiliates/$AFFILIATE_ID/withdraw-fees" \
-H "Content-Type: application/json" \
-d '{
"token": "btc"
}'Response 201 / 200:
{
"recordId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"token": "btc",
"feesUsdVirtual": 105,
"l1Amount": "65000",
"l1Address": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
"tokenDecimals": 8,
"orderEmbedId": "embed-id-example",
"orderL2Txid": "l2-txid-example"
}Notes:
l1Amountis in the payout token’s smallest units (derived from fee USD notional and current token USD price).orderEmbedId/orderL2Txididentify the on-chain payout order created by the service.
Possible errors:
400 INVALID_ARGUMENT(invalidaffiliateId/token)400 MANUAL_WITHDRAWAL_NOT_ALLOWED(affiliate is on automatic withdrawal)400 TOKEN_WALLET_MISMATCH(btcwithoutbtcWallet, or any other token withoutevmWallet)400 BELOW_THRESHOLD(detailsincludesbalanceUsdandthresholdUsd)404 AFFILIATE_NOT_FOUND422 AFFILIATE_NOT_ACTIVATED500 INTERNAL_ERROR
6.5 List affiliate withdrawals
- Method/Path:
GET /affiliates/{affiliateId}/withdrawals - Purpose: paginated list of fee withdrawals for the affiliate (automatic EVM
payouts and manual
withdraw-feesrecords).
Query params:
offset(number, optional, default0) — number of items to skip. Must be≥ 0.count(number, optional, default10) — page size. Must be1..100.
Example:
BASE_URL="https://api-affiliate.pactswap.io/api/v1"
AFFILIATE_ID="0x9a8b7c6d5e4f3210abcdeffedcba012345678901"
curl -sS "$BASE_URL/affiliates/$AFFILIATE_ID/withdrawals" \
--get \
--data-urlencode "offset=0" \
--data-urlencode "count=10"Response 200 (example):
{
"withdrawals": [
{
"id": "2d03607f-5bfc-4354-9721-b7753e805a6a",
"createdAt": "2026-09-08T07:57:42.482Z",
"feesUsdVirtual": 4565677889861197300,
"token": "usdt_bnb",
"l1Amount": "4565677889861197300",
"l1Address": "0x018a81aaf8b984d0f0d962580d476505d4130b94",
"orderCweb": "3009348365199166228726",
"orderEmbedId": "e47ef0f49c34ff05b13cf7dcb171371db779f61f20b264ff00fb0ef659399233",
"orderL2Txid": "e47ef0f49c34ff05b13cf7dcb171371db779f61f20b264ff00fb0ef659399233",
"orderId": "0x088d86b538bd6e8898b23a8ea86bafb1f47dcb752d80ccc39e6bd2ac2bd4ebd0",
"payoutL1TxId": "b7c907b873a07dacad7d62810d2cc0c7bf8dc89193dcbf958a602976f44a917a",
"orderStatus": "closed",
"activityStatus": "COMPLETED",
"closedAt": "2026-09-08T08:00:01.306Z"
},
{
"id": "56334a36-c835-4744-9ede-1ba2525cde4f",
"createdAt": "2026-05-12T10:47:12.202Z",
"feesUsdVirtual": 4568102093523446000,
"token": null,
"l1Amount": null,
"l1Address": null,
"orderCweb": "3412464381565092346392",
"orderEmbedId": "97ca5d3805e6efd6b6f1e8cda1cdb6f44da536fb15279a6272b17e36c8a93fe1",
"orderL2Txid": "97ca5d3805e6efd6b6f1e8cda1cdb6f44da536fb15279a6272b17e36c8a93fe1",
"orderId": "0x1ee7761947854e02631e3898c8439f5f68bd3ba29fe764d021823be5671bdb96",
"payoutL1TxId": null,
"orderStatus": null,
"activityStatus": null,
"closedAt": null
}
],
"offset": 0,
"count": 10,
"hasMore": false
}Notes:
idis the withdrawal record identifier (same role asrecordIdfromPOST /affiliates/{affiliateId}/withdraw-fees).createdAt/closedAtare ISO-8601 timestamps.closedAtis set when the payout finishes.l1Amountis in the payout token’s smallest units when present.orderEmbedId/orderL2Txid/orderIdidentify the on-chain payout order.payoutL1TxIdis the L1 transaction id of the completed payout.token,l1Amount,l1Address,payoutL1TxId,orderStatus,activityStatus, andclosedAtarenulluntil the payout is filled in.offset/countin the response echo the requested pagination.hasMore: truemeans another page is available; request the next page withoffset = offset + count.
Possible errors:
400 INVALID_ARGUMENT(invalidaffiliateIdformat,offset < 0, orcountoutside1..100)404 AFFILIATE_NOT_FOUND
6.6 List affiliate swaps
- Method/Path:
GET /affiliates/{affiliateId}/swaps - Purpose: paginated list of swaps attributed to the affiliate. Use each
l1TxIdwithGET /swaps/{l1TxId}(§ 6.7) orGET /getL1TxInfo(§ 6.8) when you need fee amounts or ledger allocations.
Query params:
offset(number, optional, default0) — number of items to skip. Must be≥ 0.count(number, optional, default10) — page size. Must be1..100.
Example:
BASE_URL="https://api-affiliate.pactswap.io/api/v1"
AFFILIATE_ID="0x9a8b7c6d5e4f3210abcdeffedcba012345678901"
curl -sS "$BASE_URL/affiliates/$AFFILIATE_ID/swaps" \
--get \
--data-urlencode "offset=0" \
--data-urlencode "count=10"Response 200 (example):
{
"swaps": [
{
"l1TxId": "261f445e311b9ad5e0d127b3bd5567a468e54d214040e4933e43eb92a40113a5",
"fromToken": "BNB",
"feeBips": 15,
"timestamp": 1782379394000
},
{
"l1TxId": "2397ff0a4359a3e3bcce9bef5a1a6ff0556dd8a3b31e9b1de9b8306c20fd2934",
"fromToken": "USDT_BNB",
"feeBips": 15,
"timestamp": 1780045460000
},
{
"l1TxId": "4ce85e1e716c95861adc067e02bb4bc324925701aa1799b6ec3f3c4562c20466",
"fromToken": "BTC",
"feeBips": 40,
"timestamp": 1778521106000
}
],
"offset": 0,
"count": 10,
"hasMore": true
}Notes:
fromTokenis the source token of the swap (for exampleBNB,BTC,USDT_BNB,USDT_ETH).feeBipsis the affiliate fee for that swap in basis points (1 bp = 0.01%).timestampis the swap finalization time as a Unix epoch in milliseconds (not the time the swap was initiated).offset/countin the response echo the requested pagination.hasMore: truemeans another page is available; request the next page withoffset = offset + count.
Possible errors:
400 INVALID_ARGUMENT(invalidaffiliateIdformat,offset < 0, orcountoutside1..100)404 AFFILIATE_NOT_FOUND
6.7 Get swap info
- Method/Path:
GET /swaps/{l1TxId} - Purpose: returns consolidated swap fee info in a single response — total
acquired fees and swap kind — without a per-affiliate breakdown. Use
GET /getL1TxInfo(§ 6.8) when you need individual affiliate allocations.
Example to get swap info by L1 transaction id:
BASE_URL="https://api-affiliate.pactswap.io/api/v1"
L1TXID="0xaaaabbbbccccddddeeeeffff1111222233334444555566667777888899990000"
curl -sS "$BASE_URL/swaps/$L1TXID"Response 200 (normal case):
{
"kind": "normal",
"feesAcquiredUsdt": "245.100000",
"feeBips": 30
}Response 200 (reversed pact case):
{
"kind": "reversed_pact"
}Possible errors:
400 INVALID_ARGUMENT(invalidl1TxIdformat)404 SWAP_NOT_FOUND
6.8 Get L1 tx fee ledger info
- Method/Path:
GET /getL1TxInfo - Purpose: look up affiliate fee allocation for a completed L1 swap from the on-chain fee ledger (preferred for reconciliation).
Query params:
l1TxId(string, required) — L1 transaction id (with or without0xprefix)
Example:
BASE_URL="https://api-affiliate.pactswap.io/api/v1"
L1TXID="aaaabbbbccccddddeeeeffff1111222233334444555566667777888899990000"
curl -sS "$BASE_URL/getL1TxInfo" \
--get \
--data-urlencode "l1TxId=$L1TXID"Response 200 (example):
{
"l1TxId": "aaaabbbbccccddddeeeeffff1111222233334444555566667777888899990000",
"oracles": {
"l1TokenToUsd": { "rate": "350000000000", "decimals": 8 },
"usdtBnbToUsd": { "rate": "100000000", "decimals": 8 }
},
"affiliates": [
{
"affiliateId": "0x9a8b7c6d5e4f3210abcdeffedcba012345678901",
"basisPoints": 25,
"amountRaw": "612750000000000000",
"decimals": 18
}
]
}Notes:
oracles/affiliatesmay be omitted when the ledger claim has no such payload.amountRawis the affiliate fee share in virtual USDT (BNB) units atdecimalsprecision.
Possible errors:
400 INVALID_ARGUMENT(missingl1TxId)404 SWAP_NOT_FOUND500 INTERNAL_ERROR
6.9 Get swap quotes by send amount (quotes)
- Method/Path:
GET /pactswap_cm/getSwapQuotesByAmountFromonhttps://api.pactswap.io - Purpose: retrieve multiple swap quotes for a given
amountFrom(compare rates from different routes).
Query params:
from(string, required) — L2 C1 contract id for the source token.to(string, required) — L2 C2 contract id for the destination token.amountFrom(number, required) — amount in smallest units.fromType(string, optional) — source chain/type (for example,eth,btc,bnb).toType(string, optional) — destination chain/type.affiliates(array, optional) — affiliate fee recipients. In query strings use indexed fields, for exampleaffiliates[0][affiliateId]andaffiliates[0][bips]. Use youraffiliateIdfrom registration.slippageBips(number, optional) — slippage tolerance in basis points (1 bp = 0.01%, so100= 1%). Minimum50when provided. Quotes includeminAmountToderived from this.
Contract ids and presets are deployment-specific. Replace the placeholders below with values from your environment before calling production.
Example: request quotes to swap 1 ETH to BNB:
PACTSWAP_BASE_URL="https://api.pactswap.io"
# ETH (source): C1 base + destination C2 maker for BNB — replace with your deployment ids
FROM_C1="0x3f4031b087cb09891360a0b7aada49359eaabd09713979c190effc5b7ff928f6"
TO_C2="0x20ada6149b7480fc734c0ac2482d139e1febe1c5c01f9d7708b32ea986f691f7"
curl -sS -g "$PACTSWAP_BASE_URL/pactswap_cm/getSwapQuotesByAmountFrom" \
--get \
--data-urlencode "from=$FROM_C1" \
--data-urlencode "to=$TO_C2" \
--data-urlencode "fromType=eth" \
--data-urlencode "toType=bnb" \
--data-urlencode "amountFrom=1000000000000000000" \
--data-urlencode "slippageBips=100" \
--data-urlencode "affiliates[0][affiliateId]=0x9a8b7c6d5e4f3210abcdeffedcba012345678901" \
--data-urlencode "affiliates[0][bips]=25" \
--data-urlencode "affiliates[1][affiliateId]=0x5D3e2B7C9a1F4c8E0b6A7D2C1E9f3A4b8C6d0F12" \
--data-urlencode "affiliates[1][bips]=40"-g tells curl not to treat [ / ] in affiliates[0][...] as URL glob
characters.
Response 200 (example):
[
{
"amountTo": 50000000,
"minAmountTo": 49500000,
"route": "0xC0ffee254729296a45a3885639AC7E10F9d54979",
"lp": "0xC0ffee254729296a45a3885639AC7E10F9d54979",
"estimatedSwapTimeSeconds": 120
}
]Notes:
amountFromis always provided in the smallest units of the source token (for example, satoshis for BTC, wei for ETH/BNB/POL).- Example:
amountFrom=100for BTC means100 satoshis, not100 BTC. route/lp— liquidity provider identifier from the quote. Pass it to compose asrouteorlp.minAmountTo— lower bound on the destination amount implied by the quotedamountToand yourslippageBips(same smallest units asamountTo).estimatedSwapTimeSeconds— approximate expected swap duration in seconds (not a hard guarantee).
6.10 Compose swap transaction by send amount (compose)
- Method/Path:
GET /pactswap_cm/composeSwapTxByAmountFromonhttps://api.pactswap.io - Purpose: compose an unsigned L1 transaction based on
amountFrom. The affiliate/user must sign this transaction with their wallet, then broadcast it to the source chain.
Query params (required for EVM swaps):
fromType,toType(string)fromWalletAddress,toWalletAddress(string) — valid addresses for the respective chainsfromC1ContractId,fromC2ContractId,toC1ContractId,toC2ContractId(string) — L2 contract ids for source/destination tokensamountFrom(number)preset(number) — swap routing preset for the destination chain and address format (deployment-specific)routeorlp(string) — liquidity provider id from the quote response
Query params (optional):
affiliates(array) — same indexed query format as in § 6.9slippageBips(number, optional) — same meaning as for quotes (≥50when provided); see § 6.9
Query params (UTXO-based source chains only):
fromPublicKey(string, required for BTC/LTC/DOGE)utxos(string, required for BTC/LTC/DOGE) — JSON string with UTXOs
Example: compose an unsigned EVM transaction to swap 1 ETH to BNB (use route
from § 6.9):
PACTSWAP_BASE_URL="https://api.pactswap.io"
FROM_C1="0x3f4031b087cb09891360a0b7aada49359eaabd09713979c190effc5b7ff928f6"
FROM_C2="0xe2dcfe88387f5dbc8ec583727cf4280462ceb356be3199d320ed818089f8a693"
TO_C1="0x6f20d1802288c90d2a044d3f7afae73fda261b27d85c0e01fdaaf3199b2c0e85"
TO_C2="0x20ada6149b7480fc734c0ac2482d139e1febe1c5c01f9d7708b32ea986f691f7"
ROUTE="0xC0ffee254729296a45a3885639AC7E10F9d54979" # from quotes[].route or quotes[].lp
PRESET="9007199254740257" # deployment-specific; depends on toType + toWalletAddress format
curl -sS -g "$PACTSWAP_BASE_URL/pactswap_cm/composeSwapTxByAmountFrom" \
--get \
--data-urlencode "fromType=eth" \
--data-urlencode "toType=bnb" \
--data-urlencode "fromWalletAddress=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" \
--data-urlencode "toWalletAddress=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" \
--data-urlencode "amountFrom=1000000000000000000" \
--data-urlencode "fromC1ContractId=$FROM_C1" \
--data-urlencode "fromC2ContractId=$FROM_C2" \
--data-urlencode "toC1ContractId=$TO_C1" \
--data-urlencode "toC2ContractId=$TO_C2" \
--data-urlencode "preset=$PRESET" \
--data-urlencode "route=$ROUTE" \
--data-urlencode "slippageBips=100" \
--data-urlencode "affiliates[0][affiliateId]=0x9a8b7c6d5e4f3210abcdeffedcba012345678901" \
--data-urlencode "affiliates[0][bips]=25" \
--data-urlencode "affiliates[1][affiliateId]=0x5D3e2B7C9a1F4c8E0b6A7D2C1E9f3A4b8C6d0F12" \
--data-urlencode "affiliates[1][bips]=40"Response 200 (example):
{
"rawTx": "0x123..."
}Notes:
rawTxis an unsigned transaction payload returned by the API for client-side signing.- Signing and broadcasting are performed by the affiliate/user wallet flow (outside this API endpoint).
7) TypeScript interfaces for affiliate clients
export type AddressLike = string;
export type DecimalString = string;
export type WithdrawalToken =
| 'usdt_bnb'
| 'usdc_bnb'
| 'usdt_eth'
| 'usdc_eth'
| 'eth'
| 'btc';
export type WithdrawalMode = 'auto' | 'manual';
export interface RegisterAffiliateRequest {
evmWallet?: AddressLike;
btcWallet?: string;
/** Omit to keep legacy defaults: EVM-only → auto `usdt_bnb`; BTC present → manual. */
withdrawalMode?: WithdrawalMode;
/** Required when `withdrawalMode` is `auto`. */
token?: WithdrawalToken;
}
export interface RegisterAffiliateResponse {
affiliateId: AddressLike;
isActivated: boolean;
}
export interface GetAffiliateResponse {
affiliateId: AddressLike;
isActivated: boolean;
}
export interface GetFeeBalanceResponse {
balanceUsd: DecimalString;
}
export interface WithdrawFeesRequest {
token: WithdrawalToken;
}
export interface WithdrawFeesResponse {
recordId: string;
token: WithdrawalToken;
feesUsdVirtual: number;
l1Amount: string;
l1Address: string;
tokenDecimals: number;
orderEmbedId: string | null;
orderL2Txid: string | null;
}
export interface AffiliateWithdrawalItem {
id: string;
createdAt: string;
feesUsdVirtual: number;
token: WithdrawalToken | null;
l1Amount: string | null;
l1Address: string | null;
orderCweb: string;
orderEmbedId: string;
orderL2Txid: string;
orderId: string;
payoutL1TxId: string | null;
orderStatus: string | null;
activityStatus: string | null;
closedAt: string | null;
}
export interface ListAffiliateWithdrawalsResponse {
withdrawals: AffiliateWithdrawalItem[];
offset: number;
count: number;
hasMore: boolean;
}
export interface AffiliateSwapItem {
l1TxId: string;
fromToken: string;
feeBips: number;
timestamp: number; // swap finalization, Unix epoch ms
}
export interface ListAffiliateSwapsResponse {
swaps: AffiliateSwapItem[];
offset: number;
count: number;
hasMore: boolean;
}
export interface SwapInfoNormal {
kind: 'normal';
feesAcquiredUsdt: DecimalString;
feeBips: number;
}
export interface SwapInfoReversedPact {
kind: 'reversed_pact';
}
export type GetSwapInfoResponse = SwapInfoNormal | SwapInfoReversedPact;
export interface GetL1TxInfoResponse {
l1TxId: string;
oracles?: {
l1TokenToUsd: { rate: string; decimals: number };
usdtBnbToUsd: { rate: string; decimals: number };
};
affiliates?: {
affiliateId: string;
basisPoints: number;
amountRaw: string;
decimals: number;
}[];
}
export interface ApiErrorResponse {
error: {
code: string;
message: string;
details?: Record<string, unknown>;
};
}8) Integration flow (recommended)
- Call
POST /affiliateswithevmWallet,btcWallet, or both. OmitwithdrawalModefor the previous defaults, or setauto/manualexplicitly.
BASE_URL="https://api-affiliate.pactswap.io/api/v1"
curl -sS -X POST "$BASE_URL/affiliates" \
-H "Content-Type: application/json" \
-d '{
"evmWallet": "0x1234567890abcdef1234567890abcdef12345678",
"btcWallet": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"
}'- Store returned
affiliateIdas primary identifier for all next API calls. PollGET /affiliates/by-wallet/{wallet}(EVM or Bitcoin address) untilisActivatedistruebefore fee balance / withdrawal flows.
# Example of storing returned affiliateId for next requests
AFFILIATE_ID="0x9a8b7c6d5e4f3210abcdeffedcba012345678901"
EVM_WALLET="0x1234567890abcdef1234567890abcdef12345678"
curl -sS "$BASE_URL/affiliates/by-wallet/$EVM_WALLET"- For accounting UI, periodically call:
GET /affiliates/{affiliateId}/fee-balanceGET /affiliates/{affiliateId}/swaps(paginated swap history)GET /affiliates/{affiliateId}/withdrawals(paginated payout history)
curl -sS "$BASE_URL/affiliates/$AFFILIATE_ID/fee-balance"
curl -sS "$BASE_URL/affiliates/$AFFILIATE_ID/swaps" \
--get \
--data-urlencode "offset=0" \
--data-urlencode "count=10"
curl -sS "$BASE_URL/affiliates/$AFFILIATE_ID/withdrawals" \
--get \
--data-urlencode "offset=0" \
--data-urlencode "count=10"- Withdraw fees:
- Automatic mode (default for EVM-only, or explicit
withdrawalMode: "auto"): no action — withdrawal runs in the registeredtokenwhen the threshold is reached. - Manual mode (default when
btcWalletis sent, or explicitwithdrawalMode: "manual"): callPOST /affiliates/{affiliateId}/withdraw-feeswith atokenthat matches a registered wallet.
- Automatic mode (default for EVM-only, or explicit
curl -sS -X POST "$BASE_URL/affiliates/$AFFILIATE_ID/withdraw-fees" \
-H "Content-Type: application/json" \
-d '{"token":"usdt_bnb"}'- For swap audit/reconciliation:
- list attributed swaps via
GET /affiliates/{affiliateId}/swaps - prefer
GET /getL1TxInfo?l1TxId=...for eachl1TxId - optionally
GET /swaps/{l1TxId}
- list attributed swaps via
L1TXID="aaaabbbbccccddddeeeeffff1111222233334444555566667777888899990000"
curl -sS "$BASE_URL/getL1TxInfo" --get --data-urlencode "l1TxId=$L1TXID"- Get swap quotes on Pact Swap API (pick
route/lpfrom the response):GET https://api.pactswap.io/pactswap_cm/getSwapQuotesByAmountFrom- pass your
affiliateIdfrom step 2 inaffiliates; setslippageBipsforminAmountToon quotes
PACTSWAP_BASE_URL="https://api.pactswap.io"
FROM_C1="0x3f4031b087cb09891360a0b7aada49359eaabd09713979c190effc5b7ff928f6"
TO_C2="0x20ada6149b7480fc734c0ac2482d139e1febe1c5c01f9d7708b32ea986f691f7"
# `amountFrom` is in smallest units (wei/satoshi/etc), not whole coins.
curl -sS -g "$PACTSWAP_BASE_URL/pactswap_cm/getSwapQuotesByAmountFrom" \
--get \
--data-urlencode "from=$FROM_C1" \
--data-urlencode "to=$TO_C2" \
--data-urlencode "fromType=eth" \
--data-urlencode "toType=bnb" \
--data-urlencode "amountFrom=1000000000000000000" \
--data-urlencode "slippageBips=100" \
--data-urlencode "affiliates[0][affiliateId]=$AFFILIATE_ID" \
--data-urlencode "affiliates[0][bips]=25" \
--data-urlencode "affiliates[1][affiliateId]=0x5D3e2B7C9a1F4c8E0b6A7D2C1E9f3A4b8C6d0F12" \
--data-urlencode "affiliates[1][bips]=40"- Compose swap tx by selected route on Pact Swap API:
GET https://api.pactswap.io/pactswap_cm/composeSwapTxByAmountFrom- pass
route(orlp) from step 6, all four contract ids,preset,affiliates, andslippageBips(same values as step 6) - endpoint returns an unsigned tx payload; sign it in wallet flow and then broadcast
PACTSWAP_BASE_URL="https://api.pactswap.io"
FROM_C1="0x3f4031b087cb09891360a0b7aada49359eaabd09713979c190effc5b7ff928f6"
FROM_C2="0xe2dcfe88387f5dbc8ec583727cf4280462ceb356be3199d320ed818089f8a693"
TO_C1="0x6f20d1802288c90d2a044d3f7afae73fda261b27d85c0e01fdaaf3199b2c0e85"
TO_C2="0x20ada6149b7480fc734c0ac2482d139e1febe1c5c01f9d7708b32ea986f691f7"
ROUTE="0xC0ffee254729296a45a3885639AC7E10F9d54979"
PRESET="9007199254740257"
curl -sS -g "$PACTSWAP_BASE_URL/pactswap_cm/composeSwapTxByAmountFrom" \
--get \
--data-urlencode "fromType=eth" \
--data-urlencode "toType=bnb" \
--data-urlencode "fromWalletAddress=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" \
--data-urlencode "toWalletAddress=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" \
--data-urlencode "amountFrom=1000000000000000000" \
--data-urlencode "fromC1ContractId=$FROM_C1" \
--data-urlencode "fromC2ContractId=$FROM_C2" \
--data-urlencode "toC1ContractId=$TO_C1" \
--data-urlencode "toC2ContractId=$TO_C2" \
--data-urlencode "preset=$PRESET" \
--data-urlencode "route=$ROUTE" \
--data-urlencode "slippageBips=100" \
--data-urlencode "affiliates[0][affiliateId]=$AFFILIATE_ID" \
--data-urlencode "affiliates[0][bips]=25" \
--data-urlencode "affiliates[1][affiliateId]=0x5D3e2B7C9a1F4c8E0b6A7D2C1E9f3A4b8C6d0F12" \
--data-urlencode "affiliates[1][bips]=40"Operational recommendations:
- Treat
POST /affiliatesas idempotent by wallet on the client side (retry-safe logic). Re-registering an existing EVM or Bitcoin wallet returns409 AFFILIATE_ALREADY_EXISTS— resolve viaGET /affiliates/by-wallet/.... - Wait for
isActivated: truebefore withdrawal attempts. - Use exponential backoff for temporary
5xxfailures.
9) Operational guidance for affiliates
9.1 Idempotency and retries
- For
POST /affiliates, client should implement retry-safe behavior keyed by whichever wallets were sent (evmWallet,btcWallet, or both). - Recommended retry strategy for transient failures (
5xx, network timeout): exponential backoff with jitter.
9.2 Rate limits
- Default partner limit recommendation:
60 requests/minuteper IP. - If response is
429 RATE_LIMITED, retry after backoff. - Clients should cache stable lookup data (
affiliateIdresolution) to reduce request volume.
9.3 Timeouts and polling
- Recommended client timeout per request:
10s. - For operational dashboards, polling interval for balance/history:
15-60sdepending on UI needs. - After registration, poll activation status every
15-30suntilisActivatedbecomestrue(activation involves on-chain funding and may take up to a few minutes).
9.4 Withdrawal checklist
- Omit
withdrawalModeto keep the previous defaults, or set it explicitly.autoneeds atokenthat matches a wallet in the same request (btc↔btcWallet, every other token ↔evmWallet). - Automatic mode: monitor
fee-balance; payouts happen in the registered token above threshold. Track records viaGET /affiliates/{affiliateId}/withdrawals. - Manual mode: call
withdraw-feeswhen balance ≥ threshold.btcrequires a registeredbtcWallet; other tokens requireevmWallet. A mismatch returnsTOKEN_WALLET_MISMATCH. Automatic affiliates returnMANUAL_WITHDRAWAL_NOT_ALLOWED. - Handle
BELOW_THRESHOLDandAFFILIATE_NOT_ACTIVATEDexplicitly.
9.5 Production readiness checklist (partner side)
- Store
affiliateIdas primary partner key. - Persist and surface
isActivated. - Handle both swap variants:
normalandreversed_pact. - Prefer
GET /affiliates/{affiliateId}/swapsfor paginated swap history; page withoffset/countwhilehasMoreistrue. - Prefer
GET /affiliates/{affiliateId}/withdrawalsfor paginated payout history (fields may benulluntil the payout completes). - Prefer
getL1TxInfofor fee reconciliation on completed swaps. - Implement structured handling for documented error codes.
- Add observability for request id, latency, non-2xx responses, and retry attempts.
Was this documentation helpful? Any suggestions?