Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Euler Data API (V3) Securitize API
version: 3.0.0
description: 'API specification for Euler Data v3. This spec defines the current
resource-oriented contract for the platform, with emphasis on consistent
schemas, predictable REST semantics, caching, observability, and a uniform
developer experience. This public document covers unauthenticated endpoints and integrations that
use API keys, including capability-scoped keys. Browser-session Toolbox
operations, admin-secret operations, and the Prometheus endpoint are served
separately and are intentionally omitted. Migration notes
- Euler Data v3 is not a path-for-path clone of v1/v2. Some endpoints map
directly, some require multiple v3 calls, and some legacy aggregates were
intentionally removed. - The live migration guide explains how legacy v1/v2
endpoints and payloads map into the v3 resource model. - Important semantic changes:
- Vault base APY and rewards APY are exposed separately in v3. - Account positions are flattened into account-vault rows instead of the
legacy nested sub-account shape. - All supported API paths live under `/v3`; legacy paths return `410`. - Summary endpoints prefer smaller, focused resources over large
BFF-style payloads. Base path: /v3
Conventions
- JSON field naming: camelCase
- Addresses: accept lowercase or checksum; responses are EIP-55 checksummed
- Public APY values (`*Apy`, `apy*`): percent numbers with 6 decimal places (e.g., 5.123456 = 5.123456%)
- Contract interest-rate fields (`borrowAPY`, `supplyAPY` in `interestRates`): decimal strings in contract fraction units
- Ratios (utilization, LTV, etc.): numbers with 6 decimal places
- Response timestamps: ISO-8601 strings (UTC). Some legacy fields still expose unix
seconds for compatibility and include `*Iso` companions. - Query time ranges: unix seconds (from/to)
Unit policy
- v3 separates market metadata from contract verdicts by both name and type. - Market-normalized USD prices and USD values are JSON numbers. These are values
derived from off-chain pricing, cached price snapshots, or API-level market math. This includes `/v3/prices`, token price routes, vault/earn/protocol USD totals,
portfolio market values, portfolio USD liquidation/risk fields such as
`liabilityValueUsd`, `totalCollateralValueUsd`, `borrowLiquidationPriceUsd`,
and `collateralLiquidationPricesUsd`, and vault holder `assetsUsd`. - Contract-derived oracle and raw account-liquidity verdict values are exact strings. These preserve the integer value used by contracts, normalized to 18 decimals
for API exposure. Oracle prices are quoted in the vault unit of account, which
can be USD, ETH, or another asset. This includes `/v3/oracles/prices`, raw
account-liquidity `liabilityValue` and `totalCollateralValue` objects,
`liabilityValueBorrowing`, `liabilityValueLiquidation`, and collateral verdict
values. - On-chain token quantities are bigint strings in their native unit scale. This
includes amounts, balances, shares, assets, borrows, reward amounts, liquidation
repay/yield amounts, and block numbers. - Caps are also bigint strings, but EVK caps are exposed as resolved underlying
asset-unit amounts rather than packed contract config words; an unlimited EVK cap is
type(uint256).max and `0` is a zero cap. The exceptions are
cap-history and config-history, which carry the raw uint16 encodings. - LTV config values use canonical basis-point strings. Legacy decimal aliases
may remain on config-history payloads for compatibility when explicitly named. Rate limiting
- Optional API keys for higher limits
- Standard limits are 1000 req/min for unauthenticated callers (IP-based)
and 10000 req/min for authenticated callers (per API key), with a 60s window. Individual API keys can carry a custom limit. - By default, proxy headers are not trusted for IP identity unless explicitly enabled. - Redis failures default to fail-closed (503) for strict enforcement; fail-open is opt-in. - RateLimit-* (IETF draft-6) and legacy X-RateLimit-* headers are returned.'
servers:
- url: /
description: Current environment
security: []
tags:
- name: Securitize
description: Securitize collateral vaults, which the Securitize factory deploys and the issuer governs. Separate from the EVK routes, which never list them.
paths:
/v3/securitize/vaults/batch:
post:
tags:
- Securitize
summary: Securitize vault batch
description: 'Returns Securitize vault rows for explicit addresses on one chain, in request
order after address deduplication; `meta.notFound` lists the rest. The
governing address is `governorAdmin`. Serves what the EVK routes never
list: Securitize vaults come from their own factory and their own indexed
table. A chain this deployment does not index answers 404
`CHAIN_NOT_SUPPORTED`; an indexed chain with no Securitize factory answers
every address as not found. When the indexed positions or the prices
cannot be read, the rows still answer, with the affected deposit fields
null, the source named in `meta.degradedProviders`, and
`Cache-Control: no-store`.
Request cap: 1000 vault addresses and 256 KiB of JSON body.'
x-status: implemented
x-cache-ttl: 60
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SecuritizeVaultBatchRequest'
responses:
'200':
description: Securitize vault batch
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/SecuritizeVaultBatchResponse'
'400':
$ref: '#/components/responses/Error400'
'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: postSecuritizeVaultBatch
/v3/securitize/vaults/{chainId}/{address}:
get:
tags:
- Securitize
summary: Securitize vault detail
description: 'Returns one Securitize vault with its visibility verdict. A consumer that
resolves an address by family reads the EVK detail first, then Earn, then
this route; each answers 404 `VAULT_NOT_FOUND` for a vault of another
family. When the indexed positions or the prices cannot be read, the vault
still answers, with the affected deposit fields null, the source named in
`meta.degradedProviders`, and `Cache-Control: no-store`.'
x-status: implemented
x-cache-ttl: 60
parameters:
- $ref: '#/components/parameters/ChainIdPath'
- $ref: '#/components/parameters/AddressPath'
responses:
'200':
description: Securitize vault detail
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
type: object
properties:
data:
$ref: '#/components/schemas/SecuritizeVaultSummary'
meta:
$ref: '#/components/schemas/PaginationMeta'
'400':
$ref: '#/components/responses/Error400'
'404':
$ref: '#/components/responses/Error404'
'429':
$ref: '#/components/responses/Error429'
'500':
$ref: '#/components/responses/Error500'
operationId: getSecuritizeVaultsByChainIdByAddress
components:
schemas:
LabelHoldSummary:
description: What a draft read shows on a held row.
type: object
required:
- id
- kind
- reason
- since
properties:
id:
type: string
format: uuid
kind:
type: string
enum:
- quarantine
- entity-hold
reason:
type: string
since:
type: string
format: date-time
ExcludedChains:
type: array
description: 'On a read across chains that names no `chainId`: the served chains it left out because they do not run the capability the operation needs, rather than reading them as empty. Absent when no chain was left out.'
items:
type: object
required:
- chainId
- capability
properties:
chainId:
type: integer
capability:
type: string
enum:
- indexing
- activity
- prices
- historicalPrices
- assessments
- labels
- logos
- stats
- risk
- rewards
- apys
ResolvedProductLabels:
type: object
readOnly: true
description: Read-time entity fallbacks for display. Derived, never stored.
required:
- entityName
- url
- logo
properties:
entityName:
type: string
nullable: true
url:
type: string
nullable: true
description: Product url, falling back to the owning entity url.
logo:
type: string
nullable: true
description: Product logo, falling back to the owning entity logo.
VaultListingDecidedBy:
type: string
description: 'Who decided one discovery side''s listing, nearest explicit decision first: `platform` (assessment override), `escrow` (lend side of an escrow vault, set by Euler automatically), `curator` (vault-level flag), `curator-product` (product-level flag), `deprecated` (resolved deprecation with no curator flag), or `none` (shown, nothing decided).'
enum:
- platform
- escrow
- curator
- curator-product
- deprecated
- none
SecuritizeVaultSummary:
type: object
description: 'A Securitize collateral vault: an EVault deployed by the Securitize factory, collateral-only, governed by the issuer. Everything knowable about one from the index -- the vault token, its asset, who governs it, its supply cap, its deposits. It has no oracle, interest rate model, borrowing, utilization or APY (nothing is lent from it), which is why it is served here and never on the EVK routes. The deposit fields use the EVK read''s names and are valued exactly as `/v3/protocol/stats` values them.'
required:
- chainId
- address
- vaultType
- isEscrow
- name
- symbol
- decimals
- asset
- shares
- governorAdmin
- supplyCap
- caps
- totalAssets
- totalSupplyUsd
- snapshotTimestamp
- createdAt
- visibility
properties:
chainId:
type: integer
address:
type: string
vaultType:
type: string
enum:
- securitize
description: Every row of this surface is a Securitize vault; one read tells a consumer the family.
isEscrow:
type: boolean
description: Always false; the escrow perspective verifies EVK-factory vaults only.
name:
type: string
symbol:
type: string
decimals:
type: integer
asset:
allOf:
- $ref: '#/components/schemas/AssetRef'
description: 'The underlying token as the app''s token registry knows it, in the shape the EVK rows use: `address` always; `symbol`, `decimals` and `name` only when the registry has them. A token the registry does not know is answered by address alone -- the share token''s identity is never substituted for it.'
shares:
$ref: '#/components/schemas/SecuritizeTokenRef'
governorAdmin:
type: string
description: The address that governs the vault -- the issuer. The field the curator claim preflight reads.
supplyCap:
type: string
description: Resolved supply cap as a bigint string in underlying asset base units, decoded from the EVK cap encoding; `0` when no cap is set. Unlike the EVK detail, which serves an unset cap as type(uint256).max, this route keeps `0`. Do not decode it again.
caps:
allOf:
- $ref: '#/components/schemas/VaultCaps'
description: The same resolved cap under the key the EVK detail uses, with the same `0` for no cap as `supplyCap` (not type(uint256).max); `borrowCap` is absent because a collateral-only vault has no borrow side.
totalAssets:
type: string
nullable: true
description: 'Deposits as a bigint string in underlying asset base units: the shares outstanding (the sum of the indexed positions), read one share to one asset. The vault earns nothing and has no decimals offset, so shares and assets only drift apart if someone sends the asset straight to the vault. Null when the positions could not be read, named then in `meta.degradedProviders` as `securitize-positions`.'
totalSupplyUsd:
type: number
nullable: true
description: '`totalAssets` in USD at V3''s selected price (at most 24 hours old, the on-chain fallback included). Null when the deposits or the price could not be read (the latter named `prices` in `meta.degradedProviders`), or the vault holds assets whose asset has no usable price; an empty vault answers 0.'
snapshotTimestamp:
type: string
format: date-time
nullable: true
description: 'The time of the data behind `totalAssets`: the indexer''s sync time for the chain (the block time of its latest checkpoint). Null when the positions could not be read.'
createdAt:
type: string
format: date-time
description: Deployment time from the factory event.
visibility:
$ref: '#/components/schemas/VaultVisibilitySummary'
ProductPlatformListing:
description: The platform-owned discovery decision on a product, as a product row shows it.
type: object
required:
- notExplorableLend
- notExplorableBorrow
- reason
properties:
notExplorableLend:
type: boolean
notExplorableBorrow:
type: boolean
reason:
type: string
nullable: true
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.
outcome:
type: string
enum:
- disabled
- removed
description: On a toolbox config DELETE, what happened to the row.
products:
type: array
description: 'On a curation vault `POST`, `PUT`, or `PATCH`: the products the write touched (the one the vault left and the one it joined) as they are after the write, `governanceMode` included, so the caller applies them instead of re-reading.'
items:
$ref: '#/components/schemas/ProductLabels'
timestamp:
type: string
format: date-time
chainId:
type: string
description: Comma-separated chain IDs for multi-chain responses.
degradedProviders:
type: array
items:
type: string
description: Live providers whose data is incomplete in this response.
excludedChains:
$ref: '#/components/schemas/ExcludedChains'
SecuritizeTokenRef:
type: object
required:
- address
- symbol
- decimals
- name
properties:
address:
type: string
symbol:
type: string
decimals:
type: integer
name:
type: string
SecuritizeVaultBatchResponse:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/SecuritizeVaultSummary'
meta:
$ref: '#/components/schemas/SecuritizeVaultBatchMeta'
SecuritizeVaultBatchMeta:
type: object
properties:
count:
type: integer
requested:
type: integer
notFound:
type: array
items:
type: string
timestamp:
type: string
format: date-time
chainId:
type: string
degradedProviders:
type: array
items:
type: string
enum:
- securitize-positions
- prices
description: Deposit sources that could not be read for this answer.
ListingFlag:
type: boolean
nullable: true
description: Curator listing flag. `null` leaves the decision to platform overrides and deprecation, `true` hides the vault(s) from discovery, `false` keeps a deprecated vault listed.
VaultCaps:
type: object
description: EVK caps resolved to underlying asset base units as bigint strings. A vault without a cap (encoded zero) is `115792089237316195423570985008687907853269984665640564039457584007913129639935` (type(uint256).max), with or without an on-chain read; `0` is a real zero cap.
properties:
supplyCap:
type: string
description: Resolved supply cap as a bigint string in underlying asset base units; `115792089237316195423570985008687907853269984665640564039457584007913129639935` when unlimited, `0` for a zero cap.
borrowCap:
type: string
description: Resolved borrow cap as a bigint string in underlying asset base units; `115792089237316195423570985008687907853269984665640564039457584007913129639935` when unlimited, `0` for a zero cap.
SecuritizeVaultBatchRequest:
type: object
required:
- chainId
- addresses
properties:
chainId:
type: integer
addresses:
type: array
minItems: 1
maxItems: 1000
items:
type: string
maxLength: 42
AssetRef:
type: object
properties:
address:
type: string
symbol:
type: string
decimals:
type: integer
name:
type: string
nullable: true
ErrorResponse:
type: object
required:
- error
properties:
error:
type: object
required:
- code
- message
- requestId
properties:
code:
type: string
description: 'Domain error code. Examples:
- BAD_REQUEST
- INVALID_ADDRESS
- INVALID_CHAIN_ID
- CHAIN_NOT_SUPPORTED
- CHAIN_CAPABILITY_DISABLED
- NOT_FOUND
- VAULT_NOT_FOUND
- TOKEN_NOT_FOUND
- ACCOUNT_NOT_FOUND
- VALIDATION_ERROR
- CONFLICT
- PRECONDITION_FAILED
- PAYLOAD_TOO_LARGE
- RATE_LIMIT_EXCEEDED
- UNSUPPORTED_MEDIA_TYPE
- UPSTREAM_TIMEOUT
- UNAUTHORIZED
- FORBIDDEN
- SERVICE_UNAVAILABLE
- SERVICE_DISABLED
- INTERNAL_ERROR
'
message:
type: string
requestId:
type: string
details:
type: object
additionalProperties: true
description: Context of the error. Where present, `details.reason` is a stable kebab-case value to key on, and `details.cause` narrows a reason that has several causes. The labels routes list theirs in the Labels tag.
VaultVisibilitySummary:
type: object
description: 'Platform visibility verdict for discovery surfaces. Warning stays discoverable with a badge; the per-surface booleans carve out lend/borrow discovery individually. A side is explorable when `status` is `visible` or `warning` and nothing hides that side: a platform override, the escrow rule, a curator listing flag on the vault or its product, or deprecation (which hides by default unless a curator re-lists with a `false` flag). An escrow vault (`isEscrow: true`) is never explorable for lending, because nothing can be borrowed from it and a deposit earns nothing; it stays explorable for borrowing, so a market that accepts it as collateral keeps it in its pairs. Its `status` is unaffected.'
required:
- status
- explorableLend
- explorableBorrow
- decidedBy
- reason
properties:
status:
type: string
enum:
- visible
- warning
- hidden
- pending_review
explorableLend:
type: boolean
explorableBorrow:
type: boolean
explorableLendDecidedBy:
$ref: '#/components/schemas/VaultListingDecidedBy'
explorableBorrowDecidedBy:
$ref: '#/components/schemas/VaultListingDecidedBy'
decidedBy:
type: string
description: Which resolution rule decided the status. `config-*` codes come from Layer 1 (configuration safety), `consistency-*` codes from Layer 2 (label consistency). `unclaimed` and `unassigned` are label gates. A verified or unassessable non-escrow vault stays in `pending_review` until an entity claims it, and EVK and Securitize vaults additionally require assignment to a product. Escrow vaults bypass both label gates. `advisories` badges a vault that passed both layers but has a failed advisory finding — it stays in discovery, with `checksStatus` on its assessment naming a Layer 1 concern and `consistencyContext` a Layer 2 one (an Earn vault's deprecated dependency); an advisory that could not be judged does not badge.
enum:
- config-revoked
- consistency-revoked
- config-suspended
- consistency-suspended
- config-failed
- not-explorable
- unassessable
- deprecated
- advisories
- unclaimed
- unassigned
- verified
- awaiting-verification
reason:
type: string
nullable: true
description: 'Display-appropriate explanation for the decision, when there is one: the curated deprecation reason, the failing check''s sentence, or, for `advisories`, the sentence of the first failed advisory (Layer 1 before Layer 2, each by finding key) followed by a count of the rest, e.g. "… (2 more checks flagged)". Null for a deprecated vault whose curator gave no reason, and whenever nothing needs explaining.'
ProductLabels:
type: object
required:
- id
- chainId
- entityId
- coBrandEntityIds
- name
- isDeprecated
- notExplorable
- governanceMode
- resolved
- anyExplorableLend
- anyExplorableBorrow
- createdAt
- updatedAt
properties:
id:
type: string
pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$
chainId:
type: integer
minimum: 1
entityId:
type: string
coBrandEntityIds:
type: array
description: Additional entities whose logos should be displayed. Product management remains exclusively with entityId.
items:
type: string
name:
type: string
logo:
type: string
nullable: true
description:
type: string
nullable: true
url:
type: string
nullable: true
maxLength: 2048
pattern: ^[Hh][Tt][Tt][Pp][Ss]://
description: Absolute https URL.
portfolioNotice:
type: string
nullable: true
isDeprecated:
type: boolean
deprecationReason:
type: string
nullable: true
notExplorable:
allOf:
- $ref: '#/components/schemas/ListingFlag'
description: Product-wide curator listing flag applied to both sides of every member vault unless a vault-level flag overrides it.
governanceMode:
type: string
enum:
- governed
- ungoverned
- unknown
readOnly: true
description: Derived by the server from the on-chain governor of member vaults; clients cannot set it. Products are created as `unknown`. Every vault assignment recomputes the mode over the resulting member set and rejects sets that mix governed and ungoverned vaults. Layer 2 adopts `governed` or `ungoverned` for an `unknown` product once its membership verifies against chain state. Entity members cannot update or delete an `ungoverned` product or its vaults after the initial assignment.
resolved:
$ref: '#/components/schemas/ResolvedProductLabels'
anyExplorableLend:
type: boolean
readOnly: true
description: True when at least one member vault is lend-discoverable per the materialized visibility verdicts. Live chain state (e.g. borrowability) is deliberately excluded.
anyExplorableBorrow:
type: boolean
readOnly: true
description: True when at least one member vault is borrow-discoverable per the materialized visibility verdicts. Live chain state (e.g. borrowability) is deliberately excluded.
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
hold:
type: object
nullable: true
description: The hold covering this row on a draft read; absent on published reads.
allOf:
- $ref: '#/components/schemas/LabelHoldSummary'
platformListing:
type: object
nullable: true
description: Euler's listing override on this product, shown to platform sessions on draft reads (null when there is none); absent on published reads and to curators.
allOf:
- $ref: '#/components/schemas/ProductPlatformListing'
responses:
Error500:
description: Internal server error
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'
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'
Error413:
description: Request body too large
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'
Error415:
description: Unsupported media type
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
parameters:
ChainIdPath:
name: chainId
in: path
required: true
schema:
type: integer
AddressPath:
name: address
in: path
required: true
schema:
type: string
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>'