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 need an API key. To initiate a trade — to create a position or swap through the API — you need a key, issued after a short review. Request one here. The key prepares; it never signs.

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 by the client, that prepares but cannot 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": 4685, "makers": 693, "pairs": 1385, "chains": 17,
      "volume_1d_usd": 73972611.94, "volume_7d_usd": 137597554.61, "volume_30d_usd": 205811838.49,
      "last_activity": "2026-09-23T00:00:00.000Z",
      "rollup_updated_at": "2026-09-24T00:00:00.000Z"
    },
    "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)

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

Quote simulation is enabled only for verified USDC/USDT strategies attached to the verified router. Any other strategy returns UNPROCESSABLE (422) with a reason rather than a guessed price.

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.

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, server-side]
                   → 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.

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": "2026-09-24T23:59:52.414Z",
    "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

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 — prepare-only, key held server-side, origin-restrictedRaised 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
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.