Euler Finance Curator API
Curator-managed metadata such as labels, descriptions, and visibility controls. This is the operator-owned customization surface in v3.
Curator-managed metadata such as labels, descriptions, and visibility controls. This is the operator-owned customization surface in v3.
openapi: 3.1.0
info:
title: Euler Data API (V3) Accounts Curator API
version: 3.0.0
description: "API specification for Euler Data v3. This spec defines the current\nresource-oriented contract for the platform, with emphasis on consistent\nschemas, predictable REST semantics, caching, observability, and a uniform\ndeveloper experience.\n\nMigration notes\n- Euler Data v3 is not a path-for-path clone of v1/v2. Some endpoints map\n directly, some require multiple v3 calls, and some legacy aggregates were\n intentionally removed.\n- The live [migration guide](/v3/docs/migration) explains how legacy v1/v2\n endpoints and payloads map into the v3 resource model.\n- Important semantic changes:\n - Vault base APY and rewards APY are exposed separately in v3.\n - Account positions are flattened into account-vault rows instead of the\n legacy nested sub-account shape.\n - All supported API paths live under `/v3`; legacy paths return `410`.\n - Summary endpoints prefer smaller, focused resources over large\n BFF-style payloads.\n\nBase path: /v3\n\nConventions\n- JSON field naming: camelCase\n- Addresses: accept lowercase or checksum; responses are EIP-55 checksummed\n- Public APY values (`*Apy`, `apy*`): percent numbers with 6 decimal places (e.g., 5.123456 = 5.123456%)\n- Contract interest-rate fields (`borrowAPY`, `supplyAPY` in `interestRates`): decimal strings in contract fraction units\n- Ratios (utilization, LTV, etc.): numbers with 6 decimal places\n- Response timestamps: ISO-8601 strings (UTC). Some legacy fields still expose unix\n seconds for compatibility and include `*Iso` companions.\n- Query time ranges: unix seconds (from/to)\n\nUnit policy\n- v3 separates market metadata from contract verdicts by both name and type.\n- Market-normalized USD prices and USD values are JSON numbers. These are values\n derived from off-chain pricing, cached price snapshots, or API-level market math.\n This includes `/v3/prices`, token price routes, vault/earn/protocol USD totals,\n portfolio market values, portfolio USD liquidation/risk fields such as\n `liabilityValueUsd`, `totalCollateralValueUsd`, `borrowLiquidationPriceUsd`,\n and `collateralLiquidationPricesUsd`, and vault holder `assetsUsd`.\n- Contract-derived oracle and raw account-liquidity verdict values are exact strings.\n These preserve the integer value used by contracts, normalized to 18 decimals\n for API exposure. Oracle prices are quoted in the vault unit of account, which\n can be USD, ETH, or another asset. This includes `/v3/oracles/prices`, raw\n account-liquidity `liabilityValue` and `totalCollateralValue` objects,\n `liabilityValueBorrowing`, `liabilityValueLiquidation`, and collateral verdict\n values.\n- On-chain token quantities are bigint strings in their native unit scale. This\n includes amounts, balances, shares, assets, borrows, reward amounts, liquidation\n repay/yield amounts, and block numbers.\n- Caps are also bigint strings, but EVK caps are exposed as resolved underlying\n asset-unit amounts rather than packed contract config words.\n- LTV config values use canonical basis-point strings. Legacy decimal aliases\n may remain on config-history payloads for compatibility when explicitly named.\n\nRate limiting\n- Optional API keys for higher limits\n- Default limits are configurable; current defaults: free tier 100 req/min (IP-based)\n and authenticated 1000 req/min (per API key), 60s window.\n- By default, proxy headers are not trusted for IP identity unless explicitly enabled.\n- Redis failures default to fail-closed (503) for strict enforcement; fail-open is opt-in.\n- RateLimit-* (IETF draft-6) and legacy X-RateLimit-* headers are returned.\n\nCORS\n- Public API responses use wildcard CORS, including preflight responses for unsafe methods.\n- Unsafe methods with request bodies must use a JSON media type.\n\nCaching\n- Cache-Control headers are returned for cacheable endpoints.\n- Defaults (may be adjusted in config):\n - Prices: 300s\n - APYs: 600s\n - Rewards: 900s\n - General responses: 60s (short 30s, long 300s)\n\nErrors\n- All errors use a standard envelope: { error: { code, message, requestId, details? } }\n- Domain error codes are documented in this spec.\n- JSON request bodies must use `Content-Type: application/json` or another `application/*+json` media type.\n- Request bodies larger than 1 MiB are rejected before route parsing with `413 PAYLOAD_TOO_LARGE`.\n"
servers:
- url: /
description: Current environment
security: []
tags:
- name: Curator
description: Curator-managed metadata such as labels, descriptions, and visibility controls. This is the operator-owned customization surface in v3.
paths:
/v3/curator/vaults:
get:
tags:
- Curator
summary: List vaults labeled by the authenticated curator
x-status: implemented
x-cache-ttl: 30
security:
- ApiKeyAuth: []
- BearerAuth: []
parameters:
- $ref: '#/components/parameters/ChainIdParam'
- $ref: '#/components/parameters/OffsetParam'
- $ref: '#/components/parameters/LimitParam'
responses:
'200':
description: Curator-labeled vaults
headers:
Cache-Control:
$ref: '#/components/headers/Cache-Control'
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/OracleRouterState'
meta:
$ref: '#/components/schemas/PaginationMeta'
'401':
$ref: '#/components/responses/Error401'
'403':
$ref: '#/components/responses/Error403'
'429':
$ref: '#/components/responses/Error429'
'500':
$ref: '#/components/responses/Error500'
operationId: getCuratorVaults
/v3/curator/vaults/{chainId}/{address}/labels:
put:
tags:
- Curator
summary: Submit or update curator label for a vault
x-status: implemented
x-cache-ttl: 0
security:
- ApiKeyAuth: []
- BearerAuth: []
parameters:
- $ref: '#/components/parameters/ChainIdPath'
- $ref: '#/components/parameters/AddressPath'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- displayName
properties:
displayName:
type: string
minLength: 1
maxLength: 120
pattern: ^[^\u0000-\u001F\u007F-\u009F<>]+$
description: Plain text only; clients must render as text, not HTML or Markdown.
description:
type: string
maxLength: 1024
pattern: ^[^\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F<>]*$
description: Plain text only; clients must render as text, not HTML or Markdown. Tabs and line breaks are allowed.
productCategory:
type: string
maxLength: 120
pattern: ^[^\u0000-\u001F\u007F-\u009F<>]*$
description: Plain text only; clients must render as text, not HTML or Markdown.
riskTier:
type: string
maxLength: 64
pattern: ^[^\u0000-\u001F\u007F-\u009F<>]*$
description: Plain text only; clients must render as text, not HTML or Markdown.
strategyDescription:
type: string
maxLength: 2048
pattern: ^[^\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F<>]*$
description: Plain text only; clients must render as text, not HTML or Markdown. Tabs and line breaks are allowed.
responses:
'200':
description: Curator label upserted
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
type: object
properties:
data:
$ref: '#/components/schemas/CuratorVaultLabel'
meta:
$ref: '#/components/schemas/PaginationMeta'
'400':
$ref: '#/components/responses/Error400'
'401':
$ref: '#/components/responses/Error401'
'403':
$ref: '#/components/responses/Error403'
'404':
$ref: '#/components/responses/Error404'
'413':
$ref: '#/components/responses/Error413'
'415':
$ref: '#/components/responses/Error415'
'429':
$ref: '#/components/responses/Error429'
'500':
$ref: '#/components/responses/Error500'
operationId: putCuratorVaultsByChainIdByAddressLabels
components:
responses:
Error413:
description: Request body too large
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Error429:
description: Rate limited
headers:
Retry-After:
description: Seconds until next request is allowed.
schema:
type: integer
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Error401:
description: Unauthorized
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Error415:
description: Unsupported media type
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Error500:
description: Internal server error
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Error400:
description: Bad request
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Error404:
description: Not found
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Error403:
description: Forbidden
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
headers:
X-Request-Id:
description: Request identifier for tracing.
schema:
type: string
Cache-Control:
description: Cache policy for this response.
schema:
type: string
schemas:
CuratorInfo:
type: object
required:
- apiKeyId
- name
- keyPrefix
properties:
apiKeyId:
type: string
name:
type: string
keyPrefix:
type: string
CuratorVaultLabel:
type: object
required:
- chainId
- vaultAddress
- curator
- displayName
- updatedAt
properties:
chainId:
type: integer
vaultAddress:
type: string
curator:
$ref: '#/components/schemas/CuratorInfo'
displayName:
type: string
minLength: 1
maxLength: 120
pattern: ^[^\u0000-\u001F\u007F-\u009F<>]+$
description: Plain text only; clients must render as text, not HTML or Markdown.
description:
type: string
nullable: true
maxLength: 1024
pattern: ^[^\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F<>]*$
description: Plain text only; clients must render as text, not HTML or Markdown. Tabs and line breaks are allowed.
productCategory:
type: string
nullable: true
maxLength: 120
pattern: ^[^\u0000-\u001F\u007F-\u009F<>]*$
description: Plain text only; clients must render as text, not HTML or Markdown.
riskTier:
type: string
nullable: true
maxLength: 64
pattern: ^[^\u0000-\u001F\u007F-\u009F<>]*$
description: Plain text only; clients must render as text, not HTML or Markdown.
strategyDescription:
type: string
nullable: true
maxLength: 2048
pattern: ^[^\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F<>]*$
description: Plain text only; clients must render as text, not HTML or Markdown. Tabs and line breaks are allowed.
updatedAt:
type: string
format: date-time
OracleRouterVault:
type: object
properties:
vault:
type: string
asset:
type: string
blockNumber:
type: string
timestamp:
type: string
format: date-time
txHash:
type: string
ErrorResponse:
type: object
required:
- error
properties:
error:
type: object
required:
- code
- message
- requestId
properties:
code:
type: string
description: 'Domain error code. Examples:
- INVALID_ADDRESS
- CHAIN_NOT_SUPPORTED
- VAULT_NOT_FOUND
- TOKEN_NOT_FOUND
- ACCOUNT_NOT_FOUND
- VALIDATION_ERROR
- RATE_LIMIT_EXCEEDED
- UNSUPPORTED_MEDIA_TYPE
- UNAUTHORIZED
- FORBIDDEN
- INTERNAL_ERROR
'
message:
type: string
requestId:
type: string
details:
type: object
additionalProperties: true
OracleRouterState:
type: object
properties:
chainId:
type: integer
router:
type: string
deployer:
type: string
deployedAt:
type: string
format: date-time
configs:
type: array
items:
$ref: '#/components/schemas/OracleRouterConfig'
vaults:
type: array
items:
$ref: '#/components/schemas/OracleRouterVault'
OracleRouterConfig:
type: object
properties:
asset0:
type: string
asset1:
type: string
oracle:
type: string
blockNumber:
type: string
timestamp:
type: string
format: date-time
txHash:
type: string
PaginationMeta:
type: object
required:
- timestamp
properties:
total:
type: integer
description: Exact total count when the endpoint provides one.
hasMore:
type: boolean
description: Indicates whether another page exists beyond the current page.
offset:
type: integer
limit:
type: integer
description: Echoed page size after endpoint-side clamping.
timestamp:
type: string
format: date-time
chainId:
type: string
description: Comma-separated chain IDs for multi-chain responses.
parameters:
OffsetParam:
name: offset
in: query
required: false
schema:
type: integer
default: 0
ChainIdPath:
name: chainId
in: path
required: true
schema:
type: integer
AddressPath:
name: address
in: path
required: true
schema:
type: string
ChainIdParam:
name: chainId
in: query
required: false
schema:
type: string
description: Comma-separated list of chain IDs (single value allowed).
example: 1,10,8453
LimitParam:
name: limit
in: query
required: false
description: Requested page size. Values above the endpoint cap are clamped; the default shared cap is 100.
schema:
type: integer
default: 20
maximum: 100
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
description: API key authentication (optional; higher rate limits).
BearerAuth:
type: http
scheme: bearer
bearerFormat: API key
description: 'Alternative to X-API-Key using Authorization: Bearer <key>'
AdminSecret:
type: apiKey
in: header
name: X-Admin-Secret
description: Admin secret (server-to-server) for API key management.
PlatformSession:
type: apiKey
in: cookie
name: euler_platform_session
description: Signed, httpOnly platform-operator browser session cookie.
PlatformCsrf:
type: apiKey
in: header
name: X-CSRF-Token
description: Double-submit CSRF token required for unsafe cookie-authenticated methods.