DOCS

BAZAAR API

Meta-DEX Aggregator API for cross-chain swap quotes and execution.

Base URL https://bazaar-web.onrender.com

Authentication

The API works without a key at reduced rate limits. An API key in the X-API-Key header unlocks higher limits and more concurrent SSE connections.

bash
curl -H "X-API-Key: bzr_pro_your_key_here" \
  https://bazaar-web.onrender.com/events/market?...

API Key Tiers

TierRate LimitSSE ConnPrefix
No key120/min5—
Pro300/min10bzr_pro_
Partner600/min20bzr_partner_
Enterprise1000/min50bzr_enterprise_

For now, API keys are distributed upon request.

Rate Limiting

Rate limits are enforced per API key, or per IP for unauthenticated requests (120/min, sliding 1-minute window).

Response Headers

http
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 599
X-RateLimit-Reset: 1704931200

Exceeded Limit Response

json
// HTTP 429, with a Retry-After header (seconds)
{
  "error": "Too many requests",
  "retryAfter": 30
}

Endpoints

Health Check

GET /health

Returns service health status.

json
{
  "status": "healthy",
  "timestamp": "2026-01-10T19:23:26.377Z"
}

List Chains

GET /chains

Returns all supported blockchain networks.

json
{
  "chains": [
    {
      "chainId": "1",
      "chainName": "Ethereum",
      "chainType": "evm",
      "nativeCurrency": {
        "name": "Ether",
        "symbol": "ETH",
        "decimals": 18
      }
    }
  ]
}

List Tokens

GET /tokens

Returns supported tokens, optionally filtered by chain.

ParameterTypeRequiredDescription
chainIdstringNoFilter tokens by chain ID
json
{
  "tokens": [
    {
      "chainId": "1",
      "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      "symbol": "USDC",
      "name": "USD Coin",
      "decimals": 6,
      "logoURI": "https://..."
    }
  ]
}

Get Quotes (SSE)

GET /events/market

Stream real-time swap quotes from multiple aggregators.

ParameterTypeRequiredDescription
fromChainstringYesSource chain ID ("1", "TON", ...)
toChainstringYesDestination chain ID
fromTokenstringYesSource token address
toTokenstringYesDestination token address
amountstringYesAmount in the token's smallest unit
userAddressstringYesUser wallet address
slippagestringNoPercent. Default: "1" (1%)
recipientAddressstringNoDestination wallet, if different
bash
curl -N -H "X-API-Key: bzr_pro_xxx" \
  "https://bazaar-web.onrender.com/events/market?\
fromChain=1&\
toChain=42161&\
fromToken=0xA0b...&\
toToken=0xFd0...&\
amount=1000000000&\
userAddress=0xd8d..."

Event Types

EventPayloadDescription
quoteQuote object (below)One per provider that found a route
adapter_result{ name, ok, reason? }One per provider per round; reason: no_route | timeout | error | circuit_open
done{ nextRaceMs }Round finished; the race re-runs after nextRaceMs on the same connection

Quote Event Data Model

json
{
  "quoteId": "abc123",
  "expiresAt": 1704931260000,
  "merchantName": "SquidRouter",
  "merchantLogo": "https://...",
  "fromChainId": 1,
  "toChainId": 42161,
  "fromToken": "0xA0b...",
  "toToken": "0xFd0...",
  "inAmount": "1000000000",
  "outAmount": "998500000",
  "netOutput": "996000000",
  "fees": {
    "gas": [{ "symbol": "ETH", "amount": "0.0012", "amountUSD": 2.50 }],
    "platform": [],
    "totalUSD": 2.50
  },
  "inAmountUSD": 1000.00,
  "outAmountUSD": 998.50,
  "estimatedArrivalSeconds": 120,
  "tx": {
    "to": "0x...",
    "data": "0x...",
    "value": "0"
  },
  "approvalAddress": "0x..."
}

inAmountUSD, outAmountUSD and approvalAddress are optional. When approvalAddress is absent, use tx.to as the spender. A quote with an empty tx.to is priced but not directly executable.

Execute Swap

POST /execute

Retrieves transaction data for executing a previously quoted swap. Quotes are bound to the userAddress that requested them; a mismatched address returns 403. Quotes expire ~60s after issuance and can only be executed once.

