Pact Swap

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).
  • affiliateId is 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.
  • affiliateId is the primary identifier for all subsequent calls after registration.
  • After registration the affiliate is activated asynchronously (on-chain funding
    • fee-pool registration). Use isActivated from register/lookup responses before relying on fee balance or withdrawals.
  • Registration accepts a required evmWallet and an optional btcWallet.
  • Withdrawal modes:
    • EVM-only (no btcWallet): when fee balance reaches the configured threshold (default 100 USD), the system automatically withdraws to the evmWallet (default payout token: usdt_bnb).
    • With btcWallet: automatic withdrawal is disabled. Manual withdrawal becomes available once the fee balance reaches the configured threshold (default 100 USD). The partner calls POST /affiliates/{affiliateId}/withdraw-fees and chooses the payout token (usdt_bnb, usdc_bnb, usdt_eth, usdc_eth, eth, or btc). BTC payouts go to btcWallet; other tokens go to evmWallet.

2) Core terms

  • evmWallet: external EVM wallet provided by affiliate during registration (required). Used for non-BTC payouts.
  • btcWallet: optional Bitcoin payout address provided at registration (mainnet: legacy 1…/3… or Bech32 bc1q…/bc1p…). Enables manual multi-token withdrawal and BTC payouts.
  • 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 2xx status codes.
  • Error responses use 4xx/5xx status 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=100 for BTC means 100 satoshis, not 100 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_ARGUMENT
  • AFFILIATE_ALREADY_EXISTS
  • AFFILIATE_NOT_FOUND
  • AFFILIATE_NOT_ACTIVATED
  • MANUAL_WITHDRAWAL_NOT_ALLOWED
  • BELOW_THRESHOLD
  • SWAP_NOT_FOUND
  • RATE_LIMITED
  • INTERNAL_ERROR

6) REST endpoints

6.1 Register affiliate

  • Method/Path: POST /affiliates
  • Purpose: register new affiliate by evmWallet (and optional btcWallet) and generate affiliateId. Activation starts asynchronously; new affiliates return isActivated: false.

Request body:

{
  "evmWallet": "0x1234567890abcdef1234567890abcdef12345678",
  "btcWallet": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"
}

btcWallet is optional. Omit it for EVM-only affiliates (auto-withdrawal).

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 evmWallet / btcWallet format)
  • 409 AFFILIATE_ALREADY_EXISTS (EVM or BTC wallet already registered)

6.2 Get affiliate by wallet

  • Method/Path: GET /affiliates/by-wallet/{evmWallet}
  • Purpose: resolve existing affiliateId (and activation status) by source EVM wallet.

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 (invalid affiliateId format)
  • 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 with a btcWallet. Affiliate must be activated and fee balance must be at or above the withdrawal threshold.

Request body:

{
  "token": "btc"
}

Supported token values:

tokenPayout chainDestination wallet
usdt_bnbBNBevmWallet
usdc_bnbBNBevmWallet
usdt_ethETHevmWallet
usdc_ethETHevmWallet
ethETHevmWallet
btcBTCbtcWallet

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:

  • l1Amount is in the payout token’s smallest units (derived from fee USD notional and current token USD price).
  • orderEmbedId / orderL2Txid identify the on-chain payout order created by the service.

Possible errors:

  • 400 INVALID_ARGUMENT (invalid affiliateId / token)
  • 400 MANUAL_WITHDRAWAL_NOT_ALLOWED (affiliate has no btcWallet; use auto-withdrawal instead)
  • 400 BELOW_THRESHOLD (details includes balanceUsd and thresholdUsd)
  • 404 AFFILIATE_NOT_FOUND
  • 422 AFFILIATE_NOT_ACTIVATED
  • 500 INTERNAL_ERROR

6.5 List affiliate swaps

  • Method/Path: GET /affiliates/{affiliateId}/swaps
  • Purpose: paginated list of swaps attributed to the affiliate. Use each l1TxId with GET /swaps/{l1TxId} (§ 6.6) or GET /getL1TxInfo (§ 6.7) when you need fee amounts or ledger allocations.

Query params:

  • offset (number, optional, default 0) — number of items to skip. Must be ≥ 0.
  • count (number, optional, default 10) — page size. Must be 1..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:

  • fromToken is the source token of the swap (for example BNB, BTC, USDT_BNB, USDT_ETH).
  • feeBips is the affiliate fee for that swap in basis points (1 bp = 0.01%).
  • timestamp is the swap finalization time as a Unix epoch in milliseconds (not the time the swap was initiated).
  • offset / count in the response echo the requested pagination.
  • hasMore: true means another page is available; request the next page with offset = offset + count.

Possible errors:

  • 400 INVALID_ARGUMENT (invalid affiliateId format, offset < 0, or count outside 1..100)
  • 404 AFFILIATE_NOT_FOUND

6.6 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.7) 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 (invalid l1TxId format)
  • 404 SWAP_NOT_FOUND

6.7 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 without 0x prefix)

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 / affiliates may be omitted when the ledger claim has no such payload.
  • amountRaw is the affiliate fee share in virtual USDT (BNB) units at decimals precision.

Possible errors:

  • 400 INVALID_ARGUMENT (missing l1TxId)
  • 404 SWAP_NOT_FOUND
  • 500 INTERNAL_ERROR

