Skip to main contentSkip to FAQSkip to contact

All TetraFi API requests require authentication via Bearer token. This page covers API key management, environments, rate limits, error handling, and pagination.

30-second proof of life. Set your API key and hit the status endpoint. If you get 200 OK you're authenticated and ready to make real requests:

Bash
1export TETRAFI_API_KEY=sk_test_...
2curl -H "Authorization: Bearer $TETRAFI_API_KEY" https://sandbox.tetrafi.io/v1/status
3# { "ok": true, "environment": "sandbox", "version": "v1" }
3 linesbash

TetraFi uses two types of API keys:

TypePrefixEnvironmentReal Funds
Sandboxsk_test_Testing & developmentNo
Productionsk_live_Live tradingYes

Both key types work identically - sandbox never touches real funds and compliance checks are mocked. Generate keys from the TetraFi dashboard.

Never expose API keys in client-side code. Store them in environment variables and use server-side requests only. Key rotation: generate a new key, update your config, the old key expires in 24 hours.

Include your API key in the Authorization header. Optionally include your compliance attestation:

TypeScript
1const response = await fetch("https://api.tetrafi.io/v1/rfq", {
2 method: "POST",
3 headers: {
4 "Authorization": "Bearer sk_live_...",
5 "Content-Type": "application/json",
6 // Optional: compliance attestation hash
7 "X-TetraFi-Attestation": "0x...",
8 },
9 body: JSON.stringify({
10 pair: "USDC/USDT",
11 side: "buy",
12 amount: "1000000",
13 }),
14});
15
16const data = await response.json();
16 linestypescript
SandboxProduction
Base URLhttps://sandbox.tetrafi.io/v1https://api.tetrafi.io/v1
WebSocketwss://sandbox.tetrafi.io/v1/wswss://api.tetrafi.io/v1/ws
API Key Prefixsk_test_sk_live_
Real FundsNoYes
Rate LimitsSameSame
ComplianceMockedReal
SettlementSimulatedOn-chain
Bash
1# .env.local - sandbox
2TETRAFI_API_KEY=sk_test_...
3TETRAFI_BASE_URL=https://sandbox.tetrafi.io/v1
4
5# .env.production
6TETRAFI_API_KEY=sk_live_...
7TETRAFI_BASE_URL=https://api.tetrafi.io/v1
7 linesbash

Rate limits are enforced per API key across all endpoints:

TierRequests/minBurst/secWebSocket Connections
Free60101
Growth600505
Enterprise6,00020025

Every response includes current rate limit information:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed per window
X-RateLimit-RemainingRemaining requests in current window
X-RateLimit-ResetUTC epoch when the window resets
Retry-AfterSeconds to wait (on 429 responses only)
TypeScript
1async function requestWithBackoff<T>(
2 fn: () => Promise<T>,
3 maxRetries = 5
4): Promise<T> {
5 for (let attempt = 0; attempt <= maxRetries; attempt++) {
6 try {
7 return await fn();
8 } catch (e) {
9 if (e instanceof RateLimitError && attempt < maxRetries) {
10 const wait = e.retryAfter ?? Math.min(30, 2 ** attempt);
11 console.log(`Rate limited - waiting {wait}s (attempt {attempt + 1})`);
12 await sleep(wait * 1000);
13 } else {
14 throw e;
15 }
16 }
17 }
18 throw new Error("Max retries exceeded");
19}
19 linestypescript

All errors follow a consistent machine-readable format:

JSON
1{
2 "error": {
3 "type": "invalid_request",
4 "code": "pair_not_supported",
5 "message": "The trading pair DOGE/SHIB is not supported.",
6 "param": "pair",
7 "doc_url": "https://tetrafi.io/docs/errors#pair_not_supported"
8 }
9}
9 linesjson
StatusTypeDescription
400invalid_requestMalformed request, missing required param
401authentication_errorInvalid or expired API key
403compliance_errorParticipant not compliant to trade
404not_foundResource (RFQ, quote, settlement) not found
409conflictDuplicate request (idempotency violation)
422validation_errorParam values are valid types but fail business rules
429rate_limit_errorToo many requests - use Retry-After header
500api_errorInternal server error - retry with backoff
503maintenanceScheduled maintenance - check status page
CodeMeaning
pair_not_supportedThe pair isn't available on the requested corridor
amount_too_smallBelow minimum trade size ($10,000 USD equivalent)
amount_too_largeExceeds maximum trade size for your tier
attestation_expiredCompliance attestation needs renewal
corridor_unavailableNo solvers covering the requested corridor
rfq_expiredQuote window has passed - create a new RFQ

For POST requests that create resources, include an Idempotency-Key header to safely retry failed requests:

TypeScript
1const response = await fetch("https://api.tetrafi.io/v1/rfq", {
2 method: "POST",
3 headers: {
4 "Authorization": "Bearer sk_live_...",
5 "Content-Type": "application/json",
6 // Unique per request - same key = same response (for 24h)
7 "Idempotency-Key": crypto.randomUUID(),
8 },
9 body: JSON.stringify({ pair: "USDC/USDT", side: "buy", amount: "1000000" }),
10});
10 linestypescript

Long lists (quotes, audit entries, settlements) use cursor-based pagination:

TypeScript
1// First page
2const response = await fetch("https://api.tetrafi.io/v1/settlements?limit=25", {
3 headers: { "Authorization": "Bearer sk_live_..." },
4});
5const { data, has_more, next_cursor } = await response.json();
6
7// Next page
8if (has_more) {
9 const next = await fetch(
10 `https://api.tetrafi.io/v1/settlements?limit=25&after=${next_cursor}`,
11 { headers: { "Authorization": "Bearer sk_live_..." } }
12 );
13}
13 linestypescript
ParameterTypeDescription
limitnumberNumber of results per page. Max 100, default 25.
afterstringCursor from previous response's next_cursor. Fetches next page.
beforestringFetch the previous page (reverse pagination).

Response shape:

JSON
1{
2 "data": [...],
3 "has_more": true,
4 "next_cursor": "cursor_abc123",
5 "total_count": 1247
6}
6 linesjson