BAZAAR API
Meta-DEX Aggregator API for cross-chain swap quotes and execution.
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.
curl -H "X-API-Key: bzr_pro_your_key_here" \ https://bazaar-web.onrender.com/events/market?...
API Key Tiers
| Tier | Rate Limit | SSE Conn | Prefix |
|---|---|---|---|
| No key | 120/min | 5 | — |
| Pro | 300/min | 10 | bzr_pro_ |
| Partner | 600/min | 20 | bzr_partner_ |
| Enterprise | 1000/min | 50 | bzr_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
X-RateLimit-Limit: 600 X-RateLimit-Remaining: 599 X-RateLimit-Reset: 1704931200
Exceeded Limit Response
// HTTP 429, with a Retry-After header (seconds)
{
"error": "Too many requests",
"retryAfter": 30
}Endpoints
Health Check
Returns service health status.
{
"status": "healthy",
"timestamp": "2026-01-10T19:23:26.377Z"
}List Chains
Returns all supported blockchain networks.
{
"chains": [
{
"chainId": "1",
"chainName": "Ethereum",
"chainType": "evm",
"nativeCurrency": {
"name": "Ether",
"symbol": "ETH",
"decimals": 18
}
}
]
}List Tokens
Returns supported tokens, optionally filtered by chain.
| Parameter | Type | Required | Description |
|---|---|---|---|
| chainId | string | No | Filter tokens by chain ID |
{
"tokens": [
{
"chainId": "1",
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"symbol": "USDC",
"name": "USD Coin",
"decimals": 6,
"logoURI": "https://..."
}
]
}Get Quotes (SSE)
Stream real-time swap quotes from multiple aggregators.
| Parameter | Type | Required | Description |
|---|---|---|---|
| fromChain | string | Yes | Source chain ID ("1", "TON", ...) |
| toChain | string | Yes | Destination chain ID |
| fromToken | string | Yes | Source token address |
| toToken | string | Yes | Destination token address |
| amount | string | Yes | Amount in the token's smallest unit |
| userAddress | string | Yes | User wallet address |
| slippage | string | No | Percent. Default: "1" (1%) |
| recipientAddress | string | No | Destination wallet, if different |
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
| Event | Payload | Description |
|---|---|---|
| quote | Quote 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
{
"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
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.
// 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
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.
// Request — quoteId or tracking is required
{
"quoteId": "abc123",
"tracking": "eyJ...",
"txHash": "0x9f2c..."
}
// Response
{
"ok": true
}Transaction Status
Poll the cross-chain status of a registered transaction. Returns 404 with status not_found until the hash is registered.
{
"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
Returns aggregate counts of supported chains and tokens.
Error Handling
{
"error": "Invalid request"
}| Code | Description |
|---|---|
| 200 | Success |
| 400 | Invalid request parameters |
| 401 | API key required (debug endpoints) |
| 403 | Quote does not belong to this address |
| 404 | Resource not found or expired |
| 429 | Rate limit exceeded |
| 500 | Server error |
Security
All responses include strict security headers:
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
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
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
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | 2026-09-20 | Transaction 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.0 | 2026-01-10 | Initial release with SSE quotes, execute endpoint |