# TRDEFI Liquidity API

Public, read-first API over the live non-custodial liquidity catalogue — and indicative pricing
against it. **Version `v1`.** Base URL `https://yield.trdefi.com`. No key required to read.

> The machine-readable contract is [`/openapi.json`](/openapi.json). The styled version of this page
> is [`/docs/api`](/docs/api).

## The contract

- Every response carries `X-Request-Id`.
- Every endpoint advertises `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` and
  `RateLimit-Policy` — on success **and** on failure.
- Every error uses one envelope.
- Read responses are `{ data, meta }`; `meta.freshnessSeconds` says how old the roll-up is.

## Endpoints

| Method | Path | Returns |
|---|---|---|
| GET | `/api/stats` | Catalogue totals, per-chain breakdown, top pairs by volume and by positions |
| GET | `/api/chains` | Live set of supported chains (treat as a catalog) |
| GET | `/api/strategies` | Open liquidity positions. Filters: `pair`, `chain`, `q` |
| GET | `/api/strategy-detail?hash=` | One position in detail |
| GET | `/api/quote?hash=&chain=&amount=` | Indicative quote for one strategy. Nothing is signed |
| GET | `/api/badge?metric=` | shields.io `endpoint` payload for READMEs |

### Response shape

```json
{
  "data": { "totals": { "strategies": 4685, "volume_30d_usd": 205811838.49 } },
  "meta": {
    "requestId": "9f2c1d4e7a8b3c5d6e0f1a2b3c4d5e6f",
    "generatedAt": "2026-09-24T02:11:05.376Z",
    "apiVersion": "v1",
    "freshnessSeconds": 10800,
    "cached": false
  }
}
```

## Authentication

The read surface needs **no key**. Anything that signs or moves funds lives on a separate,
origin-restricted write path with its own credential. Nothing on the read surface can move value.

## Rate limits

Per path bucket and per client — not per key; more keys do not raise them.

| Bucket | Limit | Window |
|---|---|---|
| `stats` | 120 | 60 s |
| `badge` | 120 | 60 s |
| `chains` | 60 | 60 s |
| `quote` | 60 | 60 s |
| `strategy-detail` | 60 | 60 s |
| `strategies` | 20 | 60 s |
| `ship`, `swap` (write) | 6 | 60 s |

Read the numbers from the response headers, not from this table — the headers are authoritative.

```
curl -sD - -o /dev/null https://yield.trdefi.com/api/stats | grep -i ratelimit
ratelimit-limit: 120
ratelimit-remaining: 119
ratelimit-reset: 42
ratelimit-policy: stats;w=60;limit=120
```

On `429`, `Retry-After` is always present.

## Error codes

Branch on `code`, never on `message`. `retryable` is part of the contract.

| Code | HTTP | Retryable | Meaning |
|---|---|---|---|
| `BAD_REQUEST` | 400 | no | The request could not be parsed |
| `INVALID_PARAMETER` | 400 | no | A parameter is missing or out of range |
| `UNAUTHORIZED` | 401 | no | Missing or invalid credential on a protected path |
| `FORBIDDEN` | 403 | no | Origin or scope not allowed |
| `NOT_FOUND` | 404 | no | No such resource |
| `METHOD_NOT_ALLOWED` | 405 | no | Wrong HTTP method |
| `UNSUPPORTED_CHAIN` | 422 | no | Chain not in the live catalog |
| `UNPROCESSABLE` | 422 | no | Understood, but cannot be executed as asked |
| `RATE_LIMITED` | 429 | yes | Back off using `Retry-After` |
| `INTERNAL` | 500 | yes | Unexpected error on our side |
| `UPSTREAM_UNAVAILABLE` | 503 | yes | Our data source is briefly unavailable |
| `UPSTREAM_TIMEOUT` | 504 | yes | Our data source did not answer in time |

### Envelope

```json
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded for stats",
    "requestId": "9f2c1d4e7a8b3c5d6e0f1a2b3c4d5e6f",
    "retryable": true,
    "documentation": "https://yield.trdefi.com/docs/api/errors#rate_limited"
  }
}
```

Client-fixable problems — allowance too low, balance too low, unsupported chain — additionally carry
a structured `issues[]` array with `expected` / `actual`, so you can correct them without contacting us.

## Versioning & deprecation

Resources are path-versioned. Breaking changes ship under a new path version and are announced on the
public calendar with a **minimum 90 days' notice**. Nothing is removed without a documented
replacement. Additive fields — a new key, a new enum value — may appear at any time and are not
breaking; ignore what you do not recognise.

| Change | Breaking? | How it ships |
|---|---|---|
| New field in a response | no | Any time |
| New endpoint | no | Any time |
| New value in an enum | no | Any time — handle unknown values gracefully |
| New error `code` | no | Any time — branch on known codes, fall back on the rest |
| Field removed or renamed | **yes** | New path version + 90-day notice |
| Field type or meaning changed | **yes** | New path version + 90-day notice |
| Endpoint removed | **yes** | Replacement published first + 90-day notice |

## Try it

```bash
# totals
curl -s https://yield.trdefi.com/api/stats | head -c 400

# which chains are live
curl -s https://yield.trdefi.com/api/chains

# a README badge
curl -s "https://yield.trdefi.com/api/badge?metric=volume30"
```

---

TRDEFI Ltd · London, United Kingdom · <https://trdefi.com> · info@trdefi.com
All rights reserved. Nothing here is financial advice. No guaranteed returns.