6.8 Get swap quotes by send amount (quotes)

  • Method/Path: GET /pactswap_cm/getSwapQuotesByAmountFrom on https://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 example affiliates[0][affiliateId] and affiliates[0][bips]. Use your affiliateId from registration.
  • slippageBips (number, optional) — slippage tolerance in basis points (1 bp = 0.01%, so 100 = 1%). Minimum 50 when provided. Quotes include minAmountTo derived 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:

  • amountFrom is always provided in the smallest units of the source token (for example, satoshis for BTC, wei for ETH/BNB/POL).
  • Example: amountFrom=100 for BTC means 100 satoshis, not 100 BTC.
  • route / lp — liquidity provider identifier from the quote. Pass it to compose as route or lp.
  • minAmountTo — lower bound on the destination amount implied by the quoted amountTo and your slippageBips (same smallest units as amountTo).
  • estimatedSwapTimeSeconds — approximate expected swap duration in seconds (not a hard guarantee).

6.9 Compose swap transaction by send amount (compose)

  • Method/Path: GET /pactswap_cm/composeSwapTxByAmountFrom on https://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 chains
  • fromC1ContractId, fromC2ContractId, toC1ContractId, toC2ContractId (string) — L2 contract ids for source/destination tokens
  • amountFrom (number)
  • preset (number) — swap routing preset for the destination chain and address format (deployment-specific)
  • route or lp (string) — liquidity provider id from the quote response

Query params (optional):

  • affiliates (array) — same indexed query format as in § 6.8
  • slippageBips (number, optional) — same meaning as for quotes (≥ 50 when provided); see § 6.8

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

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:

  • rawTx is 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 interface RegisterAffiliateRequest {
  evmWallet: AddressLike;
  btcWallet?: string;
}

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 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>;
  };
}
  1. Call POST /affiliates with partner evmWallet (and optional btcWallet if you need manual / BTC withdrawals).
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"
  }'
  1. Store returned affiliateId as primary identifier for all next API calls. Poll GET /affiliates/by-wallet/{evmWallet} until isActivated is true before 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"
  1. For accounting UI, periodically call:
    • GET /affiliates/{affiliateId}/fee-balance
    • GET /affiliates/{affiliateId}/swaps (paginated swap 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"
  1. Withdraw fees:
    • EVM-only affiliates: no action — auto-withdrawal runs when the threshold is reached.
    • Affiliates with btcWallet: call POST /affiliates/{affiliateId}/withdraw-fees with the desired token.
curl -sS -X POST "$BASE_URL/affiliates/$AFFILIATE_ID/withdraw-fees" \
  -H "Content-Type: application/json" \
  -d '{"token":"usdt_bnb"}'
  1. For swap audit/reconciliation:
    • list attributed swaps via GET /affiliates/{affiliateId}/swaps
    • prefer GET /getL1TxInfo?l1TxId=... for each l1TxId
    • optionally GET /swaps/{l1TxId}
L1TXID="aaaabbbbccccddddeeeeffff1111222233334444555566667777888899990000"

curl -sS "$BASE_URL/getL1TxInfo" --get --data-urlencode "l1TxId=$L1TXID"
  1. Get swap quotes on Pact Swap API (pick route / lp from the response):
    • GET https://api.pactswap.io/pactswap_cm/getSwapQuotesByAmountFrom
    • pass your affiliateId from step 2 in affiliates; set slippageBips for minAmountTo on 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"
  1. Compose swap tx by selected route on Pact Swap API:
    • GET https://api.pactswap.io/pactswap_cm/composeSwapTxByAmountFrom
    • pass route (or lp) from step 6, all four contract ids, preset, affiliates, and slippageBips (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 /affiliates as idempotent by evmWallet on client side (retry-safe logic). Note: re-registering an existing wallet returns 409 AFFILIATE_ALREADY_EXISTS — resolve via GET /affiliates/by-wallet/....
  • Wait for isActivated: true before withdrawal attempts.
  • Use exponential backoff for temporary 5xx failures.

9) Operational guidance for affiliates

9.1 Idempotency and retries

  • For POST /affiliates, client should implement retry-safe behavior keyed by evmWallet (and btcWallet when provided).
  • Recommended retry strategy for transient failures (5xx, network timeout): exponential backoff with jitter.

9.2 Rate limits

  • Default partner limit recommendation: 60 requests/minute per IP.
  • If response is 429 RATE_LIMITED, retry after backoff.
  • Clients should cache stable lookup data (affiliateId resolution) to reduce request volume.

9.3 Timeouts and polling

  • Recommended client timeout per request: 10s.
  • For operational dashboards, polling interval for balance/history: 15-60s depending on UI needs.
  • After registration, poll activation status every 15-30s until isActivated becomes true (activation involves on-chain funding and may take up to a few minutes).

9.4 Withdrawal checklist

  • Decide at registration whether you need BTC / multi-token payouts (btcWallet) or automatic EVM payouts (omit btcWallet).
  • EVM-only: monitor fee-balance; payouts happen automatically above threshold.
  • With btcWallet: call withdraw-fees when balance ≥ threshold; choose token carefully (btc requires a registered btcWallet).
  • Handle BELOW_THRESHOLD and AFFILIATE_NOT_ACTIVATED explicitly.

9.5 Production readiness checklist (partner side)

  • Store affiliateId as primary partner key.
  • Persist and surface isActivated.
  • Handle both swap variants: normal and reversed_pact.
  • Prefer GET /affiliates/{affiliateId}/swaps for paginated swap history; page with offset/count while hasMore is true.
  • Prefer getL1TxInfo for 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?