REST API Reference#
Base URL: https://api.tetrafi.io/api/v1 Stable
Auth tier is tagged in each endpoint description: Public (no auth) · Optional Auth (API key toggles behavior) · Required (JWT or API key). See Authentication for the full map.
Looking for single-endpoint deep-links? Every operation also has a dedicated auto-generated page under /docs/integration/api, sourced directly from the OpenAPI spec so it never drifts from the live schema.
Endpoint Index
| Method | Returns | Since | Status |
|---|---|---|---|
| GET /api/v1/health | 200 / 503 | - | Public |
| POST /api/v1/quotes | 200 | - | Public |
| GET /api/v1/quotes/{quoteId} | 200 | - | Public |
| POST /api/v1/orders | 201 | - | Optional |
| GET /api/v1/orders/{orderId} | 200 | - | Public |
| GET /api/v1/workspaces/.../settlements/... | 200 | - | Required |
| GET /api/v1/corridors | 200 | - | Public |
| POST /api/v1/solvers/register | 201 | - | Required |
| POST /api/v1/webhooks | 201 | - | Required |
Health#
GET /api/v1/health#
1{2 "ok": true,3 "environment": "sandbox",4 "version": "v1",5 "uptimeSeconds": 4829146}Mock mode - submit returns the first 2xx example with a 500ms delay. No network request is made.
Quotes#
POST /api/v1/quotes#
Content-Typeapplication/jsonrequiredRequest body formatinputTokenaddressrequiredERC-20 contract address on the origin chain.outputTokenaddressrequiredERC-20 contract address on the destination chain.inputAmountstringrequiredAmount in the input token's smallest unit (e.g. USDC 6 decimals).originChainIdnumberrequiredEVM chain id of the source chain.destinationChainIdnumberrequiredEVM chain id of the destination chain.preferenceenumSolver selection bias.values:pricespeedreliabilityswapTypeenumAmount-side semantics.values:exactInputexactOutput
Raw example
1{2 "inputToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",3 "outputToken": "0xdAC17F958D2ee523a2206206994597C13D831ec7",4 "inputAmount": "1000000000000",5 "originChainId": 8453,6 "destinationChainId": 10,7 "preference": "price",8 "swapType": "exactInput"9}quotesarrayrequiredCompeting quotes ranked best-first.quoteIdstringrequiredStable opaque quote identifier.solverIdstringrequiredSolver that produced the quote.outputAmountstringrequiredOutput amount in destination-token smallest units.feeBpsnumberrequiredEffective fee in basis points (includes gas).priceImpactBpsnumberPrice impact vs mid-market, in bps.expiresAtstringrequiredISO-8601 quote expiry.settlementPathenumrequiredWhich settlement rail this quote uses.values:compliantdirectlockTypeenumrequiredOn-chain lock mechanism.values:ResourceLockPermit2EscrowEIP3009Escrow
uccpBpsnumberrequiredUniform Clearing Competitive Price in bps.corridorstringrequiredCanonical corridor id.requestIdstringrequiredServer-generated id for tracing.
1{2 "quotes": [3 {4 "quoteId": "qt_01HXYZABCDEF",5 "solverId": "slv_acme",6 "outputAmount": "999725000000",7 "feeBps": 2.75,8 "priceImpactBps": 0.4,9 "expiresAt": "2026-04-16T18:42:11Z",10 "settlementPath": "compliant",11 "lockType": "ResourceLock"12 },13 {14 "quoteId": "qt_01HXYZGHIJKL",15 "solverId": "slv_bravo",16 "outputAmount": "999680000000",17 "feeBps": 3.2,18 "priceImpactBps": 0.6,19 "expiresAt": "2026-04-16T18:42:11Z",20 "settlementPath": "compliant",21 "lockType": "Permit2Escrow"22 }23 ],24 "uccpBps": 2.75,25 "corridor": "base:usdc-optimism:usdt",26 "requestId": "req_01HXYZMNOPQR"27}Mock mode - submit returns the first 2xx example with a 500ms delay. No network request is made.
GET /api/v1/quotes/{quoteId}#
1{2 "quoteId": "qt_01HXYZABCDEF",3 "status": "open",4 "solverId": "slv_acme",5 "outputAmount": "999725000000",6 "feeBps": 2.75,7 "settlementPath": "compliant",8 "lockType": "ResourceLock",9 "standardOrder": {10 "user": "0x0000000000000000000000000000000000000000",11 "originChainId": 8453,12 "expires": 1734375600,13 "fillDeadline": 1734372000,14 "inputs": [15 [16 "0xA0b8...eB48",17 "1000000000000"18 ]19 ],20 "outputs": [21 {22 "chainId": 10,23 "token": "0xdAC1...1ec7",24 "amount": "999725000000"25 }26 ]27 },28 "createdAt": "2026-04-16T18:40:11Z",29 "expiresAt": "2026-04-16T18:42:11Z"30}Orders#
POST /api/v1/orders#
quoteIdstringrequiredQuote id returned from POST /api/v1/quotes.signaturebytesrequiredEIP-712 signature over the StandardOrder typed data.noncenumberrequiredMonotonic per-user nonce that prevents replay.
Raw example
1{2 "quoteId": "qt_01HXYZABCDEF",3 "signature": "0x4e7bf3a1...c2b9",4 "nonce": 15}orderIdstringrequiredStable opaque order identifier.quoteIdstringrequiredSource quote id.statusenumrequiredCurrent settlement state.values:DepositedFilledAttestedClaimedRefundedsettlementPathenumrequiredDirect or compliant rail.values:directcompliantoriginTxHashstringrequiredOrigin-chain deposit transaction hash.destinationTxHashstringDestination-chain fill tx hash (null until filled).createdAtstringrequiredISO-8601 creation timestamp.fillDeadlinestringrequiredISO-8601 by which the solver must fill.
1{2 "orderId": "ord_01HXYZSTUVWX",3 "quoteId": "qt_01HXYZABCDEF",4 "status": "Deposited",5 "settlementPath": "compliant",6 "originTxHash": "0xab12...cd34",7 "destinationTxHash": null,8 "createdAt": "2026-04-16T18:41:02Z",9 "fillDeadline": "2026-04-16T18:51:02Z"10}Mock mode - submit returns the first 2xx example with a 500ms delay. No network request is made.
GET /api/v1/orders/{orderId}#
1{2 "orderId": "ord_01HXYZSTUVWX",3 "status": "Claimed",4 "settlementPath": "compliant",5 "originChainId": 8453,6 "destinationChainId": 10,7 "inputAmount": "1000000000000",8 "outputAmount": "999725000000",9 "originTxHash": "0xab12...cd34",10 "destinationTxHash": "0xef56...gh78",11 "oracleAttestationHash": "0x9a8b...7c6d",12 "settledAt": "2026-04-16T18:43:47Z"13}Settlements#
GET /api/v1/workspaces/{workspaceId}/settlements/{orderId}#
orderIdstringrequiredOrder id tied to this settlement.workspaceIdstringrequiredWorkspace owning the order.stateenumrequiredTerminal or intermediate settlement state.values:DepositedFilledAttestedSettledRefundedtimelinearrayrequiredChronological stage events for audit.stageenumrequiredStage marker.values:rfqdepositedfilledattestedclaimedrefundedatstringrequiredISO-8601 stage timestamp.txHashstringOn-chain tx hash (if the stage produced one).oracleHashstringOracle attestation hash (attested stage only).
evidenceHashbytesrequiredRoot of the WORM audit evidence chain.wormSequencenumberrequiredSequence number within the WORM ledger.
1{2 "orderId": "ord_01HXYZSTUVWX",3 "workspaceId": "ws_acme",4 "state": "Settled",5 "timeline": [6 {7 "stage": "rfq",8 "at": "2026-04-16T18:40:11Z"9 },10 {11 "stage": "deposited",12 "at": "2026-04-16T18:41:02Z",13 "txHash": "0xab12...cd34"14 },15 {16 "stage": "filled",17 "at": "2026-04-16T18:42:30Z",18 "txHash": "0xef56...gh78"19 },20 {21 "stage": "attested",22 "at": "2026-04-16T18:43:18Z",23 "oracleHash": "0x9a8b...7c6d"24 },25 {26 "stage": "claimed",27 "at": "2026-04-16T18:43:47Z",28 "txHash": "0x1122...3344"29 }30 ],31 "evidenceHash": "0xabcd...ef01",32 "wormSequence": 847233}GET /api/v1/corridors#
1{2 "corridors": [3 {4 "id": "base:usdc-optimism:usdt",5 "originChainId": 8453,6 "destinationChainId": 10,7 "inputToken": {8 "address": "0xA0b8...eB48",9 "symbol": "USDC",10 "decimals": 611 },12 "outputToken": {13 "address": "0xdAC1...1ec7",14 "symbol": "USDT",15 "decimals": 616 },17 "solverCount": 7,18 "minNotional": "100000000000",19 "maxNotional": "10000000000000",20 "oracle": "Hyperlane",21 "lockTypes": [22 "ResourceLock",23 "Permit2Escrow"24 ]25 },26 {27 "id": "ethereum:usdc-arbitrum:usdc",28 "originChainId": 1,29 "destinationChainId": 42161,30 "inputToken": {31 "address": "0xA0b8...eB48",32 "symbol": "USDC",33 "decimals": 634 },35 "outputToken": {36 "address": "0xaf88...831",37 "symbol": "USDC",38 "decimals": 639 },40 "solverCount": 12,41 "minNotional": "100000000000",42 "maxNotional": "20000000000000",43 "oracle": "Hyperlane",44 "lockTypes": [45 "ResourceLock",46 "Permit2Escrow",47 "EIP3009Escrow"48 ]49 }50 ]51}Solvers#
POST /api/v1/solvers/register#
1{2 "name": "My Solver",3 "corridors": [4 "base:usdc-optimism:usdt"5 ],6 "callbackUrl": "https://solver.example.com/webhook"7}1{2 "solverId": "slv_01HXYZMNOPQR",3 "name": "My Solver",4 "corridors": [5 "base:usdc-optimism:usdt"6 ],7 "wsToken": "wst_live_abc123def456",8 "wsUrl": "wss://api.tetrafi.io/api/v1/ws",9 "createdAt": "2026-04-16T18:30:00Z"10}Webhooks#
POST /api/v1/webhooks#
1{2 "url": "https://your-server.com/webhooks/tetrafi",3 "events": [4 "order.created",5 "order.settled",6 "compliance.event"7 ],8 "secret": "whsec_..."9}1{2 "webhookId": "wh_01HXYZAAAAAA",3 "url": "https://your-server.com/webhooks/tetrafi",4 "events": [5 "order.created",6 "order.settled",7 "compliance.event"8 ],9 "signingKey": "whsec_live_abc123",10 "active": true,11 "createdAt": "2026-04-16T18:35:00Z"12}See Events & Webhooks for event types, WebSocket topics, and signature verification.
WebSocket API#
Connect to the WebSocket gateway for real-time events:
1wss://api.tetrafi.io/api/v1/ws?token=tfk_live_...Topic Subscription#
After connecting, subscribe to event topics:
1{ "type": "subscribe", "topics": ["orders:*"] }| Topic Pattern | Events |
|---|---|
orders:* | All order events for your workspace |
orders:{orderId} | Events for a specific order |
prices:{corridor} | Real-time price updates for a corridor |
Error Responses#
Single error object - machine-readable code + human-readable message:
1{2 "error": {3 "code": "INVALID_REQUEST",4 "message": "inputAmount must be a positive integer string"5 }6}HTTP Status → Error Category#
| Status | Typical code values | Action |
|---|---|---|
| 400 | INVALID_REQUEST, MISSING_FIELD | Inspect request body; do not retry unchanged |
| 401 | UNAUTHORIZED, INVALID_KEY | Check API key prefix matches environment |
| 403 | COMPLIANCE_FAILED, ATTESTATION_EXPIRED | Renew KYC/KYB or add attestation header |
| 404 | NOT_FOUND | Resource no longer exists or never existed |
| 409 | QUOTE_EXPIRED, ALREADY_ACCEPTED | Request new quote |
| 422 | VALIDATION_ERROR | Field types valid but business rule failed |
| 429 | RATE_LIMITED | Honor Retry-After header |
| 5xx | API_ERROR, MAINTENANCE | Retry with exponential backoff |
Error codes may evolve during beta. Build your integration to handle unknown error codes gracefully - log them and fall back to the HTTP status class. See the full Error Code Registry for every machine-readable code with deep-link anchors.