Version: 1.1 · Effective: 2026-09-25 · Applies to: https://yield.trdefi.com/api/ and https://yield.trdefi.com/v1/
The endpoint reference, the response schemas, the integration flow, and — the part that matters most to an integrator — the write path: how a client turns an intent into a position without ever giving us a key.
Whatever else is in this document, these three hold:
1 · Reading is free and needs no key. Every GET /api/* endpoint is open to anyone. Browse the catalogue, price a trade, pull stats, embed a badge — no signup, no key, no account.
2 · To trade you present one of two credentials. To initiate a trade — to create a position or swap through the API — you either present an API key, issued after a short review (request one here), or pay per request with x402 — no account, no key to hold (Part 4.6). Either credential only prepares; neither can sign.
3 · We never hold, move or sign with a client's funds. The write path is prepare-only: the API returns a transaction that the client's own wallet signs. No endpoint accepts a private key, a seed phrase or a signing grant. There is nothing of ours to compromise, because we never hold anything.
4 · The protocol fee is inside the position, not on top of it. Creating a position through TRDEFI — the web app or the API alike — embeds a 0.05 % protocol fee in the order the maker signs. It is written into the signed order data, executed on-chain, and cannot be removed by the integrator, by us after the fact, or by anyone else. Positions created before this rule was in force are unaffected: their terms are immutable on-chain.
Part 4 specifies the write path. Part 7 states the fee in full.
These twelve properties are identical for every client. They are the contract. Nothing here is negotiable per client, because the moment one client's contract differs from the base, the base stops being a contract.
| # | Property | Value |
|---|---|---|
| 1 | Credentials | Read surface: none. Write path: an API key held server-side, or an x402 payment (pay-per-request, no key). Both only prepare — neither can sign. |
| 2 | Request id | X-Request-Id on every response, echoed in the body |
| 3 | Versioning | Path-versioned resources; OpenAPI 3.1 as the contract |
| 4 | Errors | { error: { code, message, requestId, retryable, documentation } } — always |
| 5 | Preflight | A result union that says whether the client must approve, is short of balance, or can proceed |
| 6 | Idempotency | Idempotency-Key on every write; 24 h retention; documented 5xx rule |
| 7 | Rate limits | RateLimit-* on success and failure; Retry-After on every 429 |
| 8 | Webhooks | Signed, retried, deduplicated, reorg-aware, with a simulate endpoint |
| 9 | Values | Amounts as strings in base units with explicit decimals; ISO-8601 UTC timestamps |
| 10 | Freshness | Every derived value states its age |
| 11 | Caching | Cache-Control always sent; meta.cached always honest |
| 12 | Deprecation | Public calendar, 90-day minimum notice, replacement before removal |
GET /api/statsCatalogue totals plus per-chain and top-pair roll-ups.
curl -s https://yield.trdefi.com/api/stats
{
"data": {
"source": "open liquidity strategies (normalized by TRDEFI)",
"totals": {
"strategies": <int>, "makers": <int>, "pairs": <int>, "chains": <int>,
"volume_1d_usd": <number>, "volume_7d_usd": <number>, "volume_30d_usd": <number>,
"last_activity": "<ISO-8601 timestamp>",
"rollup_updated_at": "<ISO-8601 timestamp>"
},
"chains": [ { "chain": "Ethereum", "count": 3426, "volume_30d_usd": 203020000, "last_activity": "…" } ],
"top_pairs_by_volume": [ { "pair": "USDC/USDT", "chain": "Ethereum", "count": 104, "maker_count": 87, "volume_30d_usd": 135300000, "logo_a": "…", "logo_b": "…" } ],
"top_pairs_by_positions": [ ]
},
"meta": { "requestId": "…", "generatedAt": "…", "apiVersion": "v1", "freshnessSeconds": 10800, "cached": false }
}
Bucket: stats (120/60 s) · Cache: 60 s
GET /api/chainsThe live set of chains. Treat as a catalog — never hardcode.
{ "chains": [ { "chain": "Ethereum", "count": 3426 } ], "requestId": "…" }
Bucket: chains (60/60 s)
GET /api/strategiesOpen liquidity positions.
| Parameter | Type | Notes |
|---|---|---|
resource | enum | list (default), chains, stats, detail, search |
pair | string | Exact pair, e.g. USDC/EURC |
chain | string | Chain key, e.g. base |
q | string | Free-text search (with resource=search) |
quote_ready | boolean | true narrows to the strategies /api/quote can simulate — USDC/USDT attached to the TRDEFI router |
Bucket: strategies (20/60 s)
GET /api/strategy-detail?hash=<strategyHash>One position in detail. Bucket: strategy-detail (60/60 s)
GET /api/quote?hash=<strategyHash>&chain=<chain>&amount=<baseUnits>An indicative quote for one strategy. Nothing is signed; nothing moves. A signable order is produced only by the write path, and is still signed by the client (Part 4).
Coverage is real but partial, and we say which is which. The quote is simulated on-chain against the strategy as it stands right now. Makers may gate a strategy on the caller holding an access licence token, and about half of sampled strategies in the catalogue do — strongly split by network: BNB Chain quotes cleanly, while Ethereum and Base sit almost entirely behind this gate. With no from the simulation runs as address(0) and a gated strategy answers a clear UNPROCESSABLE (the strategy is gated) rather than a simulated price; a caller that holds the licence token passes its own address as from and gets a live quote.
Which strategies can quote at all. Only USDC/USDT strategies attached to the TRDEFI router can be simulated; anything else answers UNPROCESSABLE with the reason, and a strategy whose order data is missing or unreadable answers UNPROCESSABLE too. The catalogue marks the router-attached USDC/USDT rows quote_eligible: true, and GET /api/strategies?quote_ready=true returns only those — pick a hash there before calling quote, so a UNPROCESSABLE is read as coverage, not as a broken request.
| Parameter | Type | Notes |
|---|---|---|
hash | string | Required. Strategy hash, 64 hex characters. |
chain | string | Chain key. Defaults to ethereum. |
amount | string | Required. Amount in token base units, as a string. |
direction | enum | aToB (default) or bToA. |
from | address | Optional. Your own address, used as msg.sender for the on-chain simulation. Pass the address that will sign so a maker-gated strategy can be priced against the licence token it holds; without it the call runs as address(0) and a gated strategy answers UNPROCESSABLE. |
Bucket: quote (60/60 s)
GET /api/badge?metric=<name>A shields.io endpoint payload for a repository README.
https://img.shields.io/endpoint?url=https%3A%2F%2Fyield.trdefi.com%2Fapi%2Fbadge%3Fmetric%3Dvolume30
Metrics: volume30 volume7 volume1 strategies makers pairs chains. Bucket: badge (120/60 s)
A client integration has five steps. Steps 1–3 need no credential at all. Step 5 is where a bespoke requirement belongs.
1. Discover GET /api/chains, GET /api/stats
→ learn what is live, do not hardcode
2. Read GET /api/strategies?chain=&pair= · GET /api/strategy-detail?hash=
→ list the positions, or inspect one
3. Price GET /api/quote?hash=&chain=&amount=
→ indicative only; never treat as a signed commitment
4. Prepare POST /v1/positions [API key, or an x402 payment]
→ returns UNSIGNED transactions + the fee breakdown
5. Configure (Enterprise) policy sets, approval groups, event subscriptions,
pre-signing hook → your custom revision, as data — see Part 6
A worked read integration:
# 1 · what is live
curl -s https://yield.trdefi.com/api/chains | jq '.chains[0]'
# 2 · the top pairs by settled volume
curl -s https://yield.trdefi.com/api/stats | jq '.data.top_pairs_by_volume[0:3]'
# 3 · an indicative quote
curl -s "https://yield.trdefi.com/api/quote?hash=<strategyHash>&chain=ethereum&amount=1000000" | jq
# 4 · how old is what I just read?
curl -s https://yield.trdefi.com/api/stats | jq '.meta.freshnessSeconds'
This is the part that makes the API non-custodial in the strict sense. The API never signs. It returns transactions that the client's own wallet signs, from the client's own address. There is no delegated signing, no signing grant, and no moment at which a credential of ours can move value.
One route, two credentials. Both POST /v1/positions and POST /v1/swaps accept either an API key (Authorization: Bearer trd_live_<keyId>_<secret>, §4.1–4.5) or an x402 payment — the same call, paid per request, with no account and no key to hold (§4.6). The key path is described first because it is the one an integrator holds long-term; the x402 path is what lets an agent that has no account with us use the route at all.
client server TRDEFI API client's wallet
───────────── ─────────── ───────────────
1 POST /v1/positions ───────────► authenticate the key
Authorization: Bearer <key> validate the intent
Idempotency-Key: <uuid> embed the 0.05 % protocol fee
{ chain, wallet, read live allowance + balance
deposits:[{symbol,amount}×2], build UNSIGNED tx 1..n
makerFeeBps } (approve ×0-2, ship)
◄──── 200 { transactions[],
fee, strategyHash,
preflight }
2 (nothing has happened yet)
3 sign each tx locally ──────► user / HSM / multisig
(we are not involved)
4 broadcast ───────────────────────────────────────────────────► chain
Step 1 is the only call that needs a key. It is a computation of what must be signed, and it hands the result back. It cannot execute anything, and there is no code path in it that touches a private key.
POST /v1/positions — prepare a positioncurl -s -X POST https://yield.trdefi.com/v1/positions \
-H "Authorization: Bearer trd_live_<keyId>_<secret>" \
-H "Idempotency-Key: 8f14e45f-ea2b-4c1a-9b3e-1d2c3b4a5f60" \
-H "Content-Type: application/json" \
-d '{
"chain": "arc",
"wallet": "0xYourOwnWalletThatWillSign",
"deposits": [
{ "symbol": "USDC", "amount": "1000000" },
{ "symbol": "EURC", "amount": "900000" }
],
"makerFeeBps": 30000,
"checkBalances": true
}'
| Field | Type | Notes |
|---|---|---|
chain | enum | Required. base (8453), arc (5042) or baseSepolia (84532). |
wallet | address | Required. The address that will sign. It must be yours. |
deposits | array | Required. Exactly two { symbol, amount } entries. amount is in base units, as an integer string. |
makerFeeBps | integer | Your own commission, in the 1e7 scale (30000 = 0.30 %). 0–2000000. Default 0. |
includeApprovals | boolean | Default true. Set false to get only the ship step. |
checkBalances | boolean | Default false. Adds live balance checks to preflight. |
Two things are deliberately not parameters:
position.impliedRate is reported for your own sanity check, not used.{
"data": {
"status": "prepared",
"chain": "arc",
"chainId": 5042,
"wallet": "0xYourOwnWalletThatWillSign",
"strategyHash": "0x9f71222e…",
"transactions": [
{
"step": 1,
"purpose": "approve",
"to": "0x3600000000000000000000000000000000000000",
"value": "0",
"data": "0x095ea7b3…",
"description": "Approve the position registry to move USDC. This is a bounded allowance you can revoke at any time — it is not a transfer, and the funds stay in your wallet."
},
{
"step": 2,
"purpose": "ship",
"to": "0x1111113ccf1426a8e30e2bff5e005d929bf6a90a",
"value": "0",
"data": "0xf50b870f…",
"description": "Create the USDC/EURC position on Arc. Funds stay in your wallet; the position is backed by the allowance you just signed."
}
],
"fee": {
"protocolFeeBps": 5000,
"protocolFeePercent": "0.05",
"makerFeeBps": 30000,
"makerFeePercent": "0.30",
"totalFeePercent": "0.35",
"embeddedIn": "signed_order_data",
"removable": false,
"explanation": "The 0.05% protocol fee is written into the order you sign. It is executed on-chain by the position itself and cannot be removed — not by you, not by us."
},
"position": {
"tokenA": { "symbol": "USDC", "address": "0x3600…0000", "amount": "1000000", "decimals": 6 },
"tokenB": { "symbol": "EURC", "address": "0xbef5…21c1", "amount": "900000", "decimals": 6 },
"impliedRate": 1.1111111111111112,
"programBytes": 223
},
"preflight": {
"status": "ready",
"checks": [
{ "name": "wallet_valid", "ok": true },
{ "name": "tokens_sorted", "ok": true },
{ "name": "both_amounts_positive", "ok": true },
{ "name": "fees_wiring", "ok": true },
{ "name": "balance_a", "ok": true, "detail": "USDC" },
{ "name": "balance_b", "ok": true, "detail": "EURC" }
]
},
"idempotent": true
},
"meta": {
"requestId": "d2f7201ef219bb3a52228bb813ba779c",
"apiVersion": "v1",
"preparedAt": "<ISO-8601 timestamp>",
"note": "Nothing has been signed or broadcast. Sign each transaction in `transactions` with your own wallet, in order, then broadcast."
}
}
Rules that apply to every POST /v1/positions:
transactions[] is ordered. Execute in the order given. The approve steps come first and are omitted when your live allowance already covers the amount — we read it from the chain before answering. The last step is always the operation itself.fee is informational and non-negotiable. It reports what is already embedded in the unsigned order data. There is no parameter that removes it, and no tier on which it is waived.strategyHash is the identity of the position. It is the keccak256 of the order you are about to sign, so you can compute it yourself from the returned data and check that what you sign is what we built.(your key, Idempotency-Key). The same key therefore returns the same strategyHash, so a retried request cannot create a second position. Omit the header and every call is a new position.preflight.status is ready, or review when one of its checks failed. It exists so you can tell a human "this will not go through" before asking them to approve — not after.GET /v1/positions/<strategyHash> — track itThe strategyHash returned by POST /v1/positions is the position's id. Use it to find out whether your own transaction landed — you do not have to poll an RPC to know.
curl -s https://yield.trdefi.com/v1/positions/0x9f71222e57269fd7525375aca3c66c13c7f27137eb052e4bf1e3dc8f9a284b08 \
-H "Authorization: Bearer $TRDEFI_KEY"
{ "data": {
"positionId": "0x9f7122…",
"status": "filled",
"chain": "arc", "chainId": 5042,
"wallet": "0xYourOwnWalletThatWillSign",
"tokenA": { "symbol": "USDC", "address": "0x3600…0000", "amount": "1000000" },
"tokenB": { "symbol": "EURC", "address": "0xbef5…21c1", "amount": "900000" },
"makerFeeBps": 30000, "protocolFeeBps": 5000,
"observedOnChain": true, "volumeUsd": 22013772.64,
"preparedAt": "…", "firstSeenOnChainAt": "…", "firstSeenFilledAt": "…",
"signer": "client — we never signed or broadcast anything" },
"meta": { "requestId": "…", "checkedAt": "…",
"timestampsMeaning": "…when TRDEFI first OBSERVED each state, not when it actually happened." } }
| Status | Meaning — and only what we have observed |
|---|---|
prepared | We returned unsigned transactions and have observed nothing on-chain yet. |
shipped | The position exists in the live catalogue — so your wallet signed, broadcast and it was included. |
filled | It has settled volume. |
Two deliberate omissions, both stated rather than papered over:
signed state. A signature is not observable until the transaction is broadcast, and by then it is shipped. Reporting a signed state would mean claiming knowledge we do not have.failed state. We watch the catalogue, not every reverted transaction. If your transaction reverts, your own receipt — not this endpoint — is the authority.firstSeenOnChainAt and firstSeenFilledAt are named for what they are: when we observed the state, which is not necessarily when it happened. Your transaction receipt carries the true time.
A key can only ever see positions it prepared itself. Another organisation's position id, and an id that does not exist, both return 404 — deliberately indistinguishable.
| With a write key | Possible? |
|---|---|
| Read the public catalogue | Yes (no key needed, but a key also works) |
| Prepare unsigned transactions | Yes |
| See the live allowance and balance of the wallet you name | Yes |
| Track a position you prepared | Yes — and only yours |
| Sign anything | Never |
| Broadcast on your behalf | Never |
| Move, withdraw or transfer value | Never |
| Spend outside the allowance you signed | Never |
Act on any wallet other than one you name as wallet | Never |
| See another organisation's keys, positions or activity | Never |
POST /v1/swaps — prepare a swapWhere the protocol earns. A taker swaps against a maker position that is already shipped; the 0.05 % protocol fee rides inside the maker's order, so every swap that executes pays it without anything extra being asked of the taker. Prepare-only, exactly like POST /v1/positions.
curl -s -X POST https://yield.trdefi.com/v1/swaps \
-H "Authorization: Bearer trd_live_<keyId>_<secret>" \
-H "Content-Type: application/json" \
-d '{
"chain": "ethereum",
"wallet": "0xYourOwnWalletThatWillSign",
"strategyHash": "0x5928c6b6c24c08615ddde8b832e6f4b135550601e2bb903dba4123c1b8ff8f2c",
"amount": "1000000"
}'
{ "data": {
"status": "prepared",
"pair": "USDC/USDT",
"tokenIn": "0xa0b86991…", "tokenOut": "0xdac17f95…", "amountIn": "1000000",
"expected": { "amountIn": "1000000", "amountOut": "999774", "orderHash": "0x5928c6b6…", "mode": "simulated" },
"allowance": "0",
"transactions": [
{ "step": 1, "purpose": "approve", "to": "0xa0b86991…", "value": "0", "data": "0x095ea7b3…" },
{ "step": 2, "purpose": "swap", "to": "0x11111133…", "value": "0", "data": "0xf4d2d412…" }
],
"fee": { "protocolFeePercent": "0.05", "embeddedIn": "signed_order_data", "paidBy": "the maker position, from the swap proceeds", "removable": false }
} }
approve step appears only if the live allowance is short, so the same request is sometimes one transaction and sometimes two.expected.amountOut is a simulation at the current block, not a promise. If you need protection against it moving before you sign, put your own threshold in the transaction data.A caller that holds no API key can still use the write path by paying for the request with x402. Nothing else changes: the response is the same prepare-only payload, the client's own wallet still signs, and we still never hold a key.
Why this route and not the reads. Our revenue is the 0.05 % collected on-chain when a position trades, not a per-call fee, so paywalling the reads would only reduce the odds an agent uses us. The prepare path is the opposite: it is the one capability that does something rather than describing it, and the one that needed a credential. Charging for it removes the credential friction instead of adding one.
The challenge. Call POST /v1/positions (or POST /v1/swaps) with no credential at all and the route answers 402 Payment Required:
{
"x402Version": 2,
"error": "Payment required",
"resource": { "url": "https://yield.trdefi.com/v1/positions", "mimeType": "application/json" },
"accepts": [
{ "scheme": "exact", "network": "eip155:8453", "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"payTo": "0x4C96dA02d7120BFb81594d0e924B237e0c74660d", "amount": "20000", "maxAmountRequired": "20000",
"resource": "https://yield.trdefi.com/v1/positions", "maxTimeoutSeconds": 3600,
"extra": { "name": "USD Coin", "version": "2" } },
{ "scheme": "exact", "network": "eip155:5042", "asset": "0x3600000000000000000000000000000000000000",
"payTo": "0x4C96dA02d7120BFb81594d0e924B237e0c74660d", "amount": "20000", "maxAmountRequired": "20000",
"resource": "https://yield.trdefi.com/v1/positions", "maxTimeoutSeconds": 3600,
"extra": { "name": "USDC", "version": "2" } }
],
"extensions": { "bazaar": { "…": "route discovery metadata" } }
}
PAYMENT-REQUIRED response header (base64 of the JSON) — x402 v2 clients read the header.0x8335…, CAIP-2 eip155:8453, settled by Coinbase's CDP facilitator) and Arc (USDC 0x3600…, eip155:5042, settled by our own facilitator).X402_PRICE_USD. It is a fee for the request, separate from and additional to the 0.05 % protocol fee embedded in the position.amount is atomic USDC (6 decimals): 20000 = 0.02 USDC. extra.name is the token's EIP-712 domain name, which a client must use to sign the authorization ("USD Coin" on Base, "USDC" on Arc).Paying. The client signs an x402 authorization with its own wallet and retries the same call with the encoded payment in a PAYMENT-SIGNATURE header (the x402 v2 name; the deprecated v1 X-PAYMENT is still accepted). The facilitator verifies and settles it, and the route proceeds exactly as the key path does. A successful paid prepare carries the settlement in its meta:
{ "data": { "status": "prepared", "…": "…" },
"meta": { "requestId": "…", "apiVersion": "v1", "preparedAt": "…",
"payment": { "settled": true, "transaction": "0x…", "network": "eip155:5042" } } }
Two rules a buyer should know:
402 PAYMENT_INVALID with the reason — it does not return a fresh challenge, because doing so would invite a double payment. A 402 challenge (with accepts) means "no credential yet, here are the terms"; PAYMENT_INVALID means "the payment you sent was refused".keyId, so it is not readable through the key-scoped GET /v1/positions/<hash> (§4.3). The strategyHash is still returned in the prepare response, and the position is still visible in the public catalogue once shipped.Discovery. The 402 — specifically the bazaar extension and the PAYMENT-REQUIRED header — is what makes both routes discoverable to x402 agents: the Coinbase Bazaar indexes a route only once it answers 402 with that metadata and has settled at least one real payment. POST /v1/positions and POST /v1/swaps are listed there.
Every resource accepts a bounded free-form metadata map (no secrets). A client's cost centre, desk id or accounting tag travels with our objects and returns in webhooks and exports.
/api/chains and the asset catalog are live by default. A tenant may pin the exact set it tested against, for stability, and unpin later. Opt-in, never the default.
This is the part that matters most to a client with a requirement we have never seen. It describes the Enterprise tier.
Principle: the base is fixed; a client's differences are data. A client-specific revision is a configuration object plus, at most, the client's own endpoint. It is never a code change on our side, never a bespoke response shape, and never a client-only endpoint.
POST /v1/permissions
{
"rules": [
{ "effect": "allow", "action": "prepare", "chain": "base", "pair": "USDC/EURC",
"maxAmount": "25000", "window": "1d", "enforced": "service" },
{ "effect": "deny", "action": "prepare", "chain": "arbitrum", "enforced": "service" }
],
"approvalGroups": [ { "when": { "amountOver": "100000" }, "require": ["role:treasury_lead"] } ]
}
Ordered. Explicit deny wins. An amount scope that distinguishes a single transaction from a windowed total. Approval groups. And — the field that matters — enforced: every rule states where it is enforced, so the client can draw its own trust boundary without asking us. On this tier the enforcement point is service (we refuse to prepare) and, for anything that must bind the position itself, onchain (the allowance that the client's own wallet signed).
{ "profile": "transfer_restricted",
"actions": { "prepare": {"allow": true}, "transfer_out": {"allow": false, "reason": "requires_whitelisted_destination"} } }
Presets: open, transfer_restricted, redemption_only, freeze_only. A client may define its own without touching us.
{ "subscriptions": [
{ "events": ["position.shipped","position.filled","position.failed"], "url": "…", "signingKeyId": "…" },
{ "events": ["risk.ltv_changed"], "url": "…", "thresholdPct": "80" } ] }
Per-subscription URLs let a client route to different internal systems. Adding an event is the cheapest custom revision available, and it is the only thing a client should ever pin a product to.
The strongest extension point. Before we return a prepared transaction, we call the client's endpoint with the exact intent. The client returns allow or deny.
POST <client_url> { "intent": { … }, "tenant": "…", "requestId": "…" }
← 200 { "allow": true } or { "allow": false, "reason": "over my internal limit" }
This is how a client applies a rule we have never heard of — its own risk model, its own treasury policy, its own approval matrix — without us shipping a feature. Their logic, our preparation, their signature.
One rule, for everyone. A position created through TRDEFI — through the web app or through the API — carries a 0.05 % protocol fee, written into the order data the maker signs.
| Rate | 0.05 % of the traded amount |
| Where it lives | Inside the signed order data of the position. It is not a separate transfer and not an invoice. |
| Who is charged | Everyone who creates a new position. There is no tier, no volume threshold and no integration path that avoids it. |
| What the integrator controls | Their own makerFeeBps (their commission). The 0.05 % is on top and is not theirs to set. |
| Removable? | No. Not by the integrator, not by us, not after the fact. The fee is executed by the position itself when it trades. |
| Existing positions | Unaffected. Terms are immutable on-chain; positions created before this rule keep their original terms. |
| Reading data | Free, always. The fee applies to creating positions, never to reading. |
The fee is disclosed three times before anything is signed: in POST /v1/positions (the fee object), in the web app before the confirmation step, and in this document. An integrator that resells access must pass the fee through — it is part of the position, not a cost we absorb.
| Tier | Status | Read surface | Write path | Rate limits | Support |
|---|---|---|---|---|---|
| Open | Live | All read endpoints, no key | — | As advertised on each reply | |
| Integrator | Live (after review) | Same | POST /v1/positions and POST /v1/swaps — prepare-only, key held server-side, origin-restricted — or the same routes paid per request with x402, no key | Raised buckets per key, agreed | Email, named contact |
| Enterprise | Roadmap | Same | Same + policy sets, approval groups, pre-preparation hook, event subscriptions | Dedicated buckets | Named contact, agreed SLO |
Open and Integrator are live today. Enterprise describes the shape we are building towards. Where a capability is not yet available it is labelled above rather than implied.
Tier differences are limits, support and write-path features — never response shape. A client on any tier can be confident that the payload it parses today is the payload it parses tomorrow.
# 1 · discover the live set
curl -s https://yield.trdefi.com/api/chains | jq '.chains | length'
# 2 · headline numbers
curl -s https://yield.trdefi.com/api/stats \
| jq '{strategies: .data.totals.strategies, vol30: .data.totals.volume_30d_usd, fresh: .meta.freshnessSeconds}'
# 3 · the three deepest pairs
curl -s https://yield.trdefi.com/api/stats | jq '.data.top_pairs_by_positions[0:3]'
# 4 · inspect one position
curl -s "https://yield.trdefi.com/api/strategy-detail?hash=<hash>" | jq
# 5 · price an intended trade (indicative)
curl -s "https://yield.trdefi.com/api/quote?hash=<strategyHash>&chain=ethereum&amount=1000000" | jq '.rate'
# 6 · prepare a real position (needs a key)
curl -s -X POST https://yield.trdefi.com/v1/positions \
-H "Authorization: Bearer $TRDEFI_KEY" -H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"chain":"arc","wallet":"0x…","checkBalances":true,
"deposits":[{"symbol":"USDC","amount":"1000000"},{"symbol":"EURC","amount":"900000"}]}' \
| jq '.data.fee, (.data.transactions[] | {step, purpose, to})'
# → sign each transaction with your own wallet, in order, then broadcast
# 7 · read your own quota before a burst
curl -sD - -o /dev/null https://yield.trdefi.com/api/stats | grep -i '^ratelimit'
| Element | Where |
|---|---|
| OpenAPI 3.1 | https://yield.trdefi.com/openapi.json |
| Markdown twin of the docs | https://yield.trdefi.com/docs/api.md |
| Agent index | https://yield.trdefi.com/llms.txt |
| Request an API key | https://yield.trdefi.com/docs/api#access |
| x402 payment (write path, no key) | POST https://yield.trdefi.com/v1/positions — answers 402 with the terms |
| MCP server (keyless read tools for agents) | https://yield.trdefi.com/mcp |
| Error code table | https://yield.trdefi.com/docs/api#errors |
| Rate limits | https://yield.trdefi.com/docs/api#rate-limits |
| Method of Statement | https://yield.trdefi.com/docs/method-of-statement |
| General Rules | https://yield.trdefi.com/docs/general-rules |
TRDEFI Ltd, London, United Kingdom. See also: Method of Statement, General Rules.