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.


Part 0 · The three things that never change

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.

Part 1 · The frozen base

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.

#PropertyValue
1CredentialsRead 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.
2Request idX-Request-Id on every response, echoed in the body
3VersioningPath-versioned resources; OpenAPI 3.1 as the contract
4Errors{ error: { code, message, requestId, retryable, documentation } } — always
5PreflightA result union that says whether the client must approve, is short of balance, or can proceed
6IdempotencyIdempotency-Key on every write; 24 h retention; documented 5xx rule
7Rate limitsRateLimit-* on success and failure; Retry-After on every 429
8WebhooksSigned, retried, deduplicated, reorg-aware, with a simulate endpoint
9ValuesAmounts as strings in base units with explicit decimals; ISO-8601 UTC timestamps
10FreshnessEvery derived value states its age
11CachingCache-Control always sent; meta.cached always honest
12DeprecationPublic calendar, 90-day minimum notice, replacement before removal

Part 2 · Endpoint reference — the read surface

2.1 GET /api/stats

Catalogue 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

2.2 GET /api/chains

The live set of chains. Treat as a catalog — never hardcode.

{ "chains": [ { "chain": "Ethereum", "count": 3426 } ], "requestId": "…" }

Bucket: chains (60/60 s)

2.3 GET /api/strategies

Open liquidity positions.

ParameterTypeNotes
resourceenumlist (default), chains, stats, detail, search
pairstringExact pair, e.g. USDC/EURC
chainstringChain key, e.g. base
qstringFree-text search (with resource=search)
quote_readybooleantrue narrows to the strategies /api/quote can simulate — USDC/USDT attached to the TRDEFI router

Bucket: strategies (20/60 s)

2.4 GET /api/strategy-detail?hash=<strategyHash>

One position in detail. Bucket: strategy-detail (60/60 s)

2.5 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.

ParameterTypeNotes
hashstringRequired. Strategy hash, 64 hex characters.
chainstringChain key. Defaults to ethereum.
amountstringRequired. Amount in token base units, as a string.
directionenumaToB (default) or bToA.
fromaddressOptional. 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)

2.6 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)

Part 3 · Integration flow

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'

Part 4 · The write path — prepare-only

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.

4.1 The flow, end to end

 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.

4.2 POST /v1/positions — prepare a position

curl -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
      }'
FieldTypeNotes
chainenumRequired. base (8453), arc (5042) or baseSepolia (84532).
walletaddressRequired. The address that will sign. It must be yours.
depositsarrayRequired. Exactly two { symbol, amount } entries. amount is in base units, as an integer string.
makerFeeBpsintegerYour own commission, in the 1e7 scale (30000 = 0.30 %). 0–2000000. Default 0.
includeApprovalsbooleanDefault true. Set false to get only the ship step.
checkBalancesbooleanDefault false. Adds live balance checks to preflight.

Two things are deliberately not parameters:

{
  "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:

4.3 GET /v1/positions/<strategyHash> — track it

The 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." } }
StatusMeaning — and only what we have observed
preparedWe returned unsigned transactions and have observed nothing on-chain yet.
shippedThe position exists in the live catalogue — so your wallet signed, broadcast and it was included.
filledIt has settled volume.

Two deliberate omissions, both stated rather than papered over:

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.

4.4 What a key can and cannot do

With a write keyPossible?
Read the public catalogueYes (no key needed, but a key also works)
Prepare unsigned transactionsYes
See the live allowance and balance of the wallet you nameYes
Track a position you preparedYes — and only yours
Sign anythingNever
Broadcast on your behalfNever
Move, withdraw or transfer valueNever
Spend outside the allowance you signedNever
Act on any wallet other than one you name as walletNever
See another organisation's keys, positions or activityNever

4.5 POST /v1/swaps — prepare a swap

Where 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 }
  } }

4.6 The second credential — x402 (pay per request)

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" } }
}

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:

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.

Part 5 · Menus of the read surface

5.1 Metadata

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.

5.2 Catalog pinning

/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.

Part 6 · The configuration surface — how a custom revision happens

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.

6.1 Permission set — policy as data

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).

6.2 Restriction profiles — compliance as a named preset

{ "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.

6.3 Event subscriptions — the client chooses what it hears

{ "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.

6.4 Pre-preparation review hook — bring your own logic

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.

Part 7 · Fees

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.

Rate0.05 % of the traded amount
Where it livesInside the signed order data of the position. It is not a separate transfer and not an invoice.
Who is chargedEveryone who creates a new position. There is no tier, no volume threshold and no integration path that avoids it.
What the integrator controlsTheir 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 positionsUnaffected. Terms are immutable on-chain; positions created before this rule keep their original terms.
Reading dataFree, 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.

Part 8 · Tiers

TierStatusRead surfaceWrite pathRate limitsSupport
OpenLiveAll read endpoints, no key—As advertised on each replyEmail
IntegratorLive (after review)SamePOST /v1/positions and POST /v1/swaps — prepare-only, key held server-side, origin-restricted — or the same routes paid per request with x402, no keyRaised buckets per key, agreedEmail, named contact
EnterpriseRoadmapSameSame + policy sets, approval groups, pre-preparation hook, event subscriptionsDedicated bucketsNamed 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.

Part 9 · Full worked example — a treasury dashboard

# 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'

Appendix · Contract quick reference

ElementWhere
OpenAPI 3.1https://yield.trdefi.com/openapi.json
Markdown twin of the docshttps://yield.trdefi.com/docs/api.md
Agent indexhttps://yield.trdefi.com/llms.txt
Request an API keyhttps://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 tablehttps://yield.trdefi.com/docs/api#errors
Rate limitshttps://yield.trdefi.com/docs/api#rate-limits
Method of Statementhttps://yield.trdefi.com/docs/method-of-statement
General Ruleshttps://yield.trdefi.com/docs/general-rules

TRDEFI Ltd, London, United Kingdom. See also: Method of Statement, General Rules.