> For the complete documentation index, see [llms.txt](https://docs.yifi.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.yifi.io/api-reference/pairs.md).

# Pairs

Exact pair metadata and counterpart-token search (`GET /v1/pairs`, `GET /v1/pairs/search`)

## Search available exchange pairs

> Returns metadata for \*\*one exact direction\*\*. All four query fields are required: \`fromToken\`, \`fromNetwork\`, \`toToken\`, \`toNetwork\`.\
> \
> Each pair includes \`availableEngines\` (\`on-chain\` / \`off-chain\` / \`private\`), provider slugs, \`minAmount\` and \`maxAmount\` (\`"0"\` when the catalog has no max).\
> \
> Unknown token/network combinations that still pass validation return \`{ tokenPairs: \[], totalPairs: 0 }\` (\`200\`), not \`404\`.\
> \
> Successful lookups are cached for 5 minutes. To list counterpart tokens for a single side, use \`GET /v1/pairs/search\`.

```json
{"openapi":"3.0.0","info":{"title":"YiFi Swap Public API","version":"1.0"},"tags":[{"name":"Pairs","description":"Exact pair metadata and counterpart-token search (`GET /v1/pairs`, `GET /v1/pairs/search`)"}],"servers":[{"url":"https://api.yifi.io","description":"Production"},{"url":"https://api-dev.yifi.io","description":"Development / Staging"}],"paths":{"/v1/pairs":{"get":{"description":"Returns metadata for **one exact direction**. All four query fields are required: `fromToken`, `fromNetwork`, `toToken`, `toNetwork`.\n\nEach pair includes `availableEngines` (`on-chain` / `off-chain` / `private`), provider slugs, `minAmount` and `maxAmount` (`\"0\"` when the catalog has no max).\n\nUnknown token/network combinations that still pass validation return `{ tokenPairs: [], totalPairs: 0 }` (`200`), not `404`.\n\nSuccessful lookups are cached for 5 minutes. To list counterpart tokens for a single side, use `GET /v1/pairs/search`.","operationId":"getPairs","parameters":[{"name":"fromToken","required":true,"in":"query","description":"Source token ticker. Must be provided together with `fromNetwork`.","schema":{"type":"string"}},{"name":"fromNetwork","required":true,"in":"query","description":"Source chain slug (`GET /v1/chains` → `id`)","schema":{"type":"string"}},{"name":"toToken","required":true,"in":"query","description":"Target token ticker. Must be provided together with `toNetwork`.","schema":{"type":"string"}},{"name":"toNetwork","required":true,"in":"query","description":"Target chain slug (`GET /v1/chains` → `id`)","schema":{"type":"string"}}],"responses":{"200":{"description":"Matching token pairs (often 0 or 1) with engines and limits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenPairsResponseDto"}}}},"400":{"description":"Missing required field or unknown query parameter","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable code (`COIN_NOT_FOUND`, `RATE_EXPIRED`, `INVALID_API_KEY`, `HTTP_EXCEPTION` for class-validator, …)"},"message":{"description":"Human-readable message. Class-validator 400s may return a string **array** of constraint texts.","oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"requestId":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"details":{"description":"Present for some validation (4xx) errors when thrown with `details`.","oneOf":[{"type":"object","additionalProperties":true},{"type":"array"}]}},"required":["code","message","requestId","timestamp"]}}}}}},"408":{"description":"`WORKFLOW_TIMEOUT` (20s pair workflow)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable code (`COIN_NOT_FOUND`, `RATE_EXPIRED`, `INVALID_API_KEY`, `HTTP_EXCEPTION` for class-validator, …)"},"message":{"description":"Human-readable message. Class-validator 400s may return a string **array** of constraint texts.","oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"requestId":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"details":{"description":"Present for some validation (4xx) errors when thrown with `details`.","oneOf":[{"type":"object","additionalProperties":true},{"type":"array"}]}},"required":["code","message","requestId","timestamp"]}}}}}},"500":{"description":"`TOKEN_PAIRS_ERROR` or workflow failure","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable code (`COIN_NOT_FOUND`, `RATE_EXPIRED`, `INVALID_API_KEY`, `HTTP_EXCEPTION` for class-validator, …)"},"message":{"description":"Human-readable message. Class-validator 400s may return a string **array** of constraint texts.","oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"requestId":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"details":{"description":"Present for some validation (4xx) errors when thrown with `details`.","oneOf":[{"type":"object","additionalProperties":true},{"type":"array"}]}},"required":["code","message","requestId","timestamp"]}}}}}}},"summary":"Search available exchange pairs","tags":["Aggregator","Pairs"]}}},"components":{"schemas":{"TokenPairsResponseDto":{"type":"object","properties":{"tokenPairs":{"description":"List of token pairs","type":"array","items":{"$ref":"#/components/schemas/TokenPairDto"}},"totalPairs":{"type":"number","description":"Total number of token pairs found"}},"required":["tokenPairs","totalPairs"]},"TokenPairDto":{"type":"object","properties":{"fromToken":{"type":"string","description":"Source token ticker"},"fromNetwork":{"type":"string","description":"Source chain slug"},"toToken":{"type":"string","description":"Target token ticker"},"toNetwork":{"type":"string","description":"Target chain slug"},"availableEngines":{"description":"Available engines for this pair","type":"array","items":{"type":"string"}},"providers":{"description":"Provider IDs supporting this pair","type":"array","items":{"type":"string"}},"minAmount":{"type":"string","description":"Minimum exchange amount"},"maxAmount":{"type":"string","description":"Maximum exchange amount"}},"required":["fromToken","fromNetwork","toToken","toNetwork","availableEngines","providers","minAmount","maxAmount"]}}}}
```

## Search available counterpart tokens for a pair

> Paginated counterpart tokens for building a pair picker. Response shape matches \`GET /v1/tokens\`.\
> \
> \*\*How filters are applied (no 400 for a lone ticker/network):\*\*\
> \
> \- \`fromToken\` \*\*and\*\* \`fromNetwork\` both set → tokens you can \*\*receive\*\* (the \`to\` side of catalog pairs). Optional \`toNetwork\` further restricts those counterparts.\
> \- \`toToken\` \*\*and\*\* \`toNetwork\` both set → tokens you can \*\*send\*\* (the \`from\` side). Optional \`fromNetwork\` further restricts those counterparts.\
> \- Only one side of a pair (\`fromToken\` without \`fromNetwork\`, etc.) is treated as \*\*not set\*\*.\
> \- \*\*Neither complete side\*\* → the counterpart set is empty (\`tokens: \[]\`, \`total: 0\`). This endpoint does \*\*not\*\* dump the full catalog.\
> \
> \`search\` ranks within the counterpart set (ticker / name / address). Default page: \`limit=20\`, \`offset=0\`. Coin-set cache TTL: 5 minutes.

```json
{"openapi":"3.0.0","info":{"title":"YiFi Swap Public API","version":"1.0"},"tags":[{"name":"Pairs","description":"Exact pair metadata and counterpart-token search (`GET /v1/pairs`, `GET /v1/pairs/search`)"}],"servers":[{"url":"https://api.yifi.io","description":"Production"},{"url":"https://api-dev.yifi.io","description":"Development / Staging"}],"paths":{"/v1/pairs/search":{"get":{"description":"Paginated counterpart tokens for building a pair picker. Response shape matches `GET /v1/tokens`.\n\n**How filters are applied (no 400 for a lone ticker/network):**\n\n- `fromToken` **and** `fromNetwork` both set → tokens you can **receive** (the `to` side of catalog pairs). Optional `toNetwork` further restricts those counterparts.\n- `toToken` **and** `toNetwork` both set → tokens you can **send** (the `from` side). Optional `fromNetwork` further restricts those counterparts.\n- Only one side of a pair (`fromToken` without `fromNetwork`, etc.) is treated as **not set**.\n- **Neither complete side** → the counterpart set is empty (`tokens: []`, `total: 0`). This endpoint does **not** dump the full catalog.\n\n`search` ranks within the counterpart set (ticker / name / address). Default page: `limit=20`, `offset=0`. Coin-set cache TTL: 5 minutes.","operationId":"searchPairs","parameters":[{"name":"fromToken","required":false,"in":"query","description":"Source token ticker. Used only when `fromNetwork` is also set; otherwise ignored.","schema":{"type":"string"}},{"name":"fromNetwork","required":false,"in":"query","description":"Source chain slug. Used only when `fromToken` is also set; otherwise ignored.","schema":{"type":"string"}},{"name":"toToken","required":false,"in":"query","description":"Target token ticker. Used only when `toNetwork` is also set; otherwise ignored.","schema":{"type":"string"}},{"name":"toNetwork","required":false,"in":"query","description":"Target chain slug. Used only when `toToken` is also set; otherwise ignored.","schema":{"type":"string"}},{"name":"search","required":false,"in":"query","description":"Search by ticker or token name within the results","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Number of results per page. Maximum 100.","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Pagination offset","schema":{"minimum":0,"default":0,"type":"number"}}],"responses":{"200":{"description":"Paginated counterpart tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenListApiResponseDto"}}}},"400":{"description":"Invalid pagination or unknown query parameter","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable code (`COIN_NOT_FOUND`, `RATE_EXPIRED`, `INVALID_API_KEY`, `HTTP_EXCEPTION` for class-validator, …)"},"message":{"description":"Human-readable message. Class-validator 400s may return a string **array** of constraint texts.","oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"requestId":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"details":{"description":"Present for some validation (4xx) errors when thrown with `details`.","oneOf":[{"type":"object","additionalProperties":true},{"type":"array"}]}},"required":["code","message","requestId","timestamp"]}}}}}},"408":{"description":"`WORKFLOW_TIMEOUT` (20s pair workflow)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable code (`COIN_NOT_FOUND`, `RATE_EXPIRED`, `INVALID_API_KEY`, `HTTP_EXCEPTION` for class-validator, …)"},"message":{"description":"Human-readable message. Class-validator 400s may return a string **array** of constraint texts.","oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"requestId":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"details":{"description":"Present for some validation (4xx) errors when thrown with `details`.","oneOf":[{"type":"object","additionalProperties":true},{"type":"array"}]}},"required":["code","message","requestId","timestamp"]}}}}}},"500":{"description":"`TOKEN_PAIRS_ERROR` or workflow failure","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable code (`COIN_NOT_FOUND`, `RATE_EXPIRED`, `INVALID_API_KEY`, `HTTP_EXCEPTION` for class-validator, …)"},"message":{"description":"Human-readable message. Class-validator 400s may return a string **array** of constraint texts.","oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"requestId":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"details":{"description":"Present for some validation (4xx) errors when thrown with `details`.","oneOf":[{"type":"object","additionalProperties":true},{"type":"array"}]}},"required":["code","message","requestId","timestamp"]}}}}}}},"summary":"Search available counterpart tokens for a pair","tags":["Aggregator","Pairs"]}}},"components":{"schemas":{"TokenListApiResponseDto":{"type":"object","properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/PublicTokenItemApiDto"}},"totalTokens":{"type":"number","description":"Number of token objects in this response page (matches `tokens.length`)"},"limit":{"type":"number","description":"Page size for this response"},"offset":{"type":"number","description":"Pagination offset"},"total":{"type":"number","description":"Total tokens matching filters before pagination"}},"required":["tokens","totalTokens","limit","offset","total"]},"PublicTokenItemApiDto":{"type":"object","properties":{"uuid":{"type":"string","description":"Internal coin UUID (used by workflows; not required on public query params)"},"network":{"type":"string","description":"Canonical chain slug (`GET /v1/chains` → `id`)"},"ticker":{"type":"string","description":"Token ticker"},"name":{"type":"string","description":"Display name"},"supportsFixedRate":{"type":"boolean","description":"Whether any catalogued route supports a fixed rate for this asset"},"contractAddress":{"type":"object","description":"Contract address; `null` for native coins","nullable":true},"engineSupport":{"description":"Engines that support this token: `on-chain` (DEX), `off-chain` (CEX), and sometimes `private`","type":"array","items":{"type":"string"}},"logoUrlCoin":{"type":"string","description":"Token logo URL"},"regexAddress":{"type":"string","description":"JavaScript regex source used to validate addresses of this asset (`receiveAddress` / `refundAddress` on swap)"},"explorerAddressUrl":{"type":"string","description":"Block-explorer URL template for an address"},"explorerTransactionUrl":{"type":"string","description":"Block-explorer URL template for a transaction"},"decimals":{"type":"object","nullable":true,"description":"Token decimals"},"logoUrlsNetwork":{"type":"object","nullable":true,"description":"Network / chain logo URL"},"coingeckoCoinId":{"type":"object","nullable":true,"description":"CoinGecko coin id (`bitcoin`, `ethereum`, `usd-coin`)"},"currentPriceUsd":{"type":"object","nullable":true,"description":"Spot price in USD from CoinGecko (numeric string)"}},"required":["uuid","network","ticker","name","supportsFixedRate","contractAddress"]}}}}
```