json
// Request
{
  "quoteId": "abc123",
  "userAddress": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
}

// Response
{
  "txData": {
    "to": "0x...",
    "data": "0x...",
    "value": "0",
    "gasLimit": "250000"
  },
  "quote": {
    "merchantName": "SquidRouter",
    "fromChainId": 1,
    "toChainId": 42161,
    "fromToken": "0xA0b...",
    "toToken": "0xFd0...",
    "inAmount": "1000000000",
    "outAmount": "998500000",
    "fees": { "gas": [], "platform": [], "totalUSD": 2.50 }
  },
  "tracking": "eyJ..."
}

Keep the tracking token — it is a signed, 24h-valid credential that lets you register the transaction for status tracking even after the quote expires.

Register Transaction

POST /status/register

Call once after your wallet broadcasts the transaction. Send either the quoteId or the tracking token from /execute (plus the tx hash) so status polling knows which provider to ask.

json
// Request — quoteId or tracking is required
{
  "quoteId": "abc123",
  "tracking": "eyJ...",
  "txHash": "0x9f2c..."
}

// Response
{
  "ok": true
}

Transaction Status

GET /status/:txHash

Poll the cross-chain status of a registered transaction. Returns 404 with status not_found until the hash is registered.

json
{
  "txHash": "0x9f2c...",
  "merchant": "SquidRouter",
  "status": "bridging",
  "srcTxHash": "0x9f2c...",
  "destTxHash": "0x71aa...",
  "srcExplorerUrl": "https://...",
  "destExplorerUrl": "https://...",
  "progressPercent": 60,
  "message": "Waiting for bridge",
  "updatedAt": 1704931260000
}

status is one of pending | submitted | bridging | complete | failed | not_found | untracked. Stop polling on complete, failed or untracked (the provider exposes no status API — check the explorer). All fields except txHash, merchant, status and updatedAt are optional.

Stats

GET /stats

Returns aggregate counts of supported chains and tokens.

Error Handling

json
{
  "error": "Invalid request"
}
CodeDescription
200Success
400Invalid request parameters
401API key required (debug endpoints)
403Quote does not belong to this address
404Resource not found or expired
429Rate limit exceeded
500Server error

Security

All responses include strict security headers:

http
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Content-Security-Policy: default-src 'self'
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=(), camera=()
Strict-Transport-Security: max-age=31536000; includeSubDomains

Code Examples

TypeScript / Node.js

typescript
const BASE_URL = 'https://bazaar-web.onrender.com';

const params = new URLSearchParams({
  fromChain: '1',
  toChain: '42161',
  fromToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  toToken: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
  amount: '1000000000',
  userAddress: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
});

// Works unauthenticated (120/min). The browser-native EventSource
// cannot send headers — to use an API key, connect from a backend
// with the 'eventsource' npm package:
//   new EventSource(url, { headers: { 'X-API-Key': 'bzr_pro_...' } })
const eventSource = new EventSource(
  `${BASE_URL}/events/market?${params}`
);

eventSource.addEventListener('quote', (event) => {
  const quote = JSON.parse(event.data);
  console.log('Received quote:', quote.merchantName, quote.netOutput);
});

eventSource.addEventListener('done', (event) => {
  const { nextRaceMs } = JSON.parse(event.data);
  console.log(`Round complete — next race in ${nextRaceMs}ms`);
});

Python

python
import requests
import sseclient

API_KEY = 'bzr_pro_your_key'
BASE_URL = 'https://bazaar-web.onrender.com'
headers = {'X-API-Key': API_KEY}

# Stream quotes
response = requests.get(
    f'{BASE_URL}/events/market',
    params={...},
    headers=headers,
    stream=True
)

client = sseclient.SSEClient(response)
for event in client.events():
    if event.event == 'quote':
        print(f'Quote: {event.data}')

Changelog

VersionDateChanges
1.0.02026-09-20Transaction status tracking (/status/register, /status/:txHash); /execute returns a signed tracking token and requires userAddress; adapter_result and done SSE events; unauthenticated tier (120/min)
1.0.02026-01-10Initial release with SSE quotes, execute endpoint