The @tetrafi/sdk package provides a typed, ergonomic interface for the TetraFi API. Stripe-inspired design: a single client instance with namespaced methods.
1npm install @tetrafi/sdk2# or3pnpm add @tetrafi/sdk4# or5yarn add @tetrafi/sdk1import { TetraFi } from "@tetrafi/sdk";23const tetrafi = new TetraFi({4 apiKey: process.env.TETRAFI_API_KEY!,5 environment: "sandbox", // "sandbox" | "production"6 timeout: 30000, // request timeout (ms), default 300007 retries: 3, // auto-retry on 5xx, default 38});| Parameter | Type | Description |
|---|---|---|
| apiKeyrequired | string | Your API key (sk_test_* for sandbox, sk_live_* for production) |
| environment | "sandbox" | "production" | API environment. Defaults to "production". |
| timeout | number | Request timeout in milliseconds. Defaults to 30000. |
| retries | number | Auto-retry count on 5xx errors. Defaults to 3. |
| baseUrl | string | Override the API base URL. Useful for proxies or local development. |
| logger | (msg: string) => void | Custom logging function. Defaults to console.log in development. |
Submit a new Request for Quote to competing solvers.
| Parameter | Type | Description |
|---|---|---|
| pairrequired | string | Trading pair in QUOTE/BASE format, e.g. "USDC/USDT" |
| siderequired | "buy" | "sell" | Trade direction from the taker's perspective |
| amountrequired | string | Trade size as a decimal string in source token units |
| corridor | string | Cross-chain path, e.g. "ethereum-optimism". Defaults to same-chain. |
| maxSlippage | number | Maximum acceptable slippage (0.001 = 0.1%). Defaults to 0.005. |
1const rfq = await tetrafi.rfq.create({2 pair: "USDC/USDT",3 side: "buy",4 amount: "1000000.00",5 corridor: "ethereum-optimism",6 maxSlippage: 0.001,7});Get competing quotes for an active RFQ.
1const quotes = await tetrafi.rfq.getQuotes("rfq_abc123");Automatically select and accept the best available quote.
1const settlement = await tetrafi.rfq.acceptBest("rfq_abc123");Accept a specific quote and trigger escrow creation.
1const settlement = await tetrafi.quotes.accept("qt_xyz789");Get the current status of a settlement.
1const settlement = await tetrafi.settlements.get("stl_abc123");Check whether an address has a valid compliance attestation.
1const status = await tetrafi.compliance.check("...");Fetch the WORM audit trail for a completed settlement.
1const entries = await tetrafi.audit.getTrail("stl_abc123");Subscribe to real-time events via WebSocket.
1const unsubscribe = tetrafi.events.on("settlement.complete", (event) => {2 console.log("Settled:", event.settlement.id);3});45// Later: stop receiving events6unsubscribe();| Parameter | Type | Description |
|---|---|---|
| typerequired | EventType | Event type to subscribe to. Use wildcards: "settlement.*" matches all settlement events. |
| callbackrequired | (event: Event) => void | Function called when a matching event arrives. |
1interface RFQ {2 id: string;3 pair: string;4 side: "buy" | "sell";5 amount: string;6 corridor: string;7 status: "pending" | "quoting" | "accepted" | "expired";8 createdAt: string; // ISO 86019 expiresAt: string; // ISO 860110}1112interface Quote {13 id: string;14 rfqId: string;15 solverId: string;16 price: string; // Decimal string, e.g. "0.9995"17 ttl: number; // Seconds until expiry18 confidence: number; // 0-1 fill confidence score19 createdAt: string;20}2122interface Settlement {23 id: string;24 rfqId: string;25 quoteId: string;26 status: "pending" | "escrow_locked" | "filling" | "complete" | "failed" | "refunded";27 originTxHash?: string;28 destinationTxHash?: string;29 amount: string;30 createdAt: string;31 settledAt?: string;32}3334interface ComplianceStatus {35 address: string;36 isCompliant: boolean;37 attestationHash: string;38 expiresAt: string;39}4041interface AuditEntry {42 tradeId: string;43 type: "rfq_created" | "quote_accepted" | "escrow_locked" | "settlement_complete";44 timestamp: string;45 data: Record<string, unknown>;46 hash: string; // WORM integrity hash47 prevHash: string; // Chain link to previous entry48}4950type EventType =51 | "rfq.created"52 | "quote.received"53 | "quote.accepted"54 | "settlement.pending"55 | "settlement.complete"56 | "settlement.failed"57 | "audit.recorded"58 | "rfq.*"59 | "settlement.*";1import { TetraFi } from "@tetrafi/sdk";23const tetrafi = new TetraFi({4 apiKey: process.env.TETRAFI_API_KEY!,5 environment: "sandbox",6});78async function executeSwap() {9 // 1. Create RFQ10 const rfq = await tetrafi.rfq.create({11 pair: "USDC/USDT",12 side: "buy",13 amount: "1000000.00",14 });15 console.log("RFQ created:", rfq.id);1617 // 2. Wait for quotes (poll)18 await new Promise((r) => setTimeout(r, 3000));19 const quotes = await tetrafi.rfq.getQuotes(rfq.id);20 console.log("Received quotes:", quotes.length);2122 if (quotes.length === 0) {23 throw new Error("No quotes received");24 }2526 // 3. Accept best price27 const settlement = await tetrafi.rfq.acceptBest(rfq.id);28 console.log("Settlement initiated:", settlement.id);2930 // 4. Monitor to completion31 let status = settlement;32 while (!["complete", "failed", "refunded"].includes(status.status)) {33 await new Promise((r) => setTimeout(r, 5000));34 status = await tetrafi.settlements.get(settlement.id);35 console.log("Status:", status.status);36 }3738 if (status.status === "complete") {39 console.log("Success!");40 console.log("Origin TX:", status.originTxHash);41 console.log("Destination TX:", status.destinationTxHash);42 } else {43 throw new Error(`Settlement failed: {status.status}`);44 }45}4647executeSwap().catch(console.error);1import { TetraFiError, RateLimitError, AuthError, ComplianceError } from "@tetrafi/sdk";23try {4 const rfq = await tetrafi.rfq.create({5 pair: "USDC/USDT",6 side: "buy",7 amount: "1000000",8 });9} catch (e) {10 if (e instanceof RateLimitError) {11 // Exponential backoff12 await sleep(e.retryAfter * 1000);13 // retry...14 } else if (e instanceof AuthError) {15 console.error("Invalid API key - check TETRAFI_API_KEY");16 } else if (e instanceof ComplianceError) {17 console.error("Compliance check failed - ensure attestation is current");18 } else if (e instanceof TetraFiError) {19 console.error("API error:", e.code, e.message);20 } else {21 throw e; // Unknown error - rethrow22 }23}For real-time updates, the SDK exposes a WebSocket event stream via tetrafi.events. The connection authenticates with your API key and supports wildcard channel subscriptions. Auto-reconnect is on by default.
1import { TetraFi } from "@tetrafi/sdk";23const tetrafi = new TetraFi({4 apiKey: process.env.TETRAFI_API_KEY!,5 environment: "sandbox",6});78// Connect (lazy - happens on first .on() call)9const unsubQuotes = tetrafi.events.on("quote.received", (event) => {10 console.log(`[Quote] {event.quote.solverId}: {event.quote.price}`);11});1213const unsubSettlement = tetrafi.events.on("settlement.*", (event) => {14 switch (event.type) {15 case "settlement.pending":16 console.log("Escrow locked:", event.settlement.id);17 break;18 case "settlement.complete":19 console.log("Complete!", event.settlement.originTxHash);20 break;21 case "settlement.failed":22 console.error("Failed:", event.settlement.error);23 break;24 }25});2627// Connection lifecycle hooks28tetrafi.events.on("connection.opened", () => console.log("WS connected"));29tetrafi.events.on("connection.closed", () => console.log("WS disconnected - auto-reconnecting"));30tetrafi.events.on("connection.error", (e) => console.error("WS error:", e));3132// Cleanup on shutdown33process.on("SIGTERM", () => {34 unsubQuotes();35 unsubSettlement();36 tetrafi.events.disconnect();37});Auto-reconnect: the SDK reconnects automatically on connection loss with exponential backoff (1s → 2s → 4s → 8s, capped at 30s). Active subscriptions are restored after each reconnect - your .on() callbacks keep firing without re-subscribing.
| Channel | When it fires |
|---|---|
rfq.created | Your RFQ has been broadcast to solvers |
quote.received | A solver returned a quote |
quote.accepted | You accepted a quote |
settlement.pending | Settlement initiated, escrow locking |
settlement.complete | Both legs settled atomically |
settlement.failed | Settlement reverted, refund issued |
audit.recorded | New WORM audit entry |
rfq.* | Wildcard - all RFQ events |
settlement.* | Wildcard - all settlement events |
Event Stream
Subscribe to real-time quote and settlement events.The @tetrafi/sdk package follows semver. Pin your dependency conservatively until you've confirmed compatibility in staging.
| Bump | Meaning | Action required |
|---|---|---|
1.0.x → 1.0.y | Patch - bug fixes, no API changes | Auto-update is safe |
1.0.x → 1.1.x | Minor - additive features, new methods | Read changelog, no migration |
1.x.x → 2.0.0 | Major - breaking changes | Read migration guide |
Deprecation policy. Methods scheduled for removal are marked with a @deprecated JSDoc tag for at least one minor version before removal. Your IDE will surface a strikethrough on the call site, and the SDK logs a one-time warning at runtime:
1[TetraFi] Warning: tetrafi.rfq.create({ slippage }) is deprecated. Use { maxSlippage } instead. This will be removed in 2.0.0.The full changelog lives at github.com/tetrafi/sdk-typescript/releases. Subscribe to the GitHub releases feed to be notified of new versions.
Pinning tip. For production deployments, pin to an exact version ("@tetrafi/sdk": "1.4.2") rather than a caret range ("^1.4.2"). This prevents an automatic minor update from changing behavior between deploys. Upgrade explicitly after reading the changelog.
Try the SDK directly in your browser:
How this works. Edit the code below and watch the output update live. The playground runs in a sandboxed iframe using a mock @tetrafi/sdk that returns realistic data with simulated latency - no real API calls are made. Try changing the amount, pair, or side to see how responses change.
Submit an RFQ
Create an RFQ, receive quotes, and accept the best price.