{"openapi":"3.1.0","info":{"title":"Euler Data API (V3)","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\nThis public document covers unauthenticated endpoints and integrations that\nuse API keys, including capability-scoped keys. Browser-session Toolbox\noperations, admin-secret operations, and the Prometheus endpoint are served\nseparately and are intentionally omitted.\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; an unlimited EVK cap is\n  type(uint256).max and `0` is a zero cap. The exceptions are\n  cap-history and config-history, which carry the raw uint16 encodings.\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- Standard limits are 1000 req/min for unauthenticated callers (IP-based)\n  and 10000 req/min for authenticated callers (per API key), with a 60s window.\n  Individual API keys can carry a custom limit.\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":"Protocol","description":"Protocol-wide summary endpoints and aggregate metrics. In v3, these endpoints are explicitly summary-oriented and should be treated as lightweight rollups rather than replacements for full vault list payloads."},{"name":"Health","description":"Liveness, readiness, and dashboard-friendly platform status checks. Public readiness calls use a bounded per-process admission budget; dependency-health routes share that budget and Kubernetes probes use a Service-excluded management listener. Use these for operational monitoring, not for reconstructing full portfolio state."},{"name":"Entities","description":"Platform-admin managed KYBed organization profiles used as backend-owned label and control-plane resources."},{"name":"Labels","description":"The labeling system behind the Toolbox: entity and product profiles, vault labels, vault assessments, geo policies, and label publishing. The address that governs a vault is its governing address: the governor of an EVK or Securitize vault, the owner of an Earn vault. In this API \"controller\" always means the EVC controller, the liability vault an account has enabled through the Ethereum Vault Connector, never the address that governs a vault.\n\n**Errors on the `/v3/labels` routes.** Key on the status, `error.code` and `error.details.reason`; `error.message` is for people and may change. `details.cause` narrows a reason that has several causes. An error without a reason is the only one its route answers with that status and code. The labels routes never answer `SERVICE_DISABLED`.\n\n| Status | Code | `details.reason` | Meaning |\n|---|---|---|---|\n| 401 | UNAUTHORIZED | `invalid-session` | No active session of a kind the route accepts. |\n| 403 | FORBIDDEN | `authorization-denied` | The actor may not make this write. `details.cause`: `platform-admin-denied`, `missing-csrf` or `csrf-mismatch` on platform-only routes; `wrong-entity`, `insufficient-role`, `unsupported-actor`, `inactive-actor`, `malformed-actor` or `missing-actor` on entity, member, address, product and vault writes. |\n| 403 | FORBIDDEN | `missing-csrf`, `csrf-mismatch` | Entity-or-platform route, unsafe method: the CSRF header is missing or does not match. While a session changes under the request the reason can also be `missing-session`, `invalid-session`, `expired-session`, `entity-member-denied`, `entity-auth-disabled` or `platform-admin-denied`. |\n| 403 | FORBIDDEN | `entity-suspended` | The member's entity is suspended by the platform. |\n| 403 | FORBIDDEN | `entity-admin-required` | The route needs an entity admin; the session is an editor. |\n| 403 | FORBIDDEN | `entity-scope-denied` | A draft read of another entity's rows. |\n| 403 | FORBIDDEN | `self-demotion-denied`, `self-revoke-denied` | An entity admin demoting or revoking their own membership. |\n| 403 | FORBIDDEN | `published-row` | An entity member deleting a product the public has seen. |\n| 403 | FORBIDDEN | `ungoverned-locked` | An ungoverned vault or product is write-once for entity members. |\n| 403 | FORBIDDEN | `ownership-denied` | No entity address governs the vault; on a product, `details.addresses` lists the vaults the entity no longer governs. |\n| 403 | FORBIDDEN | `vault-not-claimable` | An escrow vault, or a vault type an entity cannot claim. |\n| 403 | FORBIDDEN | `no-governing-address` | The vault has no governor or owner on chain (`details.role`); only Euler can assign it. |\n| 403 | FORBIDDEN | `capability-denied`, `api-key-read-only`, `platform-session-required` | An API key without the capability, a key on a write a read grant cannot make, or an action only a platform session may take. |\n| 404 | NOT_FOUND | `unknown-vault` | The vault is not in indexed factory discovery. |\n| 404 | NOT_FOUND | `label-set-not-found`, `label-version-not-found`, `hold-not-found`, `resource-not-found` | Label set, version, hold and quarantine routes. |\n| 404 | NOT_FOUND | none | The entity, member, address, product, vault labels or listing override does not exist. On the label reads, a 404 with `details.labelSet` and `details.version` means the label set or version could not be resolved; only that 404 carries `details.labelSet`. |\n| 404 | CHAIN_NOT_SUPPORTED | none | A product or vault delete or transfer on a chain the deployment does not serve. |\n| 409 | CONFLICT | `duplicate` | The entity, address, product or vault labels already exist. |\n| 409 | CONFLICT | `already-member`, `email-unavailable` | Adding a member: the email is already an active member of this entity (`details.memberId`), or another entity holds it (only a platform session also gets `details.entityId` and `details.revokedAt`). |\n| 409 | CONFLICT | `address-taken` | The address is registered to another entity (`details.holderEntityId`). |\n| 409 | CONFLICT | `already-revoked`, `last-active-admin-denied` | The member is already revoked, or the change would leave the entity without an active admin. |\n| 409 | CONFLICT | `referenced` | Entity delete while products, claimed vaults or co-brands reference it (`details.references`). |\n| 409 | CONFLICT | `vault-type-mismatch`, `mixed-governance`, `invalid-membership` | The vault type differs from discovery (`details.actualType`), the product would mix governed and ungoverned vaults, or a vault type cannot belong to a product (`details.addresses`). |\n| 409 | CONFLICT | `already-quarantined`, `already-released`, `entity-hold` | Hold routes; an entity hold is released by resuming the entity. |\n| 409 | CONFLICT | `label-set-not-publishable`, `version-exists`, `publication-suspended`, `restore-conflict` | Publishing and restoring label versions. |\n| 412 | PRECONDITION_FAILED | none | `If-Match` names an older `updatedAt`; `details.updatedAt` is the current one. |\n| 412 | PRECONDITION_FAILED | `draft-changed` | A publish's `expectedDraftToken` no longer matches its dry run; `details.draftToken` is the current one. |\n| 412 | PRECONDITION_FAILED | `stale-review` | A hold or release whose `expectedContentHash` no longer matches the draft row; `details.contentHash` is the current one, and nothing is written. |\n| 503 | SERVICE_UNAVAILABLE | `publication-in-progress` | A publication holds the label set; retry after `Retry-After` (5 seconds). |\n| 503 | SERVICE_UNAVAILABLE | `ownership-unavailable`, `governance-unavailable`, `capability-check-unavailable` | On-chain ownership, product governance or an API key capability could not be checked. |\n| 400 | BAD_REQUEST, VALIDATION_ERROR, INVALID_ADDRESS, INVALID_CHAIN_ID | none | Malformed JSON or filter (`details.param`), a malformed `If-Match`, or a malformed address or chain id in the path. |\n| 422 | VALIDATION_ERROR | none | Body or query validation; `details.issues[]` names each `path`. |\n| 413, 415, 429 | PAYLOAD_TOO_LARGE, UNSUPPORTED_MEDIA_TYPE, RATE_LIMIT_EXCEEDED | none | A body over 1 MiB, a body that is not JSON, or a rate limit (`Retry-After`). |\n"},{"name":"Usage","description":"API usage and API key analytics. These endpoints are intended for operators and consumers tracking traffic, rate limits, and key-level activity."},{"name":"Images","description":"Stable, extensionless image URLs and the authenticated image catalog used by Euler applications."},{"name":"Changes","description":"Change requests for managed data. Every data area (token images, price sources, and later ones) goes through the same routes, with server-side checks, a per-domain policy that applies or proposes, admin review, revert, and an auto-apply kill switch."},{"name":"Chains","description":"Chain inventory and per-chain protocol summaries. These replace ad-hoc chain-level aggregates from legacy APIs with explicit, cacheable resources."},{"name":"Vaults","description":"Canonical vault resources, vault history, holders, borrowers, and open-interest views. In v3, vault detail is decomposed into focused endpoints instead of one large legacy response."},{"name":"Accounts","description":"Account activity, discovered positions, and sub-account relationships. Legacy nested account payloads are flattened into account-vault rows in v3."},{"name":"Activity","description":"Normalized vault and owner event timelines with explicit per-chain source coverage and cursor pagination."},{"name":"Tokens","description":"Token metadata, protocol classifications, and related static reference data used throughout the API."},{"name":"Prices","description":"Current and historical token prices. Prices follow v3 source priority rules, return the canonical merged value, and expose provenance only as `onchain`, `offchain`, or `hardcoded`. Current-price responses are best-known observations up to 7 days old; clients use `timestamp` to evaluate age. `timestamp` is the provider's own time for the price when it gives one (CoinGecko `last_updated_at`, DefiLlama `timestamp`, Pyth `publish_time`; an ERC-4626 share takes its underlying's), and the time V3 read it otherwise (Pendle, the on-chain fallback), so a quote the provider stopped updating ages like any other. Derived USD calculations never use observations older than 24 hours. A price from a source set up per token (Pyth, Pendle, CoinGecko, DefiLlama, ERC-4626) is served only while the token has an enabled entry for that source. The on-chain fallback prices a vault asset with no entry by itself, and a token's `onchain` entry changes that. Enabled with an oracle adapter address, the token's on-chain price is that adapter's quote, with no assessment. The admin who pinned it vouches for it. If the quote fails, the token gets no on-chain price. Enabled with `any`, it quotes through any assessed adapter. Disabled, the token gets no on-chain price and its stored one stops being served. A share priced through it gets no new on-chain quote, but its stored one is served until it ages unless the share's own entry is disabled too. After any change to the entry, a fallback price read before the change is not served. A price-source change takes effect at once, since the token's cached price is dropped."},{"name":"APYs","description":"Base and intrinsic APY surfaces. In v3, APY families are split into dedicated endpoints instead of being embedded inconsistently across larger payloads."},{"name":"Rewards","description":"Reward campaign APRs and per-account reward breakdowns. Rewards APY is intentionally separate from base vault APY in v3; combine them client-side when you need a legacy-style total supply APY."},{"name":"Oracles","description":"Oracle routing, adapter, and price-source inspection endpoints. Price provenance is exposed only as `onchain`, `offchain`, or `hardcoded`."},{"name":"Earn","description":"Euler Earn vault resources and historical data. These endpoints are separate from EVK vaults and should be modeled independently in client code."},{"name":"Securitize","description":"Securitize collateral vaults, which the Securitize factory deploys and the issuer governs. Separate from the EVK routes, which never list them."},{"name":"Liquidations","description":"Liquidation events and related historical views used for risk analysis and monitoring."},{"name":"TermsOfUse","description":"Terms-of-use signature state and audit endpoints."},{"name":"EVC","description":"Ethereum Vault Connector account event resources. These are separate from account position snapshots and are intended for event-level inspection."},{"name":"PublicAllocator","description":"Public allocator event resources for allocator-level activity and history."},{"name":"FeeFlow","description":"Fee-flow event resources and fee-related historical activity."},{"name":"GraphQL","description":"Controlled GraphQL passthrough endpoints for indexer-backed data exploration and compatibility workflows."},{"name":"Compliance","description":"Capability-gated address screening for trusted server-side consumers."}],"components":{"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>"}},"headers":{"X-Request-Id":{"description":"Request identifier for tracing.","schema":{"type":"string"}},"X-Label-Set":{"description":"The label set this read resolved, for example `public`.","schema":{"type":"string"}},"X-Label-Version":{"description":"The label version this read resolved. For a published read it is the version's key (`latest`, `production` and other aliases resolve to it, for example `v20260929144948869`); send it back as `version=` to pin later reads to the same snapshot. For a `current` or `draft` read it is `draft`.","schema":{"type":"string"}},"X-Label-Version-Id":{"description":"The resolved published version's id. Absent on `current` and `draft` reads. It is not accepted as a `version=` selector; pin on `X-Label-Version`.","schema":{"type":"string","format":"uuid"}},"AssessmentETag":{"description":"The assessment's `platformUpdatedAt` in double quotes; absent while the vault has no stored assessment. Send it back as `If-Match` on the next PATCH.","schema":{"type":"string"}},"Cache-Control":{"description":"Cache policy for this response.","schema":{"type":"string"}}},"parameters":{"ImageVersionQuery":{"name":"v","in":"query","required":false,"description":"First 8 hex characters of the image's content digest, as `logoURI` carries it. Only the current digest earns the year-long immutable cache; any other value, a malformed one included, is ignored and the image is served with the one-hour cache, never an error.","schema":{"type":"string","pattern":"^[0-9a-f]{8}$"}},"WorkItemIdPath":{"name":"id","in":"path","required":true,"description":"Work item ID as listed, `<chainId>:<token address>`.","schema":{"type":"string","pattern":"^[1-9][0-9]{0,15}:0x[0-9a-fA-F]{40}$"}},"ChainIdParam":{"name":"chainId","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated list of positive chain IDs (single value allowed). Duplicate IDs are removed in first-occurrence order; at most 20 distinct IDs and 512 input characters are accepted.","example":"1,10,8453"},"RewardsBreakdownChainIdParam":{"name":"chainId","in":"query","required":false,"schema":{"type":"string","pattern":"^\\s*[1-9]\\d*\\s*(,\\s*[1-9]\\d*\\s*)*$"},"description":"Optional comma-separated chain filter. Every element must be a positive\nsafe integer; surrounding whitespace is ignored, and empty elements are\ninvalid. Duplicate IDs are accepted, count once toward the fan-out limit,\nand preserve first-occurrence order. At most 12 distinct supported chain\nIDs are allowed. Omitting this parameter leaves the result unrestricted by\nchain.\n","example":"1,42161,8453"},"ChainIdPath":{"name":"chainId","in":"path","required":true,"schema":{"type":"integer"}},"AddressPath":{"name":"address","in":"path","required":true,"schema":{"type":"string"}},"AddressScreeningHistoryAddressParam":{"name":"address","in":"query","required":false,"schema":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"}},"AddressScreeningHistoryChainParam":{"name":"chain","in":"query","required":false,"description":"Matches the requested or resolved chain of an evaluation, or the chain of a request.","schema":{"type":"string","minLength":1,"maxLength":50,"pattern":"^[a-zA-Z0-9_-]+$"}},"AddressScreeningHistoryFromParam":{"name":"from","in":"query","required":false,"description":"Inclusive lower bound on the evaluation or request time (RFC 3339).","schema":{"type":"string","format":"date-time"}},"AddressScreeningHistoryToParam":{"name":"to","in":"query","required":false,"description":"Inclusive upper bound on the evaluation or request time (RFC 3339).","schema":{"type":"string","format":"date-time"}},"AddressScreeningEvaluationSuspiciousParam":{"name":"suspicious","in":"query","required":false,"description":"`true` for the evaluations that flagged the address, `false` for the\nclear ones; absent for both. Applied before paging, so `meta.total`\ncounts the matching evaluations.\n","schema":{"type":"string","enum":["true","false"]}},"AddressScreeningHistoryLimitParam":{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},"OffsetParam":{"name":"offset","in":"query","required":false,"description":"Page offset, capped at 10000 to bound query cost.","schema":{"type":"integer","minimum":0,"maximum":10000,"default":0}},"IndexedEventsOffsetParam":{"name":"offset","in":"query","required":false,"description":"Indexed-event page offset as a non-negative base-10 safe integer, with a maximum of 1000. Invalid values are rejected; use narrower time or event-type filters for deeper history.","schema":{"type":"integer","minimum":0,"maximum":1000,"default":0}},"AccountPositionsOffsetParam":{"name":"offset","in":"query","required":false,"description":"Account-position page offset, capped at 1000 to bound position discovery and enrichment work.","schema":{"type":"integer","minimum":0,"maximum":1000,"default":0}},"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","minimum":1,"default":20,"maximum":100}},"LabelViewParam":{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["curation","resolved"],"default":"curation"},"description":"Read view. `curation` (default) returns raw label fields with the resolved block nested, mirroring the write schema so read-modify-write round-trips stay safe. `resolved` returns the display cascade flattened to the top level with raw fields omitted, for read-only consumers. Unknown values are rejected with 400."},"LabelSetParam":{"name":"labelSet","in":"query","required":false,"description":"Label set identifier. Defaults to `public`.","schema":{"type":"string","default":"public"}},"LabelVersionParam":{"name":"version","in":"query","required":false,"description":"Version selector. Omission, `latest`, and `production` select the latest published snapshot. Explicit `current` and `draft` select the mutable working copy and require an authorized session as documented by the endpoint. Other published keys and aliases retain their stored casing.","schema":{"type":"string","default":"latest"}},"LabelSetIdPath":{"name":"labelSetId","in":"path","required":true,"description":"Label set identifier.","schema":{"type":"string"}},"TokenLimitParam":{"name":"limit","in":"query","required":false,"description":"Requested token page size. Values above 500 are clamped.","schema":{"type":"integer","minimum":1,"default":20,"maximum":500}},"IncludeParam":{"name":"include","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated list of related resources to expand. Unknown values are ignored."},"SortParam":{"name":"sort","in":"query","required":false,"schema":{"type":"string"},"description":"Sort field, prefix with '-' for descending."},"FromParam":{"name":"from","in":"query","required":false,"schema":{"type":"integer"},"description":"Unix timestamp (seconds)."},"ToParam":{"name":"to","in":"query","required":false,"schema":{"type":"integer"},"description":"Unix timestamp (seconds)."},"HistoryFromParam":{"name":"from","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":2147483647},"description":"Unix timestamp in seconds, no later than 2038-01-19T03:14:07Z."},"HistoryToParam":{"name":"to","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":2147483647},"description":"Unix timestamp in seconds, no later than 2038-01-19T03:14:07Z."},"StartTimestampParam":{"name":"startTimestamp","in":"query","required":false,"schema":{"type":"integer"},"description":"Start of time range (unix seconds)."},"EndTimestampParam":{"name":"endTimestamp","in":"query","required":false,"schema":{"type":"integer"},"description":"End of time range (unix seconds)."}},"schemas":{"ConfigTrustEntry":{"type":"object","required":["id","chainId","kind","address","ruleKey","label","fingerprint","provider","sessionBound","maxSilenceSeconds","createdAt","updatedAt","version","createdBy","updatedBy"],"properties":{"id":{"type":"string","format":"uuid"},"chainId":{"type":"integer"},"kind":{"type":"string","enum":["hook-target","rule-exemption","custom-adapter","adapter-check-exemption"]},"address":{"type":"string","description":"Hook target address for hook-target entries; vault address for rule-exemption entries; oracle adapter address for custom-adapter and adapter-check-exemption entries."},"ruleKey":{"type":"string","nullable":true,"description":"Exempted finding key (rule-exemption entries only), e.g. `collateral.0x....ltv`; for adapter-check-exemption entries, the adapter health check key that is accepted."},"label":{"type":"string","nullable":true},"fingerprint":{"type":"string","nullable":true,"pattern":"^0x[0-9a-f]{64}$","description":"Metadata-stripped runtime bytecode SHA-256 (custom-adapter entries only)."},"provider":{"type":"string","nullable":true,"description":"Curated provider identity (custom-adapter entries only)."},"sessionBound":{"type":"boolean","description":"Custom-adapter entries only: the reviewed adapter pauses outside trading sessions. A quote revert on one of its routed pairs is then excused (`not_applicable`) when that pair quoted successfully within `maxSilenceSeconds`, measured from the last successful quote v3 observed on the pair. A pair silent longer, or never seen quoting, still fails."},"maxSilenceSeconds":{"type":"integer","nullable":true,"description":"Set exactly when `sessionBound`; between 3600 and 604800 (seven days, the closure bound of the modeled session-bound adapters)."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time","description":"When the row last changed. Rows written before it was recorded carry their creation time."},"version":{"type":"string","description":"`toolbox:<updatedAt>`; the `expectedVersion` of a `trust-entries` change. Trust entries are never edited in place, so it moves only when the entry is replaced."},"createdBy":{"$ref":"#/components/schemas/RowAuthor"},"updatedBy":{"$ref":"#/components/schemas/RowAuthor"}}},"RowAuthor":{"type":["object","null"],"description":"Who wrote the row: a platform admin by id, or a system actor such as `admin-secret` or `euler-labels-unified-importer`. Shown only to a platform session whose operator is on the Toolbox admin allowlist; null for every other reader, and for rows written before authors were recorded.","required":["kind","id"],"properties":{"kind":{"type":"string"},"id":{"type":"string"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","requestId"],"properties":{"code":{"type":"string","description":"Domain error code. Examples:\n- BAD_REQUEST\n- INVALID_ADDRESS\n- INVALID_CHAIN_ID\n- CHAIN_NOT_SUPPORTED\n- NOT_FOUND\n- VAULT_NOT_FOUND\n- TOKEN_NOT_FOUND\n- ACCOUNT_NOT_FOUND\n- VALIDATION_ERROR\n- CONFLICT\n- PRECONDITION_FAILED\n- PAYLOAD_TOO_LARGE\n- RATE_LIMIT_EXCEEDED\n- UNSUPPORTED_MEDIA_TYPE\n- UPSTREAM_TIMEOUT\n- UNAUTHORIZED\n- FORBIDDEN\n- SERVICE_UNAVAILABLE\n- SERVICE_DISABLED\n- INTERNAL_ERROR\n"},"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."}}}}},"LabelSet":{"type":"object","required":["id","name","description","createdAt","updatedAt"],"properties":{"id":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"LabelVersion":{"type":"object","required":["id","labelSetId","versionKey","status","aliases","isLatest","sourceRepo","sourceRef","sourceSha","schemaAdapter","checksum","publishedByKind","createdAt","publishedAt"],"properties":{"id":{"type":"string","format":"uuid"},"labelSetId":{"type":"string"},"versionKey":{"type":"string"},"status":{"type":"string","enum":["draft","published","archived"]},"aliases":{"type":"array","description":"Named selectors for this version. `latest` is carried by exactly one published version per label set, the one `isLatest` marks: a publish hands it over from the previous version in the same transaction.","items":{"type":"string"}},"isLatest":{"type":"boolean"},"sourceRepo":{"type":"string","nullable":true},"sourceRef":{"type":"string","nullable":true},"sourceSha":{"type":"string","nullable":true},"schemaAdapter":{"type":"string"},"checksum":{"type":"string","nullable":true,"description":"SHA-256 checksum of canonical entity, product, and vault-label content, the server-derived `isEscrow` flag of a vault included. Audit timestamps and geo policies are excluded."},"publishedByKind":{"type":"string","enum":["platform-admin","worker","api-key"],"nullable":true,"description":"Who created the version. The publisher's identity is platform-only and appears on the publication state route."},"createdAt":{"type":"string","format":"date-time"},"publishedAt":{"type":"string","format":"date-time","nullable":true}}},"AttributedLabelVersion":{"allOf":[{"$ref":"#/components/schemas/LabelVersion"},{"type":"object","required":["createdBy","createdByEmail","publishedBy","publishedByEmail"],"properties":{"createdBy":{"type":"string","nullable":true,"description":"Present for platform sessions; API keys see null."},"createdByEmail":{"type":"string","nullable":true,"description":"The email of the platform administrator `createdBy` names, for display. Present for platform sessions when the id is a known administrator; null otherwise and for API keys."},"publishedBy":{"type":"string","nullable":true,"description":"Platform administrator id, worker id, or API key id, matching `publishedByKind`. Present for platform sessions; API keys see null."},"publishedByEmail":{"type":"string","nullable":true,"description":"The email of the platform administrator `publishedBy` names when `publishedByKind` is `platform-admin`, for display. Present for platform sessions; null for the worker, for keys, and for API key sessions."},"publishedChanges":{"type":"integer","minimum":0,"description":"Change-log rows this version carried; present on the version history."}}}]},"LabelPublicationSummary":{"type":"object","required":["mode","suspended","dueAt","latestVersion"],"properties":{"mode":{"type":"string","enum":["manual","scheduled"],"description":"How changes go live; see `LabelPublicationState.mode`."},"suspended":{"type":"boolean","description":"Automatic publication is suspended (relevant in `scheduled` mode)."},"dueAt":{"type":"string","format":"date-time","nullable":true,"description":"When the pending draft is due in `scheduled` mode; null when nothing is pending or the mode is `manual`."},"latestVersion":{"type":"object","nullable":true,"required":["versionKey","publishedAt"],"properties":{"versionKey":{"type":"string"},"publishedAt":{"type":"string","format":"date-time","nullable":true}}}}},"LabelPublicationState":{"type":"object","required":["labelSetId","mode","suspended","suspendedAt","suspendedBy","suspensionReason","frozenByEnvironment","effectiveFrozen","minDelaySeconds","maxDelaySeconds","dueAt","windowStartedAt","revision","latestVersion"],"properties":{"labelSetId":{"type":"string"},"mode":{"type":"string","enum":["manual","scheduled"],"description":"How changes go live. `manual` (the rollout default): only an explicit publish by a platform session or a key with `labels:publish` creates a version; no publication window opens and `dueAt` stays null (a CHECK enforces it). `scheduled`: label writes open a window and the worker publishes after the cooldown. Changed in the database only; every mode change resets the schedule, so a switch to `scheduled` opens nothing until the next label write, and a switch to `manual` disarms an open window."},"suspended":{"type":"boolean","description":"A platform actor has suspended automatic publication (relevant in `scheduled` mode). Explicit publication still works."},"suspendedAt":{"type":"string","format":"date-time","nullable":true},"suspendedBy":{"type":"object","nullable":true,"required":["kind","id"],"properties":{"kind":{"type":"string","enum":["platform-admin","api-key"]},"id":{"type":"string","nullable":true,"description":"Present for platform sessions; API keys see the kind only."}}},"suspensionReason":{"type":"string","nullable":true},"frozenByEnvironment":{"type":"boolean","description":"The deployment override (`LABEL_PUBLICATION_FROZEN`) is set. Lifting it is a deploy, not an API call."},"effectiveFrozen":{"type":"boolean","description":"True when either the suspension or the environment override stops the timer. In `manual` mode there is no timer; explicit publication is unaffected either way."},"minDelaySeconds":{"type":"integer","description":"Cooldown after the last label change before the timer publishes. At least 60."},"maxDelaySeconds":{"type":"integer","description":"Cap from the first unpublished change; the timer publishes at the latest here. At most 86400."},"dueAt":{"type":"string","format":"date-time","nullable":true,"description":"When the pending draft is due, or null when nothing is pending or the mode is `manual`."},"windowStartedAt":{"type":"string","format":"date-time","nullable":true},"revision":{"type":"string","description":"Identifies the pending mutations; increments with every scheduled label write."},"latestVersion":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/AttributedLabelVersion"}]}}},"LabelPublicationControlResult":{"allOf":[{"$ref":"#/components/schemas/LabelPublicationState"},{"type":"object","required":["controlOutcome"],"properties":{"controlOutcome":{"type":"string","enum":["suspended","resumed","updated","unchanged"],"description":"Whether this request changed the state or found it already as requested."}}}]},"LabelPublishResult":{"allOf":[{"$ref":"#/components/schemas/LabelVersion"},{"type":"object","required":["publishOutcome","report"],"properties":{"publishOutcome":{"type":"string","enum":["published","unchanged"],"description":"Whether this request created a snapshot or returned the unchanged latest snapshot."},"report":{"$ref":"#/components/schemas/LabelPublicationReport"}}}]},"LabelPublishDryRunResult":{"type":"object","required":["dryRun","publishOutcome","latestVersion","report","changes","draftToken"],"properties":{"dryRun":{"type":"boolean","enum":[true]},"publishOutcome":{"type":"string","enum":["published","unchanged"],"description":"What the same request without `dryRun` would do."},"latestVersion":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/LabelVersion"}]},"report":{"$ref":"#/components/schemas/LabelPublicationReport"},"changes":{"type":"array","description":"What publishing would change, row by row: the report's `published` and `pulledIn` rows with their content on both sides, then the `heldBack` rows (`held: true`) with the draft content a lifted hold would publish. This is the exact answer to \"what would publishing change\", computed by the same comparison publication uses, so it covers every difference between the draft and the latest version, including writes the change log never sees.","items":{"$ref":"#/components/schemas/LabelPublicationRowChange"}},"draftToken":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Opaque token for exactly what this preview would publish, including the holds a partial publish would override. Send it back as `expectedDraftToken` to publish only if nothing moved since."}}},"LabelPublicationRowChange":{"type":"object","required":["key","change","before","after","changedFields","held"],"properties":{"held":{"type":"boolean","description":"True for a row a hold keeps out of this publication: it is listed in the report's `heldBack`, is not taken, and its `after` is the draft content the hold keeps out."},"key":{"$ref":"#/components/schemas/LabelRowKey"},"change":{"type":"string","enum":["create","update","delete"]},"before":{"type":"object","nullable":true,"additionalProperties":true,"description":"The complete row as the latest published version carries it, in the published shape (every published field, no timestamps or assignment); null for a create."},"after":{"type":"object","nullable":true,"additionalProperties":true,"description":"The complete row as the new version would carry it (for a held row, as the draft has it), in the published shape; null for a delete."},"changedFields":{"type":"array","items":{"type":"string"},"description":"The fields whose value differs between `before` and `after`, sorted."}}},"LabelRowKey":{"description":"Identifies one publishable row across the draft and every version.","oneOf":[{"type":"object","required":["type","entityId"],"properties":{"type":{"type":"string","enum":["entity"]},"entityId":{"type":"string"}}},{"type":"object","required":["type","chainId","productId"],"properties":{"type":{"type":"string","enum":["product"]},"chainId":{"type":"integer"},"productId":{"type":"string"}}},{"type":"object","required":["type","chainId","address"],"properties":{"type":{"type":"string","enum":["vault"]},"chainId":{"type":"integer"},"address":{"type":"string"}}}]},"LabelRowSelection":{"description":"The rows a partial publish takes from the draft. Dependencies the selected rows need are pulled in automatically; everything else keeps its published content. Platform sessions only.","type":"object","additionalProperties":false,"properties":{"entities":{"type":"array","items":{"type":"string"}},"products":{"type":"array","items":{"type":"object","required":["chainId","id"],"additionalProperties":false,"properties":{"chainId":{"type":"integer"},"id":{"type":"string"}}}},"vaults":{"type":"array","items":{"type":"object","required":["chainId","address"],"additionalProperties":false,"properties":{"chainId":{"type":"integer"},"address":{"type":"string"}}}}}},"LabelHoldRef":{"type":"object","required":["id","kind","reason"],"properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["quarantine","entity-hold"]},"reason":{"type":"string"}}},"LabelChange":{"type":"object","required":["id","resource","ownerEntityId","action","initialAction","before","after","afterContentHash","changedFields","actor","requestId","status","publishedVersionId","holdId","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"resource":{"$ref":"#/components/schemas/LabelRowKey"},"ownerEntityId":{"type":"string","nullable":true},"action":{"type":"string","enum":["create","update","delete","claim","unclaim","restore","scoped-restore","transfer"],"description":"`restore` marks a row a whole-draft restore brought back; `scoped-restore` one that a restore limited to a curator, products or vaults brought back; `transfer` a row the platform moved to another curator."},"initialAction":{"type":"string","enum":["create","update","delete","claim","unclaim","restore","scoped-restore","transfer"],"description":"The action the row first waited with. A later write to the same row supersedes its pending change and carries this forward, so a claim followed by an edit still reads as a claim until it is published. Equals `action` when nothing was superseded."},"before":{"type":"object","nullable":true,"additionalProperties":true},"after":{"type":"object","nullable":true,"additionalProperties":true},"afterContentHash":{"type":"string","nullable":true,"pattern":"^[0-9a-f]{64}$","description":"Hash of `after` as a draft row; null when the change deleted the row. On a row's `pending` or `quarantined` change it is the current draft row's hash: send it as a hold's or release's `expectedContentHash`."},"changedFields":{"type":"array","items":{"type":"string"}},"actor":{"type":"object","required":["kind","id","email"],"properties":{"kind":{"type":"string","enum":["platform-admin","entity-admin","entity-editor","api-key","system"]},"id":{"type":"string","nullable":true},"email":{"type":"string","nullable":true}}},"requestId":{"type":"string","nullable":true},"status":{"type":"string","enum":["pending","published","quarantined","superseded"]},"publishedVersionId":{"type":"string","format":"uuid","nullable":true},"holdId":{"type":"string","format":"uuid","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"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"}}},"LabelHoldActor":{"type":"object","required":["kind","id","email"],"properties":{"kind":{"type":"string","enum":["platform-admin","api-key","system"]},"id":{"type":"string","nullable":true,"description":"Returned to platform sessions only; keys see null."},"email":{"type":"string","nullable":true,"description":"The platform administrator's email, for display next to the id. Returned to platform sessions only; null for keys, the system, and key sessions."}}},"LabelHold":{"description":"A row held out of publication. A quarantine is a rejection of one row; an entity hold is raised by entity suspension and covers every row the entity owns. Held rows keep their published content on every full publish while the draft stays intact.","type":"object","required":["id","kind","resource","reason","contentHash","heldBy","createdAt","releasedAt","releasedBy","releaseReason"],"properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["quarantine","entity-hold"]},"resource":{"$ref":"#/components/schemas/LabelRowKey"},"reason":{"type":"string"},"contentHash":{"type":"string","nullable":true,"description":"Hash of the draft row when the hold was raised; null when the draft lacked the row."},"heldBy":{"$ref":"#/components/schemas/LabelHoldActor"},"createdAt":{"type":"string","format":"date-time"},"releasedAt":{"type":"string","format":"date-time","nullable":true},"releasedBy":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/LabelHoldActor"}]},"releaseReason":{"type":"string","nullable":true,"description":"Why the hold was released, when the release gave a reason: a quarantine release, or the entity resume that lifted an entity hold. Null while the hold is active."}}},"LabelReleaseRequest":{"type":"object","additionalProperties":false,"properties":{"reason":{"type":"string","nullable":true,"maxLength":500,"description":"Why the hold is released or the entity resumed. Trimmed; blank or null records no reason."},"expectedContentHash":{"type":"string","nullable":true,"pattern":"^[0-9a-f]{64}$","description":"The draft revision the reviewer judged: the change log's `afterContentHash` for the row (null for a row the draft no longer has). Compared with the current draft row inside the write's transaction; when the row moved since, the answer is 412 with `details.reason` `stale-review` and the current `details.contentHash`, and nothing is written. Optional for now; keys will have to send it, and a key write without it is logged."}}},"LabelQuarantineRequest":{"type":"object","additionalProperties":false,"required":["resource","reason"],"properties":{"resource":{"oneOf":[{"type":"object","additionalProperties":false,"required":["type","entityId"],"properties":{"type":{"type":"string","enum":["entity"]},"entityId":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["type","chainId","id"],"properties":{"type":{"type":"string","enum":["product"]},"chainId":{"type":"integer"},"id":{"type":"string"}}},{"type":"object","additionalProperties":false,"required":["type","chainId","address"],"properties":{"type":{"type":"string","enum":["vault"]},"chainId":{"type":"integer"},"address":{"type":"string"}}}]},"reason":{"type":"string","maxLength":500},"expectedContentHash":{"type":"string","nullable":true,"pattern":"^[0-9a-f]{64}$","description":"The draft revision the reviewer judged: the change log's `afterContentHash` for the row (null for a row the draft no longer has). Compared with the current draft row inside the write's transaction; when the row moved since, the answer is 412 with `details.reason` `stale-review` and the current `details.contentHash`, and nothing is written. Optional for now; keys will have to send it, and a key write without it is logged."}}},"LabelPublicationReport":{"description":"What the snapshot builder did: `published` rows went live from the draft, `pulledIn` rows were needed by a selected row, `heldBack` rows carry a pending change a hold kept out (their own hold, a held dependency absent from the published version, or a held published row that still needs them), and `overrides` are held rows the selection published anyway.","type":"object","required":["published","pulledIn","heldBack","overrides","leftOut"],"properties":{"published":{"type":"array","items":{"type":"object","required":["key","change"],"properties":{"key":{"$ref":"#/components/schemas/LabelRowKey"},"change":{"type":"string","enum":["create","update","delete"]}}}},"pulledIn":{"type":"array","items":{"type":"object","required":["key","change","requiredBy"],"properties":{"key":{"$ref":"#/components/schemas/LabelRowKey"},"change":{"type":"string","enum":["create","update","delete"]},"requiredBy":{"$ref":"#/components/schemas/LabelRowKey"}}}},"heldBack":{"type":"array","items":{"type":"object","required":["key","change","cause","holds","relatedKey"],"properties":{"key":{"$ref":"#/components/schemas/LabelRowKey"},"change":{"type":"string","enum":["create","update","delete"]},"cause":{"type":"string","enum":["hold","depends-on-held","required-by-held"]},"holds":{"type":"array","items":{"$ref":"#/components/schemas/LabelHoldRef"}},"relatedKey":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/LabelRowKey"}]}}}},"overrides":{"type":"array","items":{"type":"object","required":["key","holds"],"properties":{"key":{"$ref":"#/components/schemas/LabelRowKey"},"holds":{"type":"array","items":{"$ref":"#/components/schemas/LabelHoldRef"}}}}},"leftOut":{"type":"object","required":["rows","selected"],"description":"Draft vault rows with no labels (the rows discovery materialises for vaults nobody claimed, claims cleared), which the publication leaves out: how many the draft holds, and which of them the selection named, a no-op rather than an error. A selection naming only such rows answers `publishOutcome: unchanged` with them listed here.","properties":{"rows":{"type":"integer","minimum":0},"selected":{"type":"array","items":{"$ref":"#/components/schemas/LabelRowKey"}}}}}},"HealthResponse":{"type":"object","required":["status","version","uptime","timestamp"],"properties":{"status":{"type":"string","enum":["healthy","degraded","unhealthy"]},"version":{"type":"string"},"uptime":{"type":"integer"},"timestamp":{"type":"string","format":"date-time"}}},"DetailedHealthResponse":{"allOf":[{"$ref":"#/components/schemas/HealthResponse"},{"type":"object","required":["checks"],"properties":{"checks":{"type":"object","properties":{"database":{"type":"object","properties":{"status":{"type":"string","enum":["ok","error"]},"latency":{"type":"number"},"error":{"type":"string","enum":["Database health check failed"]},"code":{"type":"string","enum":["DATABASE_HEALTH_CHECK_FAILED"]}}},"ponderRead":{"type":"object","properties":{"status":{"type":"string","enum":["ok","error"]},"latency":{"type":"number"},"error":{"type":"string","enum":["Ponder read-model health check failed"]},"code":{"type":"string","enum":["PONDER_READ_MODEL_HEALTH_CHECK_FAILED"]}}},"redis":{"type":"object","properties":{"status":{"type":"string","enum":["ok","error"]},"latency":{"type":"number"},"error":{"type":"string","enum":["Redis health check failed"]},"code":{"type":"string","enum":["REDIS_HEALTH_CHECK_FAILED"]}}},"indexer":{"type":"object","properties":{"status":{"type":"string","enum":["ok","syncing","error"]},"blocksBehind":{"type":"integer"},"syncProgress":{"type":"number"},"latency":{"type":"number"},"error":{"type":"string","enum":["Indexer health check failed"]},"code":{"type":"string","enum":["INDEXER_HEALTH_CHECK_FAILED"]},"chains":{"type":"array","items":{"type":"object","required":["chainId","status"],"properties":{"chainId":{"type":"integer"},"status":{"type":"string","enum":["ok","syncing","error"]},"lastIndexedBlock":{"type":"integer"},"blocksBehind":{"type":"integer"},"syncProgress":{"type":"number"},"latency":{"type":"number"},"error":{"type":"string","enum":["Indexer chain health check failed"]},"code":{"type":"string","enum":["INDEXER_CHAIN_HEALTH_CHECK_FAILED"]}}}}}}}}}}]},"Entity":{"type":"object","required":["id","name","logo","description","url","socialTwitter","socialYoutube","socialDiscord","socialTelegram","socialGithub","socialDefillama","legalEntityName","riskMethodology","security","termsOfService","licenses","disclaimers","createdAt","updatedAt"],"properties":{"id":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","description":"Stable lowercase slug identifier."},"name":{"type":"string","pattern":"\\S"},"logo":{"oneOf":[{"type":"string","format":"uri","pattern":"^https://"},{"type":"string","maxLength":255,"pattern":"^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$"},{"type":"null"}],"description":"Absolute https URL or a safe asset filename without path separators."},"description":{"type":"string","nullable":true},"url":{"type":"string","format":"uri","pattern":"^[Hh][Tt][Tt][Pp][Ss]://","nullable":true},"socialTwitter":{"type":"string","format":"uri","pattern":"^[Hh][Tt][Tt][Pp][Ss]://","nullable":true},"socialYoutube":{"type":"string","format":"uri","pattern":"^[Hh][Tt][Tt][Pp][Ss]://","nullable":true},"socialDiscord":{"type":"string","format":"uri","pattern":"^[Hh][Tt][Tt][Pp][Ss]://","nullable":true},"socialTelegram":{"type":"string","format":"uri","pattern":"^[Hh][Tt][Tt][Pp][Ss]://","nullable":true},"socialGithub":{"type":"string","format":"uri","pattern":"^[Hh][Tt][Tt][Pp][Ss]://","nullable":true},"socialDefillama":{"type":"string","format":"uri","pattern":"^[Hh][Tt][Tt][Pp][Ss]://","maxLength":2048,"nullable":true},"legalEntityName":{"type":"string","maxLength":16384,"nullable":true},"riskMethodology":{"type":"string","maxLength":16384,"nullable":true,"description":"Markdown, at most 16384 characters, stored trimmed; link destinations must be http(s) or relative."},"security":{"type":"string","maxLength":16384,"nullable":true,"description":"Markdown, at most 16384 characters, stored trimmed; link destinations must be http(s) or relative."},"termsOfService":{"type":"string","maxLength":16384,"nullable":true,"description":"Markdown, at most 16384 characters, stored trimmed; link destinations must be http(s) or relative."},"licenses":{"type":"string","maxLength":16384,"nullable":true,"description":"Markdown, at most 16384 characters, stored trimmed; link destinations must be http(s) or relative."},"disclaimers":{"type":"string","maxLength":16384,"nullable":true,"description":"Markdown, at most 16384 characters, stored trimmed; link destinations must be http(s) or relative."},"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"}]},"suspendedAt":{"type":"string","format":"date-time","nullable":true,"description":"Draft reads only; absent on published reads."},"suspensionReason":{"type":"string","nullable":true,"description":"Draft reads by platform sessions only."},"memberCount":{"type":"integer","minimum":0,"description":"Active (not revoked) members. Present only on `GET /v3/labels/entities?include=counts`."},"adminCount":{"type":"integer","minimum":0,"description":"Active members with the admin role; zero means nobody can manage the team. Present only on `GET /v3/labels/entities?include=counts`."},"addressCount":{"type":"integer","minimum":0,"description":"Registered entity addresses. Present only on `GET /v3/labels/entities?include=counts`."}}},"EntityAddress":{"type":"object","description":"A verified address of a KYBed entity. Addresses are chain-agnostic: one\nregistration proves that the entity owns the address on every\nsupported chain. The address set is the ownership evidence for vault\nclaims; a claim is still verified per vault against that vault's\ngovernor at a pinned block. One address belongs to at most one entity.\n","required":["entityId","address","label"],"properties":{"entityId":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"EIP-55 checksummed verified address in API responses."},"label":{"type":"string","pattern":"\\S","maxLength":512,"nullable":true,"description":"Optional human-readable label. Editable by entity admins and platform admins."}}},"PriceCoverageWorkItem":{"type":"object","description":"One in-scope asset on the token-price-missing work list.","required":["id","chainId","asset","state","since","priority","price","sources","fallback","exposure","review"],"properties":{"id":{"type":"string","description":"Opaque work item ID, `<chainId>:<lowercase token address>`.","example":"1:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"},"chainId":{"type":"integer"},"asset":{"type":"object","required":["address","symbol","decimals"],"properties":{"address":{"type":"string","description":"Lowercase token address."},"symbol":{"type":["string","null"]},"decimals":{"type":"integer"}}},"state":{"type":"string","enum":["unpriced","aging","source-stopped","onchain-only","reviewed","priced"],"description":"`reviewed` while an applied review stands (see `review.kind`). Otherwise, first match wins: `unpriced` (no eligible price within 24 hours, or never), `aging` (newest price older than 12 hours), `source-stopped` (a fresh price exists but a configured source failed recent runs), `onchain-only` (only the on-chain fallback is fresh) and `priced`. Only served prices count: a source set up per token counts only while the token has an enabled entry for it. Listed items are never `priced`; a dismiss or resume response can be.\n"},"since":{"type":["string","null"],"format":"date-time","description":"When the asset entered its state, derived from price and source timestamps; for a reviewed item, the review time. An asset never priced counts from its catalog entry.\n"},"priority":{"type":"integer","description":"4 unpriced, 3 aging, 2 source-stopped, 1 onchain-only, 0 reviewed."},"price":{"type":["object","null"],"description":"Last known served price with its internal source name, of any age: fresh sources by precedence, otherwise the newest stale one.\n","required":["priceUsd","source","timestamp","stale"],"properties":{"priceUsd":{"type":"number","format":"double"},"source":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"stale":{"type":"boolean","description":"True when the price is older than 24 hours."}}},"sources":{"type":"array","description":"Configured and observed price sources. Each orchestrator run stores only the highest-ranked source with a fresh quote for the token (the newest quote when none is fresh), in the write-time merge order erc4626-fixed < erc4626 < defillama < coingecko < pendle < pyth. So a configured source silent for 24 hours, or never seen, is `stopped` or `never` only when the fresh winner ranks below it; it is `outranked` when a higher-ranked source won, and its health is then unknown. A source set up per token that the token has no enabled entry for is `stopped`, whatever the age of its last row: V3 no longer serves it. So is the on-chain fallback of a token whose `onchain` entry is disabled.\n","items":{"type":"object","required":["source","configured","lastObservedAt","lastPriceUsd","status"],"properties":{"source":{"type":"string"},"configured":{"type":"boolean"},"lastObservedAt":{"type":["string","null"],"format":"date-time"},"lastPriceUsd":{"type":["number","null"],"format":"double"},"status":{"type":"string","enum":["fresh","stopped","never","outranked"]}}}},"fallback":{"type":["object","null"],"description":"Latest on-chain fallback outcome, read for up to 26 hours. When `outcome` is `priced`, the fallback stored that price. Otherwise it gives the reason for the first step that failed, for example `out-of-scope` (only adapters of vaults the app does not show could price it), `reference-required` (a fixed or rate-provider adapter without an independent reference) or `assessment-warning` (every candidate adapter has failing checks).\n","required":["outcome","priceUsd","adapter","path","evaluatedAt"],"properties":{"outcome":{"type":"string","enum":["priced","out-of-scope","no-candidate","reference-required","reference-mismatch","conflict","assessment-warning","assessment-stale","rpc-behind","decimals","inventory-truncated","wrapper-unresolved","reorg","error","switched-off"]},"priceUsd":{"type":["number","null"],"format":"double"},"adapter":{"type":["string","null"]},"path":{"type":["array","null"],"items":{"type":"object","required":["kind","token","adapter"],"properties":{"kind":{"type":"string","enum":["unwrap","quote"]},"token":{"type":"string"},"adapter":{"type":["string","null"]}}}},"evaluatedAt":{"type":"string","format":"date-time"}}},"exposure":{"type":"object","required":["vaultCount","vaults","depositsRaw","depositsUsdAtLastPrice"],"properties":{"vaultCount":{"type":"integer"},"vaults":{"type":"array","items":{"type":"object","required":["address","symbol","vaultType","role","isEscrow"],"properties":{"address":{"type":"string"},"symbol":{"type":["string","null"]},"vaultType":{"type":"string","enum":["evk","earn","securitize"]},"role":{"type":"string","enum":["asset","collateral"]},"isEscrow":{"type":"boolean"}}}},"depositsRaw":{"type":"string","description":"Deposits of the asset in in-scope vaults, in base units."},"depositsUsdAtLastPrice":{"type":["number","null"],"format":"double"}}},"review":{"description":"The open review, if any. It stays on the item after it lapses (a later price ruled it out), for context; `state` then shows the computed state instead of `reviewed`.\n","oneOf":[{"$ref":"#/components/schemas/WorkItemReview"},{"type":"null"}]}}},"PriceCoverageWorkItemList":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PriceCoverageWorkItem"}},"meta":{"allOf":[{"$ref":"#/components/schemas/PaginationMeta"},{"type":"object","required":["counts","unreadSources"],"properties":{"unreadSources":{"type":"array","items":{"type":"string"},"description":"Price sources whose token list could not be read. While it is not empty, the list is partial, because entries of these sources are missing from each item's `sources`."},"counts":{"type":"object","description":"Listed items on the requested chains, before the state filter and paging.","required":["unpriced","aging","sourceStopped","onchainOnly","reviewed"],"properties":{"unpriced":{"type":"integer"},"aging":{"type":"integer"},"sourceStopped":{"type":"integer"},"onchainOnly":{"type":"integer"},"reviewed":{"type":"integer"}}}}}]}}},"WorkItemReview":{"type":"object","description":"The applied review that moved a work item off the outstanding list.","required":["changeId","kind","reason","decidedBy","decidedAt"],"properties":{"changeId":{"type":"string","format":"uuid","description":"The applied change that records the review."},"kind":{"oneOf":[{"type":"string","enum":["onchain-only","no-price-source","no-logo-available","no-rule-needed","no-category","no-intrinsic-apy"]},{"type":"null"}],"description":"The recognized terminal state, or null for a plain dismissal (stop looking for now). `onchain-only` or `no-price-source` on `token-price-missing`; `no-logo-available` on `token-logo-missing`; `no-category` on `token-category-missing` and `no-intrinsic-apy` on `token-intrinsic-apy-missing`, which take no null kind; `no-rule-needed` on `asset-newly-exposed`, where a null-kind review lapses when the asset is exposed again after it. A price item with a null-kind review is `reviewed` and lapses like `no-price-source`: any price observed after the decision brings it back. A logo item with a null-kind review stays reviewed until it is resumed.\n"},"reason":{"type":"string"},"decidedBy":{"type":["string","null"],"description":"The platform admin's email, else `<actorKind>:<actorId>`. Null for an API-key reader, which never sees operator identities.\n"},"decidedAt":{"type":"string","format":"date-time"}}},"ChangeActorRef":{"type":"object","description":"Who did it. API-key readers see only their own key's ID; every other actor is shown by kind with a null ID and label.\n","required":["kind","id","label"],"properties":{"kind":{"type":"string","enum":["api-key","platform-admin","admin-secret","system","entity-admin"]},"id":{"type":["string","null"]},"label":{"type":["string","null"],"description":"The platform admin's email or the key's name; null for API-key readers."}}},"ChangeCheck":{"type":"object","description":"A check the server ran itself. A caller's claims are evidence, never checks.","required":["id","outcome","message"],"properties":{"id":{"type":"string"},"outcome":{"type":"string","enum":["pass","fail","warn","skip"]},"message":{"type":"string"},"details":{"type":["object","null"],"additionalProperties":true}}},"ChangePolicyResult":{"type":"object","required":["version","decision","reasons"],"properties":{"version":{"type":"string"},"decision":{"oneOf":[{"type":"string","enum":["apply","propose"]},{"type":"null"}],"description":"Null on rows recorded before the generic policy existed."},"reasons":{"type":"array","items":{"type":"string"}}}},"ChangeEvidence":{"type":"object","description":"Required from API keys and system actors. Reviewers see it; the policy never reads it.","required":["model","promptVersion","runId","sources"],"additionalProperties":true,"properties":{"model":{"type":"string","minLength":1,"maxLength":200},"promptVersion":{"type":"string","minLength":1,"maxLength":200},"runId":{"type":"string","minLength":1,"maxLength":200},"sources":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"string","minLength":1,"maxLength":2000}}}},"ChangeRecord":{"type":"object","description":"One change in any data domain, with its full record.","required":["id","domain","operation","opClass","targetKey","status","reason","value","before","appliedValue","checks","policy","actor","decision","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"domain":{"type":"string"},"operation":{"type":"string"},"opClass":{"description":"What the change does, computed by the server. Geo changes are `tighten` (more people or assets fall under a rule), `loosen` (fewer, including any change that loosens one part) or `update` (nothing anyone is subject to changes, for example the reason).","oneOf":[{"type":"string","enum":["fill","add","replace","update","remove","enable","disable","tighten","loosen","dismiss","resume","revert"]},{"type":"null"}]},"targetKey":{"type":"string"},"status":{"type":"string","enum":["proposed","applied","rejected","superseded","reverted","withdrawn","failed","expired"]},"reason":{"type":"string"},"rationale":{"type":["string","null"]},"value":{"description":"The proposed after-state, in the domain's value shape."},"before":{"description":"The state when the change was submitted."},"appliedValue":{"description":"The state the change wrote, when applied."},"checks":{"type":"array","items":{"$ref":"#/components/schemas/ChangeCheck"}},"policy":{"$ref":"#/components/schemas/ChangePolicyResult"},"evidence":{"type":["object","null"],"additionalProperties":true},"actor":{"$ref":"#/components/schemas/ChangeActorRef"},"decision":{"type":["object","null"],"required":["actor","at","comment"],"properties":{"actor":{"$ref":"#/components/schemas/ChangeActorRef"},"at":{"type":"string","format":"date-time"},"comment":{"type":["string","null"]}}},"expectedVersion":{"type":["string","null"]},"resultingVersion":{"type":["string","null"]},"revertsChangeId":{"type":["string","null"],"format":"uuid"},"supersededByChangeId":{"type":["string","null"],"format":"uuid"},"expiresAt":{"type":["string","null"],"format":"date-time"},"error":{"type":["object","null"],"additionalProperties":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"uploadId":{"type":["string","null"],"format":"uuid","description":"Token images only: the staged upload the change carries."},"sourceProvider":{"type":["string","null"],"description":"Token images only: `coingecko`, `pendle` or `pendle-pt-ring`; null for an upload."},"sourceUrl":{"type":["string","null"],"description":"Token images only."},"sourceEvidence":{"type":["object","null"],"additionalProperties":true,"description":"Token images only: the provider record or the derivation the image came from."},"events":{"type":"array","description":"Present on the detail read only, oldest first.","items":{"$ref":"#/components/schemas/ChangeEvent"}}}},"ChangeEvent":{"type":"object","required":["id","event","status","actor","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"event":{"type":"string","enum":["submitted","approved","rejected","withdrawn","superseded","reverted","failed","expired"]},"status":{"type":"string","enum":["proposed","applied","rejected","superseded","reverted","withdrawn","failed","expired"]},"actor":{"$ref":"#/components/schemas/ChangeActorRef"},"details":{"type":["object","null"],"additionalProperties":true,"description":"What the event recorded. An API-key reader sees only `decision`, `stale`, `kind`, `reason`, `comment` and the related change ids, plus `error` as the generic `{ message: 'The change could not be applied' }`, as on the change itself."},"createdAt":{"type":"string","format":"date-time"}}},"TokenImageTarget":{"type":"object","required":["chainId","address","token","hasLogo","sha256","provenance","proposals","suppression"],"properties":{"chainId":{"type":"integer"},"address":{"type":"string"},"token":{"type":"object","required":["id","symbol","name"],"properties":{"id":{"type":"string"},"symbol":{"type":"string"},"name":{"type":"string"}}},"hasLogo":{"type":"boolean"},"sha256":{"type":["string","null"],"description":"The current managed image digest; send it as `expectedVersion`."},"provenance":{"type":["object","null"],"properties":{"sourceUrl":{"type":["string","null"]},"sourceRepository":{"type":["string","null"]},"updatedBy":{"type":["string","null"],"description":"Omitted for API keys."}}},"proposals":{"type":"array","items":{"$ref":"#/components/schemas/ChangeRecord"}},"suppression":{"description":"The applied removal or dismissal that keeps automatic sourcing off; null when sourcing is open.","oneOf":[{"$ref":"#/components/schemas/ChangeRecord"},{"type":"null"}]}}},"ChangeSubmitRequest":{"type":"object","description":"The generic body for every domain. The server computes the operation class, runs its own checks and decides with the domain's policy.\n","required":["domain","operation","key","expectedVersion","reason"],"additionalProperties":false,"properties":{"domain":{"type":"string","enum":["token-images","price-sources","yield-sources","yield-pools","token-tags","trust-entries","geo"]},"operation":{"type":"string","minLength":1,"maxLength":50},"key":{"type":"string","minLength":1,"maxLength":500,"description":"The domain's target key, in the `keyFormat` that `GET /v3/changes/domains` serves: `<chainId>:<address>` for token images and for every dismissal or resume, `<source>/<chainId>:<address>` for price sources, `<tag>:<ruleType>:<value>` for token tags (rule types `symbols`, `symbolPrefixes`, `symbolContains`, `coingeckoCategories`, and `addresses`, whose value names one token as `<chainId>:<address>` in any case and is stored lowercase)."},"value":{"description":"The proposed after-state in the domain's value shape (`valueSchema` in `GET /v3/changes/domains`); omitted or null for a removal or a dismissal without a kind. A `token-images` `derive` takes `{ source?: { chainId, address } }`."},"expectedVersion":{"type":["string","null"],"description":"The version the caller read; null when the target is empty. A stale version supersedes the change. Read it from `GET /v3/changes/targets/{domain}?key=…` (or `GET /v3/changes/targets/price-sources/{chainId}/{address}` for every source of a token)."},"reason":{"type":"string","minLength":3,"maxLength":1000},"rationale":{"type":["string","null"],"maxLength":4000},"evidence":{"$ref":"#/components/schemas/ChangeEvidence"}}},"ChangeTarget":{"type":"object","required":["domain","targetKey","value","version","proposals","history"],"properties":{"domain":{"type":"string"},"targetKey":{"type":"string","description":"The normalized target key."},"value":{"description":"The current state in the domain's value shape; null while empty."},"version":{"type":["string","null"],"description":"Send as `expectedVersion`; null while the target is empty."},"proposals":{"type":"array","items":{"$ref":"#/components/schemas/ChangeRecord"}},"history":{"type":"array","description":"Decided changes, newest first, at most 50.","items":{"$ref":"#/components/schemas/ChangeRecord"}}}},"PriceSourceTarget":{"type":"object","required":["chainId","address","sources","proposals","review"],"properties":{"chainId":{"type":"integer"},"address":{"type":"string"},"sources":{"type":"array","items":{"type":"object","required":["source","entry","version"],"properties":{"source":{"type":"string","enum":["defillama","pyth","coingecko","erc4626","pendle","onchain"]},"entry":{"type":"object","additionalProperties":true,"description":"The configured entry (identifier, symbol, metadata, enabled)."},"version":{"type":"string","description":"Send as `expectedVersion` to change this entry."}}}},"proposals":{"type":"array","items":{"$ref":"#/components/schemas/ChangeRecord"}},"review":{"oneOf":[{"$ref":"#/components/schemas/WorkItemReview"},{"type":"null"}]}}},"ChangeDecisionResult":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/ChangeRecord"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"ChangeDryRunResult":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","required":["wouldBe","opClass","checks","policy"],"properties":{"wouldBe":{"type":"string","enum":["applied","proposed","superseded"]},"opClass":{"type":"string"},"checks":{"type":"array","items":{"$ref":"#/components/schemas/ChangeCheck"}},"policy":{"$ref":"#/components/schemas/ChangePolicyResult"}}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"ChangeList":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ChangeRecord"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"ChangeDomainDescriptor":{"type":"object","required":["id","title","description","policyVersion","operations","capabilities","keyFormat","valueSchema","workItemType","reviewKinds","checks"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"policyVersion":{"type":"string"},"operations":{"type":"array","items":{"type":"string"}},"capabilities":{"type":["object","null"],"description":"Null for a domain no key may change.","required":["read","propose","write"],"properties":{"read":{"type":"string"},"propose":{"type":"string"},"write":{"type":"string"}}},"keyFormat":{"type":"string"},"valueSchema":{"type":["object","null"],"additionalProperties":true,"description":"JSON Schema of the value."},"workItemType":{"type":["string","null"]},"reviewKinds":{"type":"array","items":{"type":"string"}},"checks":{"type":"array","description":"Every check the domain can run on a change, by the `id` its change records use. A check that does not apply to an entry answers `skip` with the reason and `details.applies: false`.\n","items":{"$ref":"#/components/schemas/ChangeCheckDescriptor"}}}},"ChangeCheckDescriptor":{"type":"object","required":["id","label","purpose"],"properties":{"id":{"type":"string","example":"provider-fresh"},"label":{"type":"string","description":"A short plain name.","example":"Provider price is recent"},"purpose":{"type":"string","description":"One sentence on what the check protects."}}},"GeoExposureEdge":{"type":"object","required":["address","relation"],"properties":{"address":{"type":"string","description":"Lowercase token address."},"relation":{"type":"string","enum":["erc4626","evk-share","escrow-share","earn-share","securitize-share","earn-allocation","pendle-pt","pendle-lp","pendle-sy","pendle-yt"],"description":"How the token is built on the other: in `parents` the other token is what this one wraps; in `reachedVia` the other token wraps this one."}}},"GeoExposureVault":{"type":"object","required":["address","symbol","vaultType","role","isEscrow","productId"],"properties":{"address":{"type":"string"},"symbol":{"type":["string","null"]},"vaultType":{"type":"string","enum":["evk","earn","securitize"]},"role":{"type":"string","enum":["asset","collateral"]},"isEscrow":{"type":"boolean"},"productId":{"type":["string","null"]},"strategies":{"type":"array","items":{"type":"string"},"description":"An Earn vault's strategies, from its supply and withdraw queues."}}},"GeoExposureSignals":{"type":"object","description":"Server-read facts about the token. A read that failed on the last attempt is named in `unavailable`.","properties":{"proxy":{"type":["object","null"],"description":"The proxy the token is (EIP-1967, an EIP-1967 beacon or an EIP-1167 clone); null for a plain contract.","required":["kind","implementation"],"properties":{"kind":{"type":"string","enum":["eip1967","eip1967-beacon","eip1167"]},"implementation":{"type":"string"}}},"coingecko":{"type":["object","null"],"required":["id","categories"],"properties":{"id":{"type":"string"},"categories":{"type":"array","items":{"type":"string"}}}},"unavailable":{"type":"array","items":{"type":"string","enum":["lineage","fingerprints","coingecko"]}}}},"GeoExposureWorkItem":{"type":"object","description":"One asset on the asset-newly-exposed work list.","required":["id","type","chainId","subject","state","since","firstSeenAt","lastSeenAt","priority","vaults","depositsRaw","depositsUsd","parents","reachedVia","fingerprints","signals","signalsCheckedAt","rules","review"],"properties":{"id":{"type":"string","description":"`<chainId>:<lowercase asset address>`, as on every work list."},"type":{"type":"string","enum":["asset-newly-exposed"]},"chainId":{"type":"integer"},"subject":{"type":"object","required":["address","symbol","name","decimals"],"properties":{"address":{"type":"string"},"symbol":{"type":["string","null"]},"name":{"type":["string","null"]},"decimals":{"type":["integer","null"]}}},"state":{"type":"string","enum":["new","baseline","unverified-only","reviewed","covered"],"description":"The first that applies: `covered` (a geo rule applies on the whole chain), `reviewed` (a standing review), `baseline` (exposed when the chain's first sweep ran), `unverified-only` (reached only through vaults the app does not show, by holding or by lineage), `new`. Only `new` is outstanding. An `unverified-only` asset that a shown vault starts to reach becomes `new` on the next sweep."},"since":{"type":"string","format":"date-time","description":"Start of the current exposure."},"firstSeenAt":{"type":"string","format":"date-time"},"lastSeenAt":{"type":"string","format":"date-time"},"priority":{"type":"integer","minimum":0,"description":"One step per order of magnitude of `depositsUsd` ($10 is 1, $10M is 7); 0 when unknown or below $1."},"vaults":{"type":"array","description":"The vaults that hold the asset itself, shown in the app or not.","items":{"$ref":"#/components/schemas/GeoExposureVault"}},"depositsRaw":{"type":"string","description":"Deposits of those vaults in the asset's base units."},"depositsUsd":{"type":["number","null"],"description":"Deposits in USD at the last price, including the tokens built on the asset; null when no price is known."},"parents":{"type":"array","description":"What the asset is built on.","items":{"$ref":"#/components/schemas/GeoExposureEdge"}},"reachedVia":{"type":"array","description":"The exposed tokens built on this asset, through which a vault reaches it.","items":{"$ref":"#/components/schemas/GeoExposureEdge"}},"fingerprints":{"type":"array","description":"The asset's proxy implementation as `implementation:0x…`, empty for a plain contract. A reviewer signal only: tokens that use the same implementation may come from one issuer or from a common template, and no rule covers a token through it. Code hashes are not recorded.","items":{"type":"string","pattern":"^implementation:0x[0-9a-f]{40}$"}},"signals":{"$ref":"#/components/schemas/GeoExposureSignals"},"signalsCheckedAt":{"type":["string","null"],"format":"date-time"},"rules":{"type":"array","description":"Geo rules that cover the asset; on a `covered` item one of them applies on the whole chain, otherwise each applies only inside one product or vault.","items":{"type":"object","required":["policyId","policyType","countries","productId","vaultAddress","match"],"properties":{"policyId":{"type":"string"},"policyType":{"type":"string","enum":["block","restrict"]},"countries":{"type":"array","items":{"type":"string"}},"productId":{"type":["string","null"]},"vaultAddress":{"type":["string","null"]},"match":{"type":"string","enum":["address","symbol","name","lineage"]}}}},"review":{"oneOf":[{"$ref":"#/components/schemas/WorkItemReview"},{"type":"null"}]},"coverage":{"$ref":"#/components/schemas/AssetCoverage"}}},"AssetCoverageProposal":{"description":"The oldest open proposal that addresses the piece, a proposed \"none\" review included; null when none does.","oneOf":[{"type":"object","required":["changeId"],"properties":{"changeId":{"type":"string","format":"uuid"}}},{"type":"null"}]},"AssetCoverageReview":{"description":"The standing review that settles or pauses the piece; null when none does.","oneOf":[{"type":"object","required":["changeId","kind"],"properties":{"changeId":{"type":"string","format":"uuid"},"kind":{"type":["string","null"],"description":"The review kind; null for a stop-for-now review, which pauses the piece."}}},{"type":"null"}]},"AssetCoveragePiece":{"type":"object","required":["state","settled","need","review","proposal"],"properties":{"settled":{"type":"boolean","description":"The piece has its data, an automatic match, or an applied \"none\" review. A settled piece is never a need."},"need":{"type":"boolean","description":"Not settled, no open proposal, and the state is neither `out-of-scope` nor `paused`. The `needs` filter matches it."},"review":{"$ref":"#/components/schemas/AssetCoverageReview"},"proposal":{"$ref":"#/components/schemas/AssetCoverageProposal"}}},"AssetCoverage":{"type":"object","description":"The onboarding checklist of one exposed asset: logo, price, category (`tags`), intrinsic APY (`yield`) and geo. Logo, price, tags and yield apply only to assets shown in the app, the scope of the logo and price lists; any other asset has them as `out-of-scope`. Geo applies to every exposed asset. `paused` is a standing review without a kind (stop for now). Every piece is read in a batch for the page.","required":["logo","price","yield","tags","geo"],"properties":{"logo":{"allOf":[{"$ref":"#/components/schemas/AssetCoveragePiece"},{"type":"object","properties":{"state":{"type":"string","enum":["present","none-reviewed","paused","missing","out-of-scope"],"description":"Settled: `present` (a managed image) or `none-reviewed` (an applied `no-logo-available` review)."}}}]},"price":{"allOf":[{"$ref":"#/components/schemas/AssetCoveragePiece"},{"type":"object","properties":{"state":{"type":"string","enum":["market","onchain-only-reviewed","none-reviewed","paused","onchain-only","aging","source-stopped","unpriced","out-of-scope"],"description":"Settled: `market` (a fresh market price), `onchain-only-reviewed` (an `onchain-only` review) or `none-reviewed` (a `no-price-source` review). The `token-price-missing` states `onchain-only`, `aging`, `source-stopped` and `unpriced` without a standing review are needs."}}}]},"yield":{"allOf":[{"$ref":"#/components/schemas/AssetCoveragePiece"},{"type":"object","required":["sources"],"properties":{"state":{"type":"string","enum":["configured","none-reviewed","not-applicable","source-stopped","missing","out-of-scope"],"description":"Intrinsic APY cannot be inferred, so every asset in scope needs a decision. Settled: `configured` (a provider wrote a non-zero intrinsic APY for the asset in the last 7 days, or an enabled entry exists and any provider wrote a row, zero included, in that time), `none-reviewed` (an applied `no-intrinsic-apy` review) or `not-applicable` (an Euler vault share: EVK, Earn, escrow or Securitize). `source-stopped` is a need: an enabled entry with no row for the asset in the last 7 days, a new entry included until its source first runs, or an asset whose only rows are older than 7 days. Only served rows count: a provider set up per token counts only while the asset has an enabled entry for it, and a DefiLlama pool row only while the enabled pool mapping names its pool."},"sources":{"type":"array","description":"`yield-source`: an enabled yield-source entry; `yield-pool`: an enabled DefiLlama pool mapping; `provider`: a provider serves a non-zero intrinsic APY now.","items":{"type":"string","enum":["yield-source","yield-pool","provider"]}}}}]},"tags":{"allOf":[{"$ref":"#/components/schemas/AssetCoveragePiece"},{"type":"object","required":["tags"],"properties":{"state":{"type":"string","enum":["tagged","none-reviewed","untagged","out-of-scope"],"description":"Settled: `tagged` (any rule tags the token: a CoinGecko category, a symbol rule or an address rule) or `none-reviewed` (an applied `no-category` review). The proposal is a matching symbol, prefix, contains or address rule, or a proposed `no-category` review; category rules are not evaluated here."},"tags":{"type":"array","description":"The tags `/v3/tokens` derives for the token.","items":{"type":"string"}}}}]},"geo":{"allOf":[{"$ref":"#/components/schemas/AssetCoveragePiece"},{"type":"object","properties":{"state":{"type":"string","enum":["covered","none-reviewed","paused","outstanding"],"description":"Settled: `covered` (a geo rule applies on the whole chain) or `none-reviewed` (an applied `no-rule-needed` review). The proposal is a `geo` rule that names the asset address, or a proposed review of the asset."}}}]}}},"GeoExposureWorkItemList":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GeoExposureWorkItem"}},"meta":{"allOf":[{"$ref":"#/components/schemas/PaginationMeta"},{"type":"object","required":["counts"],"properties":{"counts":{"type":"object","description":"Items per state on the requested chains, before the state filter and paging.","required":["new","baseline","unverifiedOnly","reviewed","covered"],"properties":{"new":{"type":"integer"},"baseline":{"type":"integer"},"unverifiedOnly":{"type":"integer","description":"Items in the `unverified-only` state."},"reviewed":{"type":"integer"},"covered":{"type":"integer"}}}}}]}}},"WorkItemDismissRequest":{"type":"object","additionalProperties":false,"required":["kind","reason"],"properties":{"kind":{"oneOf":[{"type":"string","enum":["onchain-only","no-price-source","no-logo-available","no-rule-needed","no-category","no-intrinsic-apy"]},{"type":"null"}],"description":"The work list's recognized terminal state, or null to stop for now. `no-rule-needed` is the `asset-newly-exposed` kind. `no-category` (`token-category-missing`) and `no-intrinsic-apy` (`token-intrinsic-apy-missing`) take no null."},"reason":{"type":"string","minLength":3,"maxLength":1000},"evidence":{"$ref":"#/components/schemas/ChangeEvidence"}}},"TokenLogoWorkItem":{"type":"object","description":"One in-scope asset on the token-logo-missing work list.","required":["id","chainId","address","symbol","name","workerOutcome","workerProvider","lastAttemptAt","nextRetryAt","review"],"properties":{"id":{"type":"string","description":"Opaque work item ID, `<chainId>:<lowercase token address>`, as on every work list.","example":"1:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"},"chainId":{"type":"integer"},"address":{"type":"string","description":"Lowercase token address."},"symbol":{"type":"string"},"name":{"type":"string"},"workerOutcome":{"type":["string","null"],"description":"The logo worker's latest outcome for the token: `no_candidate`, `invalid_source`, `provider_failure`, `created` or `already_present`. `shadow_candidate` is a legacy value the worker no longer writes; a token that still shows it is retried at `nextRetryAt`, and that attempt replaces it."},"workerProvider":{"type":["string","null"]},"lastAttemptAt":{"type":["string","null"],"format":"date-time"},"nextRetryAt":{"type":["string","null"],"format":"date-time"},"review":{"description":"Null on the outstanding list; the applied dismissal on the reviewed list.","oneOf":[{"$ref":"#/components/schemas/WorkItemReview"},{"type":"null"}]}}},"TokenLogoWorkItemList":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TokenLogoWorkItem"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"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."}}},"Chain":{"type":"object","required":["id","name","labeling","logoURI"],"properties":{"id":{"type":"integer"},"name":{"type":"string"},"status":{"type":"string","nullable":true,"description":"Optional chain health status."},"labeling":{"type":"boolean","description":"The chain accepts products, vault labels, and geo policies. Every chain this route lists does; a client whose own chain list is wider offers only rows with `labeling: true` in its pickers. A label write naming a chain the deployment does not serve answers 422 with a `details.issues[]` entry whose `path` is `[\"chainId\"]`."},"logoURI":{"type":"string","description":"Chain logo URL, `/v3/images/chains/{chainId}` on the V3 image host. It depends on the chain id only, so a client can build it for chains this route does not list; keep a bundled logo as the fallback."}}},"ProtocolStats":{"type":"object","description":"Lending aggregates across the selected chains, with Earn TVL reported separately.","properties":{"totalSuppliedUsd":{"type":"number","description":"Total supplied in USD: the `cash + totalBorrows` of every counted EVK vault (escrow vaults included) plus the deposits of every counted Securitize vault (its shares outstanding, one share to one asset), valued in USD. Earn vault assets are excluded."},"totalBorrowedUsd":{"type":"number","description":"Total borrows in USD of the counted EVK vaults, all borrows counted. Securitize and escrow vaults lend nothing."},"earnTotalAssetsUsd":{"type":"number","description":"Total assets in USD of every counted Earn vault. Reported separately and not included in `totalSuppliedUsd` or `utilization`, since Earn deposits sit in EVK vaults."},"utilization":{"type":"number","description":"Lending utilization, computed as `totalBorrowedUsd / totalSuppliedUsd`. Earn assets are excluded from the denominator."},"vaultCount":{"type":"integer","description":"The vaults whose value is in the totals: counted EVK, escrow, Securitize and Earn vaults, empty ones included. Vaults left out (not shown, hidden by Layer 1, not evaluated yet, without a usable price, or read too long ago) are not in it."},"chainCount":{"type":"integer"}}},"ProtocolStatsExcludedTotals":{"type":"object","required":["vaultCount","suppliedUsd","borrowedUsd","earnTotalAssetsUsd"],"description":"USD sums cover only the vaults among them that have a usable price.","properties":{"vaultCount":{"type":"integer","minimum":0},"suppliedUsd":{"type":"number","description":"EVK and Securitize supply these vaults would add to `totalSuppliedUsd`."},"borrowedUsd":{"type":"number"},"earnTotalAssetsUsd":{"type":"number","description":"Earn assets these vaults would add to `earnTotalAssetsUsd`."}}},"ProtocolStatsExcludedVaults":{"type":"object","required":["hiddenByLayer1","notShown","notEvaluated","unpriced","stale"],"description":"Factory vaults the totals leave out on the included chains, by reason. Only vaults Layer 1 hides carry USD, valued from the same snapshot and price reads as the counted vaults; the others are counted only.","properties":{"hiddenByLayer1":{"allOf":[{"$ref":"#/components/schemas/ProtocolStatsExcludedTotals"}],"description":"Vaults Layer 1 checks hide (`config-failed`, `config-suspended`, or a failed Layer 1 behind a Layer 2 hide). An escrow or Securitize vault a counted vault accepts as collateral keeps counting even when Layer 1 hides it. A hidden vault without a stored balance snapshot adds no USD."},"notShown":{"type":"object","required":["vaultCount"],"description":"Vaults the app does not show for any other reason: pending review or unclaimed, hidden by a platform admin or a curator verdict, delisted, or collateral no counted vault accepts.","properties":{"vaultCount":{"type":"integer","minimum":0}}},"notEvaluated":{"type":"object","required":["vaultCount"],"description":"Vaults without a Layer 1 verdict yet.","properties":{"vaultCount":{"type":"integer","minimum":0}}},"unpriced":{"type":"object","required":["vaultCount"],"description":"Counted vaults holding a balance without a usable price. Their USD is unknown.","properties":{"vaultCount":{"type":"integer","minimum":0}}},"stale":{"type":"object","required":["vaultCount"],"description":"Counted vaults whose balance was read more than 15 minutes ago.","properties":{"vaultCount":{"type":"integer","minimum":0}}}}},"ProtocolStatsMeta":{"allOf":[{"$ref":"#/components/schemas/PaginationMeta"},{"type":"object","required":["calculationTimestamp","complete","includedChainIds","incompleteChainIds"],"properties":{"calculationTimestamp":{"type":"string","format":"date-time","description":"Time at which chain availability and aggregates were evaluated."},"complete":{"type":"boolean","description":"True when every chain in the requested scope with a counted vault contributed from fresh source state, with every counted vault's balance read. A vault without a usable price or with a balance read too long ago does not make its chain incomplete, however much of the chain it holds: it is left out of the totals and counted in `excludedVaults`. A chain is left out only when none of its counted vaults has a fresh balance (`stale_source`)."},"includedChainIds":{"type":"array","items":{"type":"integer"},"description":"Requested chains with counted vaults whose values contribute to the returned aggregate."},"incompleteChainIds":{"type":"array","items":{"type":"integer"},"description":"Requested chains with incomplete membership, unread balances, or stale source state. A chain with only unread balances may still contribute the vaults it read."},"incompleteChainReasons":{"type":"array","description":"Reasons for each incomplete chain in the requested scope. Empty for a complete response.","items":{"type":"object","required":["chainId","reasons"],"properties":{"chainId":{"type":"integer"},"reasons":{"type":"array","nullable":true,"description":"Null when the cached snapshot lacks reason provenance. `membership`: a counted vault is missing from the indexed inventory. `valuation`: a counted vault's balance could not be read; the chain still contributes the vaults it read. `stale_source`: none of the chain's counted vaults has a balance read in the last 15 minutes, priced or not, so nothing on the chain was observed. Every reason but `valuation` leaves the chain out of the totals.","items":{"type":"string","enum":["membership","valuation","stale_source"]}}}}},"excludedVaults":{"nullable":true,"description":"What the totals leave out and why, summed over the included chains. Null when an included chain's serving snapshot was written before this was recorded.","allOf":[{"$ref":"#/components/schemas/ProtocolStatsExcludedVaults"}]}}}]},"HistoryInterval":{"type":"object","required":["from","to"],"description":"Inclusive UTC bucket-start bounds. A single absent bucket has equal from/to values.","properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"}}},"HistoryMetricCoverage":{"type":"object","required":["status","availableBuckets","partialBuckets","missingBuckets","missingIntervals","partialIntervals"],"properties":{"status":{"type":"string","enum":["complete","partial","missing","not_applicable"]},"availableBuckets":{"type":"integer","minimum":0,"description":"Distinct elapsed requested buckets with a finite value, including partial aggregate values and observed zero."},"partialBuckets":{"type":"integer","minimum":0,"description":"Available buckets whose aggregate covers only part of the requested chain scope."},"missingBuckets":{"type":"integer","minimum":0},"missingIntervals":{"type":"array","items":{"$ref":"#/components/schemas/HistoryInterval"}},"partialIntervals":{"type":"array","items":{"$ref":"#/components/schemas/HistoryInterval"}}}},"HistoryCoverage":{"type":"object","required":["scope","status","requestedBuckets","evaluatedBuckets","returnedBuckets","futureBuckets","firstAvailable","lastAvailable","provisionalBucket","missingIntervals","metrics"],"description":"Availability within the requested range, not proof of historical membership, vault inception, source retention, recoverability, or price accuracy. Leading and trailing absent buckets are included. Future buckets are excluded from evaluation; the current bucket is provisional. Missing fields and read failures remain unavailable without asserting their root cause.","properties":{"scope":{"type":"string","enum":["requested-range"]},"status":{"type":"string","enum":["complete","partial","missing","not_applicable"],"description":"Complete requires all evaluated buckets and all reported metrics. Missing means no returned buckets. Not applicable means the range is entirely in the future."},"requestedBuckets":{"type":"integer","minimum":1},"evaluatedBuckets":{"type":"integer","minimum":0},"returnedBuckets":{"type":"integer","minimum":0},"futureBuckets":{"type":"integer","minimum":0},"firstAvailable":{"type":"string","format":"date-time","nullable":true,"description":"First returned bucket within the evaluated range, not the earliest retained source date."},"lastAvailable":{"type":"string","format":"date-time","nullable":true},"provisionalBucket":{"type":"string","format":"date-time","nullable":true},"missingIntervals":{"type":"array","description":"Buckets absent from the response regardless of metric coverage.","items":{"$ref":"#/components/schemas/HistoryInterval"}},"metrics":{"type":"object","description":"Coverage keyed by public metric name. Available and missing bucket counts sum to evaluatedBuckets; partialBuckets is a subset of availableBuckets.","additionalProperties":{"$ref":"#/components/schemas/HistoryMetricCoverage"}}}},"ProtocolHistoryPointCoverage":{"type":"object","required":["complete","includedChainIds","missingChainIds"],"description":"Coverage of the stored aggregate. Partially reconstructed chain rows can remain incomplete even when every requested chain has a stored row. Nullable Earn USD is reported separately; complete coverage does not certify every underlying historical source.","properties":{"complete":{"type":"boolean"},"includedChainIds":{"type":"array","items":{"type":"integer"}},"missingChainIds":{"type":"array","nullable":true,"items":{"type":"integer"},"description":"Requested chain IDs without a row. Null for incomplete unfiltered days because the historical expected chain universe is not persisted."}}},"ProtocolStatsHistoryPoint":{"type":"object","required":["timestamp","totalSuppliedUsd","totalBorrowedUsd","availableUsd","utilization","vaultCount","earnTotalAssetsUsd","coverage"],"properties":{"coverage":{"$ref":"#/components/schemas/ProtocolHistoryPointCoverage"},"timestamp":{"type":"string","format":"date-time","description":"UTC start of the represented day."},"totalSuppliedUsd":{"type":"number","description":"Supplied assets of the counted vaults, valued with bucket-aligned prices: EVK (escrow included) and, on rows written during the day, Securitize. A vault without a price that day is left out. Days before this rule shipped counted the published label set."},"totalBorrowedUsd":{"type":"number","description":"Borrows of the counted EVK vaults, valued with bucket-aligned prices."},"availableUsd":{"type":"number","description":"`totalSuppliedUsd - totalBorrowedUsd`."},"utilization":{"type":"number","description":"`totalBorrowedUsd / totalSuppliedUsd`, or zero when supplied is zero."},"vaultCount":{"type":"integer","description":"Counted EVK vaults with a value that day, escrow and empty vaults included. Earn and Securitize vaults are excluded so the definition is stable across captured and rebuilt rows. Days before this rule shipped counted the published label set."},"earnTotalAssetsUsd":{"type":"number","nullable":true,"description":"Current daily writes include Earn TVL; historical backfill rows are null because retained Earn history cannot reconstruct truthful USD values."}}},"ProtocolStatsChainHistory":{"type":"object","required":["chainId","history","coverage"],"description":"Retained history for one chain, restricted to the same eligible days as the aggregate. Explicitly selected chains without rows have empty history.","properties":{"chainId":{"type":"integer"},"history":{"type":"array","items":{"$ref":"#/components/schemas/ProtocolStatsHistoryPoint"}},"coverage":{"$ref":"#/components/schemas/HistoryCoverage"}}},"ProtocolStatsHistoryMeta":{"type":"object","required":["timestamp","from","to","resolution"],"properties":{"coverage":{"$ref":"#/components/schemas/HistoryCoverage"},"includePartial":{"type":"boolean","description":"Whether incomplete retained chain aggregates may appear in history."},"groupBy":{"type":"string","enum":["chain"],"description":"Present only when per-chain history is requested."},"timestamp":{"type":"string","format":"date-time"},"from":{"type":"integer","description":"Effective inclusive range start in Unix seconds."},"to":{"type":"integer","description":"Effective inclusive range end in Unix seconds."},"resolution":{"type":"string","enum":["1d"]},"chainId":{"type":"string","description":"Canonical comma-separated selected chain IDs when filtering."}}},"FlowsHistoryPointCoverage":{"type":"object","required":["complete","includedChainIds","missingChainIds"],"description":"Coverage of the selected configured chains for this day. Complete requires every selected chain row and all five category USD values; it does not assert complete historical event retention.","properties":{"complete":{"type":"boolean"},"includedChainIds":{"type":"array","items":{"type":"integer"}},"missingChainIds":{"type":"array","items":{"type":"integer"}}}},"FlowsHistoryPoint":{"type":"object","required":["timestamp","depositsUsd","withdrawalsUsd","borrowsUsd","repaysUsd","liquidationsUsd","netSuppliedUsd","updatedAt","coverage"],"properties":{"timestamp":{"type":"string","format":"date-time","description":"UTC start of the represented day."},"depositsUsd":{"type":"number","nullable":true,"minimum":0,"description":"Sum of retained EVK deposit asset amounts valued at event time, or null when unavailable."},"withdrawalsUsd":{"type":"number","nullable":true,"minimum":0,"description":"Sum of retained EVK withdrawal asset amounts valued at event time, or null when unavailable."},"borrowsUsd":{"type":"number","nullable":true,"minimum":0,"description":"Sum of retained EVK borrow asset amounts valued at event time, or null when unavailable."},"repaysUsd":{"type":"number","nullable":true,"minimum":0,"description":"Sum of retained EVK repay asset amounts valued at event time, or null when unavailable."},"liquidationsUsd":{"type":"number","nullable":true,"minimum":0,"description":"Sum of retained EVK liquidation repay asset amounts valued at event time, or null when unavailable."},"netSuppliedUsd":{"type":"number","nullable":true,"description":"DepositsUsd minus withdrawalsUsd; null if either input is unavailable. Borrows, repays and liquidations do not enter this formula. Negative values represent net withdrawals."},"updatedAt":{"type":"string","format":"date-time","nullable":true,"description":"Oldest rollup calculation time across the selected chain rows, or null when a selected row or its calculation time is unavailable."},"coverage":{"$ref":"#/components/schemas/FlowsHistoryPointCoverage"}}},"FlowsChainHistory":{"type":"object","required":["chainId","history","coverage"],"properties":{"chainId":{"type":"integer"},"history":{"type":"array","items":{"$ref":"#/components/schemas/FlowsHistoryPoint"}},"coverage":{"$ref":"#/components/schemas/HistoryCoverage"}}},"FlowsHistoryMeta":{"type":"object","required":["timestamp","chainId","resolution","from","to","coverage"],"properties":{"timestamp":{"type":"string","format":"date-time"},"chainId":{"type":"string","description":"Canonical comma-separated selected configured chain IDs, including the configured scope when no filter is supplied."},"vault":{"type":"string","pattern":"^0x[a-f0-9]{40}$","description":"Lowercase vault filter, present only for a vault-scoped request."},"resolution":{"type":"string","enum":["1d"]},"from":{"type":"integer","description":"Effective inclusive range start in Unix seconds."},"to":{"type":"integer","description":"Effective inclusive range end in Unix seconds."},"groupBy":{"type":"string","enum":["chain"]},"coverage":{"$ref":"#/components/schemas/HistoryCoverage"}}},"ChainStats":{"allOf":[{"$ref":"#/components/schemas/ProtocolStats"},{"type":"object","required":["chainId"],"properties":{"chainId":{"type":"integer","description":"Chain ID for the returned chain-scoped aggregate."}}}]},"AssetRef":{"type":"object","properties":{"address":{"type":"string"},"symbol":{"type":"string"},"decimals":{"type":"integer"},"name":{"type":"string","nullable":true}}},"OraclePriceRaw":{"type":"object","description":"Exact oracle quote values returned by contracts, represented as raw integer strings in the oracle unit-of-account scale.","properties":{"queryFailure":{"type":"boolean"},"queryFailureReason":{"type":"string"},"amountIn":{"type":"string","description":"Raw input amount passed to the oracle."},"amountOutMid":{"type":"string","description":"Raw midpoint oracle output amount."},"amountOutBid":{"type":"string","description":"Raw bid-side oracle output amount."},"amountOutAsk":{"type":"string","description":"Raw ask-side oracle output amount."},"timestamp":{"type":"string","format":"date-time"}}},"VaultFees":{"type":"object","properties":{"interestFee":{"type":"number","description":"Interest fee ratio number."},"accumulatedFeesShares":{"type":"string","description":"Raw accumulated fee shares as a bigint string."},"accumulatedFeesAssets":{"type":"string","description":"Raw accumulated fee assets as a bigint string."},"governorFeeReceiver":{"type":"string"},"protocolFeeReceiver":{"type":"string"},"protocolFeeShare":{"type":"number","description":"Protocol fee share ratio number."}}},"VaultHookedOperations":{"type":"object","properties":{"deposit":{"type":"boolean"},"mint":{"type":"boolean"},"withdraw":{"type":"boolean"},"redeem":{"type":"boolean"},"transfer":{"type":"boolean"},"skim":{"type":"boolean"},"borrow":{"type":"boolean"},"repay":{"type":"boolean"},"repayWithShares":{"type":"boolean"},"pullDebt":{"type":"boolean"},"convertFees":{"type":"boolean"},"liquidate":{"type":"boolean"},"flashloan":{"type":"boolean"},"touch":{"type":"boolean"},"vaultStatusCheck":{"type":"boolean"}}},"VaultHooks":{"type":"object","properties":{"hookedOperations":{"$ref":"#/components/schemas/VaultHookedOperations"},"hookTarget":{"type":"string"}}},"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."}}},"VaultLiquidation":{"type":"object","properties":{"maxLiquidationDiscount":{"type":"number"},"liquidationCoolOffTime":{"type":"integer"},"socializeDebt":{"type":"boolean"}}},"LiquidationValuation":{"type":"object","required":["status","source"],"properties":{"status":{"type":"string","enum":["available","partial","unavailable"],"description":"Available when both liquidation legs have USD values, partial when one does, and unavailable when neither does."},"source":{"type":"string","enum":["historical-price-snapshots","historical-protocol-oracle"],"description":"Oracle USD enrichment is disabled by default and requires the LIQUIDATION_ORACLE_USD_ENABLED server rollout gate. Historical protocol oracle indicates that at least one missing USD leg uses the liquidation-block oracle quote. Token-denominated quotes require a USD snapshot from the preceding 15 minutes with no future block. Existing snapshot-valued legs are preserved."},"reason":{"type":"string","description":"Present when valuation is partial or unavailable."}}},"LiquidationUnitOfAccountValuation":{"type":"object","required":["source","unitOfAccount","unitOfAccountDecimals","repayValue","collateralValue","bonusValue","blockNumber"],"properties":{"source":{"type":"string","enum":["historical-protocol-oracle"]},"unitOfAccount":{"type":"string","description":"Debt vault unit-of-account address used by the protocol oracle."},"unitOfAccountDecimals":{"type":"integer","nullable":true,"minimum":0,"maximum":255},"repayValue":{"type":"string","pattern":"^\\d+$","description":"Debt repaid, quoted into the unit of account at the liquidation block."},"collateralValue":{"type":"string","pattern":"^\\d+$","description":"Seized collateral-vault shares, quoted into the unit of account at the liquidation block."},"bonusValue":{"type":"string","pattern":"^-?\\d+$","description":"Collateral value minus repay value in raw unit-of-account units."},"blockNumber":{"type":"string","pattern":"^\\d+$"}}},"LiquidationEvent":{"type":"object","required":["chainId","vault","violator","liquidator","collateral","repayAssets","yieldBalance","debtAsset","debtAssetDecimals","debtAssetPriceUsd","repayAssetsUsd","collateralAsset","collateralAssetDecimals","collateralAssetPriceUsd","collateralAssets","collateralAssetsUsd","bonusUsd","valuation","unitOfAccountValuation","blockNumber","txHash","timestamp"],"properties":{"chainId":{"type":"integer"},"vault":{"type":"string","description":"Debt vault address."},"violator":{"type":"string"},"liquidator":{"type":"string"},"collateral":{"type":"string","description":"Collateral vault address."},"repayAssets":{"type":"string","description":"Debt repaid in raw underlying units of the debt vault asset."},"yieldBalance":{"type":"string","description":"Collateral seized in raw collateral-vault share units."},"debtAsset":{"type":"string","nullable":true,"description":"Underlying token address of the debt vault at the liquidation block."},"debtAssetDecimals":{"type":"integer","nullable":true},"debtAssetPriceUsd":{"type":"number","nullable":true,"minimum":0,"description":"Historical debt-asset USD price at or before the event time and block, never a current-price fallback."},"repayAssetsUsd":{"type":"number","nullable":true,"minimum":0},"collateralAsset":{"type":"string","nullable":true,"description":"Underlying token address of the collateral vault at the liquidation block."},"collateralAssetDecimals":{"type":"integer","nullable":true},"collateralAssetPriceUsd":{"type":"number","nullable":true,"minimum":0,"description":"Historical collateral-asset USD price at or before the event time and block, never a current-price fallback."},"collateralAssets":{"type":"string","nullable":true,"description":"Seized collateral shares converted to raw underlying units from the first indexed collateral VaultStatus after the liquidation log in the same transaction, using EVK virtual-deposit and rounding semantics. Null when that transaction-ordered status is unavailable."},"collateralAssetsUsd":{"type":"number","nullable":true,"minimum":0,"description":"USD value of seized collateral. A liquidation-block oracle quote can value the seized shares when underlying token metadata or share conversion is unavailable; those native fields remain null."},"bonusUsd":{"type":"number","nullable":true,"description":"Collateral assets USD minus repaid debt USD. Null unless both values are available."},"valuation":{"$ref":"#/components/schemas/LiquidationValuation"},"unitOfAccountValuation":{"allOf":[{"$ref":"#/components/schemas/LiquidationUnitOfAccountValuation"}],"nullable":true,"description":"Historical liquidation-block protocol-oracle quote used for fallback valuation. Retained when oracle enrichment completes the USD valuation. Null when no historical RPC quote was requested or available."},"blockNumber":{"type":"string"},"txHash":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"VaultInterestRates":{"type":"object","description":"Contract interest-rate values formatted as decimal strings in fraction units, not public percent APY numbers.","properties":{"borrowSPY":{"type":"string","description":"Borrow rate per second as an exact decimal string."},"borrowAPY":{"type":"string","description":"Borrow APY as an exact decimal fraction string; `1` means 100%."},"supplyAPY":{"type":"string","description":"Supply APY as an exact decimal fraction string; `1` means 100%."}}},"VaultInterestRateModel":{"type":"object","properties":{"address":{"type":"string"},"type":{"type":"string","enum":["unknown","kink","adaptive_curve","kinky","fixed_cyclical_binary","fixed_cyclical_binary_monthly"]},"data":{"type":"object","nullable":true,"additionalProperties":{"type":"string"}}}},"SubAccount":{"type":"object","required":["chainId","owner","addressPrefix","blockNumber","timestamp"],"properties":{"chainId":{"type":"integer"},"owner":{"type":"string"},"addressPrefix":{"type":"string"},"blockNumber":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"OracleAdapterPythDetail":{"type":"object","properties":{"pyth":{"type":"string"},"base":{"type":"string"},"quote":{"type":"string"},"feedId":{"type":"string"},"maxStaleness":{"type":"string"},"maxConfWidth":{"type":"string"}}},"OracleAdapterChainlinkDetail":{"type":"object","properties":{"oracle":{"type":"string"}}},"OracleDetailedInfo":{"type":"object","properties":{"oracle":{"type":"string"},"name":{"type":"string"},"oracleInfo":{"type":"string"}}},"OracleAdapterEntry":{"type":"object","properties":{"oracle":{"type":"string"},"name":{"type":"string"},"base":{"type":"string"},"quote":{"type":"string"},"pythDetail":{"allOf":[{"$ref":"#/components/schemas/OracleAdapterPythDetail"}],"nullable":true},"chainlinkDetail":{"allOf":[{"$ref":"#/components/schemas/OracleAdapterChainlinkDetail"}],"nullable":true}}},"OracleAdapterEvaluationRequest":{"type":"object","additionalProperties":false,"required":["chainId","address"],"properties":{"chainId":{"type":"integer","minimum":1},"address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"The adapter contract to evaluate; it need not be known to the registry."}}},"OracleAdapterEvaluationLeg":{"type":"object","additionalProperties":false,"required":["address","recognized","source"],"properties":{"address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"recognized":{"type":"boolean","nullable":true},"source":{"type":"string","enum":["stored","evaluated","unknown"],"description":"`stored`: the registry already held the leg's verdict. `evaluated`: the leg was judged in this pass, at the same block. `unknown`: neither (deeper than two levels, or a cycle); the parent's cross-legs rule stays unknown."}}},"OracleAdapterEvaluation":{"description":"An evaluate-only verdict: the stored assessment's fields (`inActiveRoute` is false; `lastCheckedAt`, `schedulingTier` and `nextCheckAt` are null, since nothing is recorded) plus `persisted`, the pinned block hash and the legs judged on the way.","type":"object","additionalProperties":false,"required":["chainId","address","recognized","checksStatus","reason","inActiveRoute","adapterClass","label","provider","methodology","model","config","findings","summary","policyId","policyVersion","blockNumber","evaluatedAt","lastCheckedAt","schedulingTier","nextCheckAt","persisted","blockHash","quoteTolerant","legs"],"properties":{"chainId":{"type":"integer","minimum":1},"address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"recognized":{"type":"boolean"},"checksStatus":{"type":"string","enum":["positive","warning","negative"],"nullable":true,"description":"Health verdict of a recognized adapter. Always null for unrecognized adapters: identity and health are orthogonal, and no health claim is made about a contract whose getters are untrusted."},"reason":{"type":"string","nullable":true},"inActiveRoute":{"type":"boolean","description":"True when a current router configuration of a vault-backed router routes through this adapter, directly or as a cross-adapter leg. Refreshed hourly by the universe reconciler."},"adapterClass":{"type":"string","enum":["ChainlinkOracle","ChainlinkInfrequentOracle","ChainlinkInfrequentNanosecondOracle","ChainlinkInfrequentXStocksOracle","ChronicleOracle","CrossAdapter","CurveEMAOracle","FixedRateOracle","IdleTranchesOracle","LidoOracle","LidoFundamentalOracle","PendleOracle","PendleUniversalOracle","PythOracle","RateProviderOracle","RedstoneCoreOracle","SwaapSafeguardOracle","UniswapV3Oracle"],"nullable":true},"label":{"type":"string","nullable":true},"provider":{"type":"string","nullable":true},"methodology":{"type":"string","enum":["Market Price","Market Price (Bolt)","Smart Value Recapture","Exchange Rate","TWAP","Custom","Unknown"],"nullable":true},"model":{"type":"string","enum":["Push","Pull","Unknown"],"nullable":true},"config":{"type":"object","additionalProperties":true,"nullable":true},"findings":{"type":"array","items":{"$ref":"#/components/schemas/OracleAdapterAssessmentFinding"}},"summary":{"allOf":[{"$ref":"#/components/schemas/OracleAdapterAssessmentSummary"}],"nullable":true},"policyId":{"type":"string","enum":["euler-oracle-adapter"],"nullable":true},"policyVersion":{"type":"integer","minimum":1,"nullable":true},"blockNumber":{"type":"string","pattern":"^\\d+$","nullable":true},"evaluatedAt":{"type":"string","format":"date-time","nullable":true},"lastCheckedAt":{"type":"string","format":"date-time","nullable":true},"schedulingTier":{"type":"string","enum":["active","background","static"],"nullable":true,"description":"Which periodic sweep re-checks the adapter: `active` (hourly) when a vault in the active tier prices through it (current router pairs, nested routers expanded, cross legs followed), `background` (daily) otherwise. A router `ConfigSet` triggers an immediate check whatever the tier. Null on an evaluate-only answer."},"nextCheckAt":{"type":"string","format":"date-time","nullable":true,"description":"When the next check is expected: the due time when one is scheduled, else the last check plus the tier's sweep interval; null while never checked with nothing scheduled, and on an evaluate-only answer."},"persisted":{"type":"boolean","enum":[false]},"blockHash":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$"},"quoteTolerant":{"type":"boolean","description":"True when the adapter's quote may legitimately revert (a pull-model or session-bound feed), as the stored checks judge it."},"legs":{"type":"array","items":{"$ref":"#/components/schemas/OracleAdapterEvaluationLeg"}}}},"OracleAdapterAssessmentFinding":{"type":"object","additionalProperties":false,"required":["key","outcome","severity","description"],"properties":{"key":{"type":"string","description":"Stable rule key from the adapter rule catalog, listed in `x-finding-keys`. Keys are never renamed, only added.","x-finding-keys":["adapter-class-known","adapter-exists","asset-consistent","assets-distinct","chronicle-feed-recognized","cross-legs-recognized","custom-adapter-recognized","custom-adapter-scope","feed-not-deprecated","feed-recognized","lido-oracle-official","linear-discount-pt-correspondence","linear-discount-rate-sane","linear-discount-staleness-config","pendle-market-expired","pendle-pool-recognized","push-staleness-buffer","push-staleness-upper-bound","pyth-base-correspondence","pyth-conf-width-range","pyth-feed-recognized","pyth-proxy-official","pyth-quote-correspondence","pyth-staleness-range","quote-liveness","quote-price-consistency","session-tolerance","source-provenance","xstocks-pause-config"]},"outcome":{"type":"string","enum":["pass","fail","unknown","not_applicable"]},"severity":{"type":"string","enum":["high","medium","low","info"]},"description":{"type":"string"},"expected":{},"observed":{},"exempted":{"type":"boolean","description":"A failure the platform accepted through an adapter-check-exemption trust entry; not counted in checksStatus and not forwarded to vaults."}}},"OracleAdapterAssessmentSummary":{"type":"object","additionalProperties":false,"required":["passed","failed","unknown","notApplicable"],"properties":{"passed":{"type":"integer","minimum":0},"failed":{"type":"integer","minimum":0},"unknown":{"type":"integer","minimum":0},"notApplicable":{"type":"integer","minimum":0},"accepted":{"type":"integer","minimum":0,"description":"Failures accepted by adapter-check-exemption entries; present only when there is one."}}},"OracleAdapterAssessment":{"type":"object","additionalProperties":false,"required":["chainId","address","recognized","checksStatus","reason","inActiveRoute","adapterClass","label","provider","methodology","model","config","findings","summary","policyId","policyVersion","blockNumber","evaluatedAt","lastCheckedAt","schedulingTier","nextCheckAt"],"properties":{"chainId":{"type":"integer","minimum":1},"address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"recognized":{"type":"boolean"},"checksStatus":{"type":"string","enum":["positive","warning","negative"],"nullable":true,"description":"Health verdict of a recognized adapter. Always null for unrecognized adapters: identity and health are orthogonal, and no health claim is made about a contract whose getters are untrusted."},"reason":{"type":"string","nullable":true},"inActiveRoute":{"type":"boolean","description":"True when a current router configuration of a vault-backed router routes through this adapter, directly or as a cross-adapter leg. Refreshed hourly by the universe reconciler."},"adapterClass":{"type":"string","enum":["ChainlinkOracle","ChainlinkInfrequentOracle","ChainlinkInfrequentNanosecondOracle","ChainlinkInfrequentXStocksOracle","ChronicleOracle","CrossAdapter","CurveEMAOracle","FixedRateOracle","IdleTranchesOracle","LidoOracle","LidoFundamentalOracle","PendleOracle","PendleUniversalOracle","PythOracle","RateProviderOracle","RedstoneCoreOracle","SwaapSafeguardOracle","UniswapV3Oracle"],"nullable":true},"label":{"type":"string","nullable":true},"provider":{"type":"string","nullable":true},"methodology":{"type":"string","enum":["Market Price","Market Price (Bolt)","Smart Value Recapture","Exchange Rate","TWAP","Custom","Unknown"],"nullable":true},"model":{"type":"string","enum":["Push","Pull","Unknown"],"nullable":true},"config":{"type":"object","additionalProperties":true,"nullable":true},"findings":{"type":"array","items":{"$ref":"#/components/schemas/OracleAdapterAssessmentFinding"}},"summary":{"allOf":[{"$ref":"#/components/schemas/OracleAdapterAssessmentSummary"}],"nullable":true},"policyId":{"type":"string","enum":["euler-oracle-adapter"],"nullable":true},"policyVersion":{"type":"integer","minimum":1,"nullable":true},"blockNumber":{"type":"string","pattern":"^\\d+$","nullable":true},"evaluatedAt":{"type":"string","format":"date-time","nullable":true},"lastCheckedAt":{"type":"string","format":"date-time","nullable":true},"schedulingTier":{"type":"string","enum":["active","background","static"],"nullable":true,"description":"Which periodic sweep re-checks the adapter: `active` (hourly) when a vault in the active tier prices through it (current router pairs, nested routers expanded, cross legs followed), `background` (daily) otherwise. A router `ConfigSet` triggers an immediate check whatever the tier. Null on an evaluate-only answer."},"nextCheckAt":{"type":"string","format":"date-time","nullable":true,"description":"When the next check is expected: the due time when one is scheduled, else the last check plus the tier's sweep interval; null while never checked with nothing scheduled, and on an evaluate-only answer."}}},"OracleResolvedVault":{"type":"object","properties":{"vault":{"type":"string"},"quote":{"type":"string"},"asset":{"type":"string"},"resolvedAssets":{"type":"array","items":{"type":"string"}}}},"OracleInfo":{"type":"object","properties":{"oracle":{"type":"string"},"name":{"type":"string"},"detailedInfo":{"$ref":"#/components/schemas/OracleDetailedInfo"},"adapters":{"type":"array","items":{"$ref":"#/components/schemas/OracleAdapterEntry"}},"resolvedVaults":{"type":"array","items":{"$ref":"#/components/schemas/OracleResolvedVault"}}}},"Vault":{"type":"object","properties":{"chainId":{"type":"integer"},"address":{"type":"string"},"isEscrow":{"type":"boolean","description":"True for an EVK vault the escrow perspective has verified as collateral-only. Derived by Euler from the perspective, never from a request; `vaultType` says `evk` for such a vault, so this flag is the only place escrow is answered."},"vaultType":{"type":"string","enum":["evk","securitize"],"description":"The label classification stored on the vault's label row: `evk` for an EVK vault (escrow vaults included; read `isEscrow`), `securitize` only when an operator classified the row so. Every row on this surface is an EVK-factory vault; do not read a value other than `evk` as \"not an EVK vault\". This is not the vault *family* the resolver, Earn, and account routes report under the same name (`evk`, `earn`, `securitize`). Discovery writes the value, the Toolbox may override it through the label row, and it falls back to `evk` while the label row is unknown."},"name":{"type":"string"},"symbol":{"type":"string"},"decimals":{"type":"integer"},"shares":{"$ref":"#/components/schemas/AssetRef"},"asset":{"$ref":"#/components/schemas/AssetRef"},"totalAssets":{"type":"string","description":"Raw underlying asset amount as a bigint string."},"totalBorrows":{"type":"string","description":"Raw borrowed asset amount as a bigint string."},"totalSupplyUsd":{"type":"number","description":"Market USD number for total supplied assets."},"totalBorrowsUsd":{"type":"number","description":"Market USD number for total borrowed assets."},"utilization":{"type":"number","description":"Utilization ratio number, computed from market-normalized totals."},"supplyApy":{"type":"number","description":"Public supply APY as a percent number."},"borrowApy":{"type":"number","description":"Public borrow APY as a percent number."},"createdAt":{"type":"string","format":"date-time"},"visibility":{"$ref":"#/components/schemas/VaultVisibilitySummary"}}},"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."}}},"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"]},"VaultResolveEntry":{"type":"object","properties":{"chainId":{"type":"integer"},"address":{"type":"string"},"found":{"type":"boolean"},"vaultType":{"oneOf":[{"type":"string","enum":["evk","earn","securitize"]},{"type":"null"}]},"factory":{"type":["string","null"]},"resource":{"type":["string","null"]},"snapshotTimestamp":{"type":"string","format":"date-time"}}},"VaultDetails":{"allOf":[{"$ref":"#/components/schemas/Vault"},{"type":"object","properties":{"dToken":{"type":"string"},"oracle":{"$ref":"#/components/schemas/OracleInfo"},"unitOfAccount":{"$ref":"#/components/schemas/AssetRef"},"creator":{"type":"string"},"governor":{"type":"string","description":"Latest governor admin if available; falls back to creator."},"governorAdmin":{"type":"string","description":"Latest governor admin if available; falls back to creator."},"supplyCap":{"type":"string","description":"Equal to `caps.supplyCap`; unlimited is type(uint256).max, `0` is a zero cap."},"borrowCap":{"type":"string","description":"Equal to `caps.borrowCap`; unlimited is type(uint256).max, `0` is a zero cap."},"totalShares":{"type":"string","description":"Raw vault share supply as a bigint string."},"totalBorrowed":{"type":"string","description":"Raw borrowed asset amount as a bigint string."},"totalCash":{"type":"string","description":"Raw cash amount as a bigint string."},"cash":{"type":"string","description":"Raw cash amount as a bigint string."},"interestRate":{"type":"string","description":"Raw contract interest-rate value as a bigint string."},"interestAccumulator":{"type":"string","description":"Raw contract interest accumulator as a bigint string."},"accumulatedFees":{"type":"string","description":"Raw accumulated fee amount as a bigint string."},"balanceTracker":{"type":"string"},"fees":{"$ref":"#/components/schemas/VaultFees"},"hooks":{"$ref":"#/components/schemas/VaultHooks"},"caps":{"$ref":"#/components/schemas/VaultCaps"},"liquidation":{"$ref":"#/components/schemas/VaultLiquidation"},"interestRates":{"$ref":"#/components/schemas/VaultInterestRates"},"interestRateModel":{"$ref":"#/components/schemas/VaultInterestRateModel"},"evcCompatibleAsset":{"type":"boolean"},"oraclePriceRaw":{"$ref":"#/components/schemas/OraclePriceRaw"},"timestamp":{"type":"string","format":"date-time"},"exchangeRate":{"type":"string","nullable":true,"description":"Raw EVK exchange rate as a bigint string: floor(convertToAssets(1e18 shares)), including the 1,000,000 virtual assets and virtual shares."},"createdAtBlock":{"type":"string","description":"Block number as a bigint string."}}}]},"VaultApyPoint":{"type":"object","properties":{"supplyApy":{"type":"number","nullable":true,"description":"Percent number with 6 decimal places."},"borrowApy":{"type":"number","nullable":true,"description":"Percent number with 6 decimal places."},"timestamp":{"type":"string","format":"date-time"}}},"VaultApy":{"type":"object","properties":{"coverage":{"$ref":"#/components/schemas/HistoryCoverage"},"current":{"$ref":"#/components/schemas/VaultApyPoint"},"history":{"type":"array","items":{"$ref":"#/components/schemas/VaultApyPoint"}}}},"VaultApyMeta":{"type":"object","properties":{"coverage":{"$ref":"#/components/schemas/HistoryCoverage"},"chainId":{"type":"string"},"vault":{"type":"string"},"resolution":{"type":"string","enum":["1h","1d"]},"startTimestamp":{"type":"string","format":"date-time"},"endTimestamp":{"type":"string","format":"date-time"},"timestamp":{"type":"string","format":"date-time"}}},"VaultTotalsPoint":{"type":"object","properties":{"totalAssets":{"type":"string","nullable":true,"description":"Raw underlying asset amount as a bigint string."},"totalAssetsUsd":{"type":"number","nullable":true,"description":"USD value of totalAssets. Uses the latest asset price for current and the bucket-aligned historical asset price for history entries when available."},"totalBorrows":{"type":"string","nullable":true,"description":"Raw borrowed asset amount as a bigint string."},"totalBorrowsUsd":{"type":"number","nullable":true,"description":"USD value of totalBorrows. Uses the latest asset price for current and the bucket-aligned historical asset price for history entries when available."},"cash":{"type":"string","nullable":true,"description":"Raw cash amount as a bigint string."},"cashUsd":{"type":"number","nullable":true,"description":"USD value of cash. Uses the latest asset price for current and the bucket-aligned historical asset price for history entries when available."},"utilization":{"type":"number","nullable":true,"description":"Utilization ratio number."},"supplyApy":{"type":"number","nullable":true,"description":"Public supply APY as a percent number."},"borrowApy":{"type":"number","nullable":true,"description":"Public borrow APY as a percent number."},"sharePrice":{"type":"number","nullable":true,"description":"Raw converted-asset-base-units per share-base-unit ratio for Earn totals. Not a decimal-normalized price; use sharePriceQuote for assets per whole share."},"sharePriceQuote":{"oneOf":[{"$ref":"#/components/schemas/EarnSharePriceQuote"},{"type":"object","nullable":true,"not":{"type":"object"}}],"description":"Verified block-pinned Earn conversion, or null when unavailable. Not supplied by EVK totals."},"timestamp":{"type":"string","format":"date-time"}}},"VaultTotals":{"type":"object","properties":{"coverage":{"$ref":"#/components/schemas/HistoryCoverage"},"current":{"$ref":"#/components/schemas/VaultTotalsPoint"},"history":{"type":"array","items":{"$ref":"#/components/schemas/VaultTotalsPoint"}}}},"VaultTotalsMeta":{"allOf":[{"$ref":"#/components/schemas/VaultApyMeta"},{"type":"object","properties":{"note":{"type":"string"}}}]},"VaultTotalsFreshness":{"type":"object","properties":{"mode":{"type":"string","enum":["fresh","cached"]},"forceFreshRequested":{"type":"boolean"},"refreshTriggered":{"type":"boolean"},"refreshCompleted":{"type":"boolean"},"timedOut":{"type":"boolean"},"rateLimited":{"type":"boolean"},"fallbackReason":{"type":"string","nullable":true},"waitedMs":{"type":"integer"},"latestSnapshotTimestamp":{"type":"string","format":"date-time"},"ageSeconds":{"type":"integer"}}},"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"}}},"OracleRouterVault":{"type":"object","properties":{"vault":{"type":"string"},"asset":{"type":"string"},"blockNumber":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"txHash":{"type":"string"}}},"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"}}}},"CollateralConfigWithPrice":{"allOf":[{"$ref":"#/components/schemas/CollateralConfig"},{"type":"object","properties":{"price":{"allOf":[{"$ref":"#/components/schemas/Price"}],"nullable":true}}}]},"VaultCollateralDetail":{"allOf":[{"$ref":"#/components/schemas/CollateralConfig"},{"type":"object","properties":{"oraclePriceRaw":{"allOf":[{"$ref":"#/components/schemas/OraclePriceRaw"}],"nullable":true}}}]},"VaultIncludePrices":{"type":"object","properties":{"asset":{"allOf":[{"$ref":"#/components/schemas/Price"}],"nullable":true},"collaterals":{"type":"array","items":{"$ref":"#/components/schemas/CollateralConfigWithPrice"}}}},"VaultDetailsWithIncludes":{"allOf":[{"$ref":"#/components/schemas/VaultDetails"},{"type":"object","properties":{"collaterals":{"type":"array","items":{"$ref":"#/components/schemas/VaultCollateralDetail"},"nullable":true},"apy":{"allOf":[{"$ref":"#/components/schemas/VaultApy"}],"nullable":true},"totals":{"allOf":[{"$ref":"#/components/schemas/VaultTotals"}],"nullable":true},"prices":{"allOf":[{"$ref":"#/components/schemas/VaultIncludePrices"}],"nullable":true}}}]},"VaultDetailResponse":{"type":"object","description":"Single-vault detail response shape for `GET /v3/evk/vaults/{chainId}/{address}`.","properties":{"chainId":{"type":"integer"},"address":{"type":"string"},"isEscrow":{"type":"boolean","description":"True for an EVK vault the escrow perspective has verified as collateral-only. Derived by Euler from the perspective, never from a request; `vaultType` says `evk` for such a vault, so this flag is the only place escrow is answered."},"vaultType":{"type":"string","enum":["evk","securitize"],"description":"The label classification stored on the vault's label row: `evk` for an EVK vault (escrow vaults included; read `isEscrow`), `securitize` only when an operator classified the row so. Every row on this surface is an EVK-factory vault; do not read a value other than `evk` as \"not an EVK vault\". This is not the vault *family* the resolver, Earn, and account routes report under the same name (`evk`, `earn`, `securitize`). Discovery writes the value, the Toolbox may override it through the label row, and it falls back to `evk` while the label row is unknown."},"name":{"type":"string"},"symbol":{"type":"string"},"decimals":{"type":"integer"},"shares":{"$ref":"#/components/schemas/AssetRef"},"asset":{"$ref":"#/components/schemas/AssetRef"},"dToken":{"type":"string"},"oracle":{"$ref":"#/components/schemas/OracleInfo"},"unitOfAccount":{"$ref":"#/components/schemas/AssetRef"},"creator":{"type":"string"},"governor":{"type":"string","description":"Latest governor admin if available; falls back to creator."},"governorAdmin":{"type":"string","description":"Latest governor admin if available; falls back to creator."},"supplyCap":{"type":"string","description":"Equal to `caps.supplyCap`; unlimited is type(uint256).max, `0` is a zero cap."},"borrowCap":{"type":"string","description":"Equal to `caps.borrowCap`; unlimited is type(uint256).max, `0` is a zero cap."},"totalShares":{"type":"string","description":"Raw vault share supply as a bigint string."},"totalAssets":{"type":"string","description":"Raw underlying asset amount as a bigint string."},"totalBorrowed":{"type":"string","description":"Raw borrowed asset amount as a bigint string."},"totalCash":{"type":"string","description":"Raw cash amount as a bigint string."},"cash":{"type":"string","description":"Raw cash amount as a bigint string."},"interestRate":{"type":"string","description":"Raw contract interest-rate value as a bigint string."},"interestAccumulator":{"type":"string","description":"Raw contract interest accumulator as a bigint string."},"accumulatedFees":{"type":"string","description":"Raw accumulated fee amount as a bigint string."},"balanceTracker":{"type":"string"},"fees":{"$ref":"#/components/schemas/VaultFees"},"hooks":{"$ref":"#/components/schemas/VaultHooks"},"caps":{"$ref":"#/components/schemas/VaultCaps"},"liquidation":{"$ref":"#/components/schemas/VaultLiquidation"},"interestRates":{"$ref":"#/components/schemas/VaultInterestRates"},"interestRateModel":{"$ref":"#/components/schemas/VaultInterestRateModel"},"evcCompatibleAsset":{"type":"boolean"},"oraclePriceRaw":{"$ref":"#/components/schemas/OraclePriceRaw"},"timestamp":{"type":"string","format":"date-time"},"exchangeRate":{"type":"string","nullable":true,"description":"Raw EVK exchange rate as a bigint string: floor(convertToAssets(1e18 shares)), including the 1,000,000 virtual assets and virtual shares."},"totalSupplyUsd":{"type":"number","description":"Market USD number for total supplied assets."},"totalBorrowsUsd":{"type":"number","description":"Market USD number for total borrowed assets."},"utilization":{"type":"number","description":"Utilization ratio number."},"supplyApy":{"type":"number","description":"Public supply APY as a percent number."},"borrowApy":{"type":"number","description":"Public borrow APY as a percent number."},"snapshotTimestamp":{"type":"string","format":"date-time"},"createdAtBlock":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"VaultDetailResponseWithIncludes":{"allOf":[{"$ref":"#/components/schemas/VaultDetailResponse"},{"type":"object","properties":{"collaterals":{"type":"array","items":{"$ref":"#/components/schemas/VaultCollateralDetail"},"nullable":true},"apy":{"allOf":[{"$ref":"#/components/schemas/VaultApy"}],"nullable":true},"totals":{"allOf":[{"$ref":"#/components/schemas/VaultTotals"}],"nullable":true},"prices":{"allOf":[{"$ref":"#/components/schemas/VaultIncludePrices"}],"nullable":true}}}]},"EvkVaultBatchRequest":{"type":"object","required":["chainId","addresses"],"properties":{"chainId":{"type":"integer"},"addresses":{"type":"array","minItems":1,"maxItems":1000,"items":{"type":"string","maxLength":42},"description":"Ordered list of EVK vault addresses to fetch."},"include":{"type":"array","items":{"type":"string","enum":["collaterals"]},"description":"Optional related resources to expand for every returned vault."}}},"EvkVaultBatchMeta":{"type":"object","properties":{"count":{"type":"integer"},"requested":{"type":"integer"},"notFound":{"type":"array","items":{"type":"string"}},"timestamp":{"type":"string","format":"date-time"},"chainId":{"type":"string"}}},"EvkVaultBatchResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/VaultDetailsWithIncludes"}},"meta":{"$ref":"#/components/schemas/EvkVaultBatchMeta"}}},"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"}}},"SecuritizeTokenRef":{"type":"object","required":["address","symbol","decimals","name"],"properties":{"address":{"type":"string"},"symbol":{"type":"string"},"decimals":{"type":"integer"},"name":{"type":"string"}}},"SecuritizeVaultBatchRequest":{"type":"object","required":["chainId","addresses"],"properties":{"chainId":{"type":"integer"},"addresses":{"type":"array","minItems":1,"maxItems":1000,"items":{"type":"string","maxLength":42}}}},"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."}}},"SecuritizeVaultBatchResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SecuritizeVaultSummary"}},"meta":{"$ref":"#/components/schemas/SecuritizeVaultBatchMeta"}}},"EarnVaultSummary":{"type":"object","properties":{"chainId":{"type":"integer"},"address":{"type":"string"},"vaultType":{"type":"string","enum":["earn"],"description":"Every row of the Earn surface is an Earn vault; the EVK surface answers the stored type (`evk` or `securitize`, with `isEscrow` beside it), so one read tells a consumer the family of an address."},"name":{"type":"string"},"symbol":{"type":"string"},"decimals":{"type":"integer"},"asset":{"$ref":"#/components/schemas/AssetRef"},"totalAssets":{"type":"string","description":"Raw underlying asset amount as a bigint string."},"totalShares":{"type":"string","description":"Raw vault share supply as a bigint string."},"lostAssets":{"type":"string","description":"Raw lost asset amount as a bigint string."},"exchangeRate":{"type":"string","description":"Raw exchange rate as a bigint string."},"totalSupplyUsd":{"type":"number","description":"Market USD number for total Earn vault assets."},"availableAssets":{"type":"string","description":"Raw underlying asset amount as a bigint string."},"availableAssetsUsd":{"type":"number","description":"Market USD number for currently available assets."},"supplyApy":{"type":"number","nullable":true,"description":"Public supply APY as a percent number."},"apyCurrent":{"type":"number","nullable":true,"description":"Current public APY as a percent number."},"apy7d":{"type":"number","nullable":true,"description":"Seven-day public APY as a percent number, using an anchor at or up to 15 minutes before the exact cutoff. Null when no qualifying local or archive anchor is available."},"apy30d":{"type":"number","nullable":true,"description":"Thirty-day public APY as a percent number, using an anchor at or up to 15 minutes before the exact cutoff. Null when no qualifying local or archive anchor is available."},"apy90d":{"type":"number","nullable":true,"description":"Ninety-day public APY as a percent number, using an anchor at or up to 15 minutes before the exact cutoff. Null when no qualifying local or archive anchor is available."},"utilization":{"type":"number","description":"Utilization ratio number."},"strategyCount":{"type":"integer"},"snapshotTimestamp":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"visibility":{"$ref":"#/components/schemas/VaultVisibilitySummary"}}},"EarnVaultBatchRequest":{"type":"object","required":["chainId","addresses"],"properties":{"chainId":{"type":"integer"},"addresses":{"type":"array","minItems":1,"maxItems":1000,"items":{"type":"string","maxLength":42}},"include":{"type":"array","items":{"type":"string","enum":["strategies"]},"description":"Optional related resources to expand for every returned vault."}}},"EarnVaultBatchMeta":{"type":"object","properties":{"count":{"type":"integer"},"requested":{"type":"integer"},"notFound":{"type":"array","items":{"type":"string"}},"timestamp":{"type":"string","format":"date-time"},"chainId":{"type":"string"}}},"EarnVaultBatchItem":{"allOf":[{"$ref":"#/components/schemas/EarnVaultSummary"},{"type":"object","properties":{"management":{"allOf":[{"$ref":"#/components/schemas/EarnVaultManagement"}],"description":"The vault's roles and parameters from the indexed events (owner, curator, guardian, fee recipient, timelock, fee), as the detail answers them; absent when nothing is indexed for the vault."},"strategies":{"type":"array","items":{"$ref":"#/components/schemas/EarnStrategy"}}}}]},"EarnVaultBatchResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EarnVaultBatchItem"}},"meta":{"$ref":"#/components/schemas/EarnVaultBatchMeta"}}},"EarnVaultDetails":{"allOf":[{"$ref":"#/components/schemas/EarnVaultSummary"},{"type":"object","properties":{"totalShares":{"type":"string","description":"Raw vault share supply as a bigint string."},"lostAssets":{"type":"string","description":"Raw lost asset amount as a bigint string."},"exchangeRate":{"type":"string","description":"Raw exchange rate as a bigint string."},"strategies":{"type":"array","items":{"$ref":"#/components/schemas/EarnStrategy"}},"governance":{"$ref":"#/components/schemas/EarnVaultGovernance"},"management":{"$ref":"#/components/schemas/EarnVaultManagement"}}}]},"EarnStrategy":{"type":"object","properties":{"address":{"type":"string"},"vaultType":{"type":"string","enum":["evk","earn","securitize","unknown"]},"symbol":{"type":"string","nullable":true},"name":{"type":"string","nullable":true},"decimals":{"type":"integer","nullable":true},"suppliedAssets":{"type":"string","description":"Raw underlying asset amount supplied to the strategy."},"withdrawnAssets":{"type":"string","description":"Raw underlying asset amount withdrawn from the strategy."},"allocatedAssets":{"type":"string","description":"Raw underlying asset amount allocated to the strategy."},"allocatedAssetsUsd":{"type":"number","description":"Market USD number for assets allocated to this strategy."},"availableAssets":{"type":"string","description":"Raw underlying asset amount available from the strategy."},"inSupplyQueue":{"type":"boolean"},"inWithdrawQueue":{"type":"boolean"},"supplyQueueIndex":{"type":"integer","nullable":true},"withdrawQueueIndex":{"type":"integer","nullable":true},"allocationCap":{"$ref":"#/components/schemas/EarnStrategyAllocationCap"},"removableAt":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["active","inactive","pending_removal"]},"lastRebalancedAt":{"type":"string","format":"date-time","nullable":true}}},"EarnVaultManagement":{"type":"object","properties":{"owner":{"type":"string"},"curator":{"type":"string"},"guardian":{"type":"string"},"feeRecipient":{"type":"string"},"timelockSeconds":{"type":"integer","description":"Timelock duration in seconds."},"performanceFee":{"type":"string","description":"Raw contract performance fee value as a bigint string."}}},"EarnVaultGovernance":{"type":"object","properties":{"owner":{"type":"string"},"creator":{"type":"string"},"curator":{"type":"string"},"guardian":{"type":"string"},"feeReceiver":{"type":"string"},"allocators":{"type":"array","items":{"type":"string"},"description":"Active allocator addresses reconstructed from SetIsAllocator events."},"timelock":{"type":"integer","description":"Timelock duration in seconds."},"pendingTimelock":{"type":"integer","description":"Pending timelock duration in seconds."},"pendingTimelockValidAt":{"type":"string","format":"date-time"},"pendingGuardian":{"type":"string"},"pendingGuardianValidAt":{"type":"string","format":"date-time"}}},"EarnStrategyAllocationCap":{"type":"object","properties":{"current":{"type":"string","description":"Raw allocation cap as a bigint string in underlying asset units."},"pending":{"type":"string","description":"Pending raw allocation cap as a bigint string in underlying asset units."},"pendingValidAt":{"type":"string","format":"date-time"}}},"EarnIncludePrices":{"type":"object","properties":{"asset":{"allOf":[{"$ref":"#/components/schemas/Price"}],"nullable":true}}},"EarnVaultDetailsWithIncludes":{"allOf":[{"$ref":"#/components/schemas/EarnVaultDetails"},{"type":"object","properties":{"apy":{"allOf":[{"$ref":"#/components/schemas/VaultApy"}],"nullable":true},"totals":{"allOf":[{"$ref":"#/components/schemas/VaultTotals"}],"nullable":true},"prices":{"allOf":[{"$ref":"#/components/schemas/EarnIncludePrices"}],"nullable":true}}}]},"EarnSharePriceQuote":{"type":"object","required":["unit","chainId","vaultAddress","assetAddress","shareDecimals","assetDecimals","convertedAssetsRaw","assetsPerShare","blockNumber","blockHash","blockTimestamp"],"description":"Conversion of one whole Earn share into underlying assets using contract metadata and convertToAssets at the same verified block. Does not use a USD price.","properties":{"unit":{"type":"string","enum":["assets-per-whole-share"]},"chainId":{"type":"integer"},"vaultAddress":{"type":"string"},"assetAddress":{"type":"string"},"shareDecimals":{"type":"integer","minimum":0,"maximum":77},"assetDecimals":{"type":"integer","minimum":0,"maximum":255},"convertedAssetsRaw":{"type":"string","description":"Exact integer result of convertToAssets(10^shareDecimals) in asset base units."},"assetsPerShare":{"type":"string","description":"Exact decimal string obtained by applying assetDecimals to convertedAssetsRaw. Observed zero is valid."},"blockNumber":{"type":"string","description":"Decimal block number used for metadata and conversion reads."},"blockHash":{"type":"string","pattern":"^0x[0-9a-fA-F]{64}$"},"blockTimestamp":{"type":"integer","description":"Source block time in Unix seconds, independent of the response bucket timestamp."}}},"EarnTotalsHistoryPoint":{"type":"object","properties":{"totalAssets":{"type":"string","description":"Raw aggregator underlying asset amount as a bigint string."},"totalAssetsUsd":{"type":"number","nullable":true,"description":"USD value of totalAssets. Current values use the materialized vault valuation; history values use the bucket-aligned asset price when available."},"sharePrice":{"type":"number","nullable":true,"description":"Raw converted-asset-base-units per share-base-unit ratio. Not a decimal-normalized price; use sharePriceQuote for assets per whole share."},"sharePriceQuote":{"oneOf":[{"$ref":"#/components/schemas/EarnSharePriceQuote"},{"type":"object","nullable":true,"not":{"type":"object"}}],"description":"Verified conversion from the same source snapshot. Null for snapshots without verified metadata; no inferred historical normalization."},"apy":{"type":"number","nullable":true,"description":"Earn public APY as a percent number."},"timestamp":{"type":"string","format":"date-time"}}},"EarnTotalsHistory":{"type":"object","properties":{"current":{"$ref":"#/components/schemas/EarnTotalsHistoryPoint"},"history":{"type":"array","items":{"$ref":"#/components/schemas/EarnTotalsHistoryPoint"}}}},"EarnTotalsHistoryMeta":{"type":"object","properties":{"coverage":{"$ref":"#/components/schemas/HistoryCoverage"},"chainId":{"type":"string"},"vault":{"type":"string"},"resolution":{"type":"string","enum":["1h","1d"]},"startTimestamp":{"type":"string","format":"date-time"},"endTimestamp":{"type":"string","format":"date-time"},"timestamp":{"type":"string","format":"date-time"},"source":{"type":"string","enum":["snapshot","live","ponder","summary","snapshot-stale"],"description":"Source selected for the current totalAssets value."},"stale":{"type":"boolean","description":"Whether the selected current totalAssets value is older than the 15-minute freshness threshold."},"snapshotTimestamp":{"type":"string","format":"date-time","description":"Timestamp of the latest Earn APY snapshot when one exists."},"snapshotAgeSeconds":{"type":"integer","minimum":0,"description":"Age of the latest Earn APY snapshot at response construction time."},"note":{"type":"string"}}},"VaultPosition":{"type":"object","properties":{"account":{"type":"string"},"shares":{"type":"string","description":"Raw vault share amount as a bigint string."},"assets":{"type":"string","description":"Raw underlying asset amount as a bigint string."},"assetsUsd":{"type":"number","nullable":true,"description":"Market USD number computed from `assets` and the token price endpoint."},"lastUpdatedBlock":{"type":"string"}}},"AccountLiquidityValue":{"type":"object","description":"Contract-derived account-liquidity value in unit-of-account terms; each field is a raw 18-decimal bigint string.","properties":{"borrowing":{"type":"string","description":"Borrowing value, raw 18-decimal bigint string."},"liquidation":{"type":"string","description":"Liquidation value, raw 18-decimal bigint string."},"oracleMid":{"type":"string","description":"Oracle midpoint value, raw 18-decimal bigint string."}}},"AccountPositionLiquidity":{"type":"object","nullable":true,"properties":{"vaultAddress":{"type":"string"},"unitOfAccount":{"type":"string"},"daysToLiquidation":{"oneOf":[{"type":"integer"},{"type":"string","enum":["Infinity","MoreThanAYear"]}]},"liabilityValue":{"$ref":"#/components/schemas/AccountLiquidityValue"},"totalCollateralValue":{"$ref":"#/components/schemas/AccountLiquidityValue"},"collaterals":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string"},"value":{"$ref":"#/components/schemas/AccountLiquidityValue"},"marketPriceUsd":{"type":"number","description":"Market USD price number for the collateral asset."},"valueUsd":{"type":"number","description":"Market USD value number for this collateral."}}}},"liabilityValueUsd":{"type":"number","description":"Market USD liability value number."},"totalCollateralValueUsd":{"type":"number","description":"Market USD collateral value number."}}},"AccountPosition":{"type":"object","properties":{"chainId":{"type":"integer"},"account":{"type":"string"},"vault":{"type":"string"},"vaultType":{"type":"string","enum":["evk","earn","securitize"]},"asset":{"type":"string","nullable":true},"shares":{"type":"string","nullable":true,"description":"Raw vault share amount as a bigint string."},"assets":{"type":"string","nullable":true,"description":"Raw underlying asset amount as a bigint string."},"borrowed":{"type":"string","nullable":true,"description":"Raw borrowed asset amount as a bigint string. `\"0\"` is a successful\nzero-debt read. `null` means EVK debt is currently unknown; it is not\na zero balance. Earn and Securitize positions use `\"0\"` because EVK\ndebt is not applicable to those vault types.\n"},"assetsValue":{"type":"string","nullable":true,"description":"Contract-derived account-liquidity asset value, raw 18-decimal bigint string."},"debtValue":{"type":"string","nullable":true,"description":"Contract-derived account-liquidity debt value, raw 18-decimal bigint\nstring. `null` means the EVK debt read is unknown, not zero.\n"},"isCollateral":{"type":"boolean","nullable":true},"balanceForwarderEnabled":{"type":"boolean","nullable":true},"isController":{"type":"boolean","nullable":true,"description":"Explicit EVC controller status when AccountLens provides it. `null`\nmeans controller status is unknown; a zero debt amount does not imply\n`false`. The field is non-applicable for Earn and Securitize positions.\n"},"liquidity":{"$ref":"#/components/schemas/AccountPositionLiquidity"},"subAccount":{"type":"object","nullable":true,"properties":{"owner":{"type":"string","nullable":true},"timestamp":{"type":"string","format":"date-time","nullable":true},"lastAccountStatusCheckTimestamp":{"type":"string","format":"date-time","nullable":true},"enabledControllers":{"type":"array","nullable":true,"items":{"type":"string"}},"enabledCollaterals":{"type":"array","nullable":true,"items":{"type":"string"}},"isLockdownMode":{"type":"boolean","nullable":true},"isPermitDisabledMode":{"type":"boolean","nullable":true}}},"snapshot":{"type":"object","properties":{"timestamp":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp of the coherent snapshot represented by this position.\nA failed partial refresh retains the prior snapshot and timestamp\nwhen replacing it would erase known EVK debt or controller state.\n"},"ageSeconds":{"type":"integer","nullable":true},"source":{"type":"string","nullable":true},"method":{"type":"string","nullable":true}}}}},"AccountPortfolioResponse":{"type":"object","properties":{"chainId":{"type":"integer"},"owner":{"type":"string"},"portfolio":{"type":"object","properties":{"savings":{"type":"array","items":{"$ref":"#/components/schemas/PortfolioSavingsPosition"}},"borrows":{"type":"array","items":{"$ref":"#/components/schemas/PortfolioBorrowPosition"}},"positions":{"type":"array","items":{"$ref":"#/components/schemas/SerializedPortfolioAccountPosition"}},"managedLending":{"type":"array","items":{"$ref":"#/components/schemas/PortfolioSavingsPosition"}},"directLending":{"type":"array","items":{"$ref":"#/components/schemas/PortfolioSavingsPosition"}},"totals":{"type":"object","description":"Aggregate portfolio metrics. When any EVK position has unknown\ndebt or controller state, the aggregate is incomplete and all\ntotal properties are omitted; `errors` identifies the affected\nposition. Consumers must not interpret omitted totals as zero.\n","properties":{"suppliedValueUsd":{"type":"number","description":"Market USD number for total supplied value."},"borrowedValueUsd":{"type":"number","description":"Market USD number for total borrowed value."},"netAssetValueUsd":{"type":"number","description":"Market USD number for supplied minus borrowed value."},"netApy":{"type":"number","description":"Public net APY as a percent number."},"roe":{"type":"number","description":"Return-on-equity ratio number."},"apyBreakdown":{"$ref":"#/components/schemas/YieldApyBreakdown"},"roeBreakdown":{"$ref":"#/components/schemas/YieldApyBreakdown"}}}}},"account":{"type":"object","nullable":true,"additionalProperties":true},"errors":{"type":"array","items":{"$ref":"#/components/schemas/DataIssue"}},"freshness":{"type":"object","properties":{"latestSnapshotTimestamp":{"type":"integer","nullable":true},"ageSeconds":{"type":"integer","nullable":true},"timestamp":{"type":"string","format":"date-time"},"mode":{"type":"string","enum":["fresh","cached"]},"forceFreshRequested":{"type":"boolean"},"refreshTriggered":{"type":"boolean"},"refreshCompleted":{"type":"boolean"},"timedOut":{"type":"boolean"},"rateLimited":{"type":"boolean"},"fallbackReason":{"type":"string","nullable":true},"waitedMs":{"type":"integer"}}}}},"PortfolioSavingsPosition":{"type":"object","properties":{"position":{"$ref":"#/components/schemas/SerializedPortfolioAccountPosition"},"vault":{"$ref":"#/components/schemas/SerializedPortfolioVault"},"subAccount":{"type":"string"},"shares":{"type":"string","description":"Raw vault share amount as a bigint string."},"assets":{"type":"string","description":"Raw underlying asset amount as a bigint string."},"suppliedValueUsd":{"type":"number","description":"Market USD value number for this savings position."},"apy":{"type":"number","description":"Public APY as a percent number."},"apyBreakdown":{"$ref":"#/components/schemas/YieldApyBreakdown"}}},"PortfolioBorrowPosition":{"type":"object","properties":{"borrow":{"$ref":"#/components/schemas/SerializedPortfolioAccountPosition"},"collaterals":{"type":"array","items":{"$ref":"#/components/schemas/SerializedPortfolioAccountPosition"}},"collateral":{"$ref":"#/components/schemas/SerializedPortfolioAccountPosition"},"borrowVault":{"$ref":"#/components/schemas/SerializedPortfolioVault"},"collateralVault":{"$ref":"#/components/schemas/SerializedPortfolioVault"},"collateralVaults":{"type":"array","items":{"type":"string"}},"subAccount":{"type":"string"},"healthFactor":{"type":"string"},"userLTV":{"type":"string","description":"Contract-derived account LTV ratio, raw 18-decimal bigint string."},"currentLTV":{"type":"string","description":"Contract-derived current LTV ratio, raw 18-decimal bigint string."},"borrowed":{"type":"string","description":"Raw borrowed asset amount as a bigint string."},"supplied":{"type":"string","description":"Raw supplied asset amount as a bigint string."},"price":{"type":"number","description":"Borrow liquidation price in USD."},"borrowLiquidationPriceUsd":{"type":"number","description":"Borrow liquidation price in USD."},"collateralLiquidationPricesUsd":{"type":"object","description":"Liquidation prices in USD keyed by collateral address.","additionalProperties":{"type":"number"}},"borrowLTV":{"type":"number","description":"Borrow LTV ratio number."},"liquidationLTV":{"type":"number","description":"Liquidation LTV ratio number."},"accountLiquidationLTV":{"type":"number","description":"Account liquidation LTV ratio number."},"liabilityValueBorrowing":{"type":"string","description":"Contract-derived liability value for borrowing, raw 18-decimal bigint string."},"liabilityValueLiquidation":{"type":"string","description":"Contract-derived liability value for liquidation, raw 18-decimal bigint string."},"liabilityValueUsd":{"type":"number","description":"Market USD liability value number."},"totalCollateralValueUsd":{"type":"number","description":"Market USD total collateral value number."},"collateralValueLiquidation":{"type":"string","description":"Contract-derived collateral liquidation value, raw 18-decimal bigint string."},"timeToLiquidation":{"oneOf":[{"type":"integer"},{"type":"string","enum":["Infinity","MoreThanAYear"]}]},"multiplier":{"type":"number","description":"Leverage multiplier ratio number."},"netApy":{"type":"number","description":"Public net APY as a percent number."},"roe":{"type":"number","description":"Return-on-equity ratio number."},"apyBreakdown":{"$ref":"#/components/schemas/YieldApyBreakdown"},"roeBreakdown":{"$ref":"#/components/schemas/YieldApyBreakdown"}}},"YieldApyBreakdown":{"type":"object","properties":{"lending":{"type":"number","description":"Lending APY contribution as a percent number."},"borrowing":{"type":"number","description":"Borrowing APY contribution as a percent number."},"rewards":{"type":"number","description":"Rewards APY contribution as a percent number."},"intrinsicApy":{"type":"number","description":"Intrinsic APY contribution as a percent number."},"total":{"type":"number","description":"Total APY as a percent number."}}},"SerializedPortfolioAccountPosition":{"type":"object","properties":{"account":{"type":"string"},"vaultAddress":{"type":"string"},"vault":{"$ref":"#/components/schemas/SerializedPortfolioVault"},"asset":{"type":"string"},"shares":{"type":"string","description":"Raw vault share amount as a bigint string."},"assets":{"type":"string","description":"Raw underlying asset amount as a bigint string."},"borrowed":{"type":"string","description":"Raw borrowed asset amount as a bigint string."},"isController":{"type":"boolean"},"isCollateral":{"type":"boolean"},"balanceForwarderEnabled":{"type":"boolean"},"marketPriceUsd":{"type":"number","description":"Market USD price number for this position's asset."},"suppliedValueUsd":{"type":"number","description":"Market USD value number for this supplied position."},"borrowedValueUsd":{"type":"number","description":"Market USD value number for this borrowed position."},"liquidity":{"$ref":"#/components/schemas/AccountPositionLiquidity"},"borrowLiquidationPriceUsd":{"type":"number","description":"Borrow liquidation price in USD."},"collateralLiquidationPricesUsd":{"type":"object","description":"Liquidation prices in USD keyed by collateral address.","additionalProperties":{"type":"number"}}}},"SerializedPortfolioVault":{"type":"object","properties":{"address":{"type":"string"},"type":{"type":"string","enum":["evk","earn","securitize","unknown"]},"asset":{"type":"object","properties":{"address":{"type":"string"},"symbol":{"type":"string"},"decimals":{"type":"integer"},"name":{"type":"string"}}},"shares":{"type":"object","properties":{"address":{"type":"string"},"symbol":{"type":"string"},"decimals":{"type":"integer"},"name":{"type":"string"}}},"supplyApy":{"type":"number","description":"Public supply APY as a percent number."},"borrowApy":{"type":"number","description":"Public borrow APY as a percent number."},"supplyApy1h":{"type":"number","description":"One-hour public supply APY as a percent number."},"strategyCount":{"type":"integer"}}},"DataIssue":{"type":"object","properties":{"code":{"type":"string"},"severity":{"type":"string","enum":["info","warning","error"]},"message":{"type":"string"},"locations":{"type":"array","items":{"type":"object","properties":{"owner":{"type":"object","additionalProperties":true},"path":{"type":"string"}}}},"source":{"type":"string"},"originalValue":{},"normalizedValue":{}}},"AccountActivity":{"type":"object","properties":{"type":{"type":"string"},"chainId":{"type":"integer"},"vault":{"type":"string"},"assets":{"type":"string","description":"Raw underlying asset amount as a bigint string."},"shares":{"type":"string","description":"Raw vault share amount as a bigint string."},"txHash":{"type":"string"},"blockNumber":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"ActivityCategory":{"type":"string","enum":["lending","borrowing","swaps","liquidations","account","rewards","governance"]},"ActivityEventType":{"type":"string","description":"Normalized event type. Filters apply to this value, not the source table name.","enum":["deposit","withdraw","mint","burn","transfer","borrow","repay","swap","interest_accrued","debt_socialized","pull_debt","liquidation","approval","balance_forwarder_status","convert_fees","set_caps","set_ltv","set_governor_admin","set_config_flags","set_fee_receiver","set_hook_config","set_interest_fee","set_interest_rate_model","set_liquidation_cool_off_time","set_max_liquidation_discount","set_oracle_config","set_fallback_oracle","set_resolved_vault","set_oracle_governor","accrue_interest","update_last_total_assets","update_lost_assets","reallocate_supply","reallocate_withdraw","set_name","set_symbol","set_fee","set_fee_recipient","set_curator","set_guardian","set_timelock","set_cap","set_is_allocator","set_supply_queue","set_withdraw_queue","submit_cap","submit_guardian","submit_timelock","submit_market_removal","revoke_pending_cap","revoke_pending_guardian","revoke_pending_timelock","revoke_pending_market_removal","ownership_transfer_started","ownership_transferred","frozen","unfrozen","paused","unpaused","seized","set_controller_perspective","set_supply_cap","owner_registered","collateral_status","operator_status","controller_status","lockdown_mode_status","nonce_status","nonce_used","permit_disabled_mode_status","reward_lock_created","reward_lock_removed","reward_transfer","reward_whitelist_status","public_reallocate_to","public_withdrawal","set_admin","set_allocation_fee","set_flow_caps","transfer_allocation_fee","buy","terms_of_use_signed"]},"ActivityAsset":{"type":"object","additionalProperties":false,"required":["kind","amountRaw"],"properties":{"kind":{"type":"string","enum":["assets","shares","value","collateral","yield"]},"amountRaw":{"type":"string","pattern":"^\\d+$","description":"Native-unit on-chain amount without decimal normalization."},"address":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","description":"Token or vault address that gives the amount context when indexed."},"symbol":{"type":"string"},"decimals":{"type":"integer","minimum":0,"maximum":255},"amount":{"type":"string","description":"Optional decimal-normalized enrichment."},"amountUsd":{"type":"string","description":"Optional event-time USD enrichment. Absence never means zero."}}},"ActivityChange":{"type":"object","additionalProperties":false,"required":["fields"],"properties":{"fields":{"type":"object","additionalProperties":true,"description":"Source-specific changed fields retained under normalized event identity."}}},"ActivityValuation":{"type":"object","additionalProperties":false,"required":["status"],"properties":{"status":{"type":"string","enum":["available","unavailable","partial"]},"amountUsd":{"type":"string"},"priceTimestamp":{"type":"string","format":"date-time"},"source":{"type":"string"},"reason":{"type":"string"}}},"ActivityEvent":{"type":"object","additionalProperties":false,"required":["id","chainId","timestamp","blockNumber","logIndex","txHash","type","category","source"],"properties":{"id":{"type":"string"},"chainId":{"type":"integer","minimum":1},"timestamp":{"type":"string","format":"date-time"},"blockNumber":{"type":"string","pattern":"^\\d+$"},"logIndex":{"type":"integer","minimum":0},"txHash":{"type":"string","pattern":"^0x[0-9a-fA-F]{64}$"},"type":{"$ref":"#/components/schemas/ActivityEventType"},"category":{"$ref":"#/components/schemas/ActivityCategory"},"source":{"type":"string","enum":["v3-ponder"]},"rawType":{"type":"string"},"owner":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"account":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"subAccountIndex":{"type":"integer","minimum":0,"maximum":255},"vault":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"vaultType":{"type":"string","enum":["evk","earn","securitize"]},"actor":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"counterparty":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"assets":{"type":"array","items":{"$ref":"#/components/schemas/ActivityAsset"}},"change":{"$ref":"#/components/schemas/ActivityChange"},"valuation":{"$ref":"#/components/schemas/ActivityValuation"},"groupId":{"type":"string"},"payload":{"type":"object","additionalProperties":true,"description":"Source-specific fallback fields. Normalized properties remain authoritative."}}},"ActivityChainCoverage":{"type":"object","additionalProperties":false,"required":["chainId","status","missingCategories"],"properties":{"chainId":{"type":"integer","minimum":1},"status":{"type":"string","enum":["complete","partial","unsupported","syncing"]},"indexedFromBlock":{"type":"string","pattern":"^\\d+$"},"indexedToBlock":{"type":"string","pattern":"^\\d+$"},"missingCategories":{"type":"array","uniqueItems":true,"items":{"$ref":"#/components/schemas/ActivityCategory"}},"reason":{"type":"string"}}},"ActivityCoverage":{"type":"object","additionalProperties":false,"required":["status","chains","missingCategories"],"properties":{"status":{"type":"string","enum":["complete","partial","unsupported","syncing"]},"chains":{"type":"array","items":{"$ref":"#/components/schemas/ActivityChainCoverage"}},"missingCategories":{"type":"array","uniqueItems":true,"items":{"$ref":"#/components/schemas/ActivityCategory"}},"reason":{"type":"string"}}},"ActivityResponse":{"type":"object","additionalProperties":false,"required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEvent"}},"meta":{"type":"object","additionalProperties":false,"required":["hasMore","nextCursor","source","coverage","timestamp"],"properties":{"hasMore":{"type":"boolean"},"nextCursor":{"type":"string","nullable":true},"source":{"type":"string","enum":["v3-ponder"]},"coverage":{"$ref":"#/components/schemas/ActivityCoverage"},"timestamp":{"type":"string","format":"date-time"}}}}},"Token":{"type":"object","properties":{"chainId":{"type":"integer"},"address":{"type":"string"},"name":{"type":"string"},"symbol":{"type":"string"},"decimals":{"type":"integer"},"logoURI":{"type":"string","description":"Token image URL on the V3 image host. When V3 holds an image for the token, `?v=` carries the first 8 hex characters of its content digest, so the URL changes when the image does and can be cached for a year. Without an image there is no `?v=`."},"hasLogo":{"type":"boolean","description":"Whether V3 holds an image for this token. When false, `logoURI` still answers with a fallback, so a client with its own logo source can prefer that instead."},"priceUsd":{"type":"number","description":"Market USD price number when token list responses include a price."},"metadata":{"$ref":"#/components/schemas/TokenMetadata"},"groups":{"type":"array","items":{"type":"string"},"description":"Asset group associations (e.g., pendle-pt, pendle-lp)."},"tags":{"type":"array","items":{"type":"string","enum":["usd","eth","btc","mon","avax","hype","bnb"]},"description":"Correlation tags derived from CoinGecko categories, symbol rules and address rules (one token by chain and address), used by clients for asset-specific processing."},"kind":{"type":"string","enum":["asset","eToken","dToken","earnShare"],"description":"What the token is to the protocol: `eToken` when the address is an EVK vault discovery recorded (escrow and Securitize vaults included), `dToken` when the indexer classified it as a vault's debt token, `earnShare` when it is an Earn vault, `asset` otherwise (also when unknown). Lets a client filter vault-issued tokens out without relying on name conventions."}}},"TokenMetadata":{"type":"object","description":"Protocol integration metadata for a token.","properties":{"isPendlePT":{"type":"boolean"},"isPendleLP":{"type":"boolean"},"pendleMarket":{"type":"string","nullable":true}},"additionalProperties":true},"Price":{"type":"object","properties":{"chainId":{"type":"integer"},"address":{"type":"string"},"symbol":{"type":"string"},"decimals":{"type":"integer"},"priceUsd":{"type":"number","description":"Market-normalized USD price number. Use `/v3/oracles/prices` for exact contract-derived oracle values."},"source":{"type":"string","enum":["onchain","offchain","hardcoded"],"description":"Provider-redacted price provenance category."},"timestamp":{"type":"string","format":"date-time","description":"Observation time, the provider's own time for the price when it gives one. Current-price endpoints return the best-known observation up to 7 days old; derived USD calculations accept observations up to 24 hours old."},"stale":{"type":"boolean","description":"Whether the served observation is older than the 24-hour freshness window. Present on current-price responses (`/v3/prices`, token price, and vault and Earn price includes); absent from `/v3/prices/history`."}}},"IntrinsicApy":{"type":"object","properties":{"chainId":{"type":"integer"},"address":{"type":"string"},"symbol":{"type":"string"},"apy":{"type":"number","description":"Percent number with 6 decimal places."},"provider":{"type":"string"},"source":{"type":"string"},"claimUrl":{"type":"string","format":"uri","description":"Where the yield is claimed. Always an https URL; absent when the source gave none or a URL that is not https."},"timestamp":{"type":"string","format":"date-time"}}},"RewardsApy":{"type":"object","properties":{"chainId":{"type":"integer"},"vault":{"type":"string"},"campaigns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"provider":{"type":"string"},"apr":{"type":"number","description":"Reward APR contribution as a public percent number. For an ended\ncampaign this is the last rate seen while it ran, not a current rate.\n"},"rewardToken":{"$ref":"#/components/schemas/AssetRef"},"source":{"type":"string","enum":["merkl","turtle","direct"]},"startTimestamp":{"type":"string","format":"date-time"},"endTimestamp":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["active","upcoming","ended"],"description":"Campaign status. 'active' = ongoing, 'upcoming' = not yet started, 'ended' = past. Ended campaigns are listed for 30 days after their end time."},"campaignType":{"type":"string"},"collateralAsset":{"type":"string"},"requiresCb1Verification":{"type":"boolean"},"merklCampaignId":{"type":"string","description":"Original Merkl campaign id when the public campaign is fanned out into vault-level instances."},"opportunityType":{"type":"string","description":"Merkl opportunity type that produced this campaign."},"sourceUrl":{"type":"string","format":"uri","description":"Exact Merkl campaign page."},"distributionType":{"type":"string","description":"Merkl distribution type for the campaign."},"whitelist":{"type":"array","description":"Lowercase recipient addresses eligible for whitelist-gated campaigns.","items":{"type":"string"}},"blacklist":{"type":"array","description":"Lowercase recipient addresses excluded from blacklist-gated campaigns.","items":{"type":"string"}},"eligibilityRequirements":{"type":"array","description":"Requirements that must be satisfied for the campaign rewards to apply.","items":{"type":"object","required":["type","chainId","tokenAddress","minimumAmount","minimumDurationSeconds"],"properties":{"type":{"type":"string","enum":["token-holding"]},"chainId":{"type":"integer","minimum":1},"tokenAddress":{"type":"string"},"minimumAmount":{"type":"string","pattern":"^[1-9][0-9]*$","description":"Minimum token amount in base units."},"minimumDurationSeconds":{"type":"integer","minimum":1,"description":"Minimum continuous holding duration in seconds."},"tokenSymbol":{"type":"string"},"tokenDecimals":{"type":"integer"}}}},"eligibilityRequirementsStatus":{"type":"string","enum":["none","complete","incomplete"],"description":"Whether campaign eligibility hooks are absent, fully represented by\neligibilityRequirements, or include conditions this API cannot model.\nThis field is always present for Merkl campaigns. Retained legacy Merkl\nrows without completeness metadata are reported as incomplete. Consumers\nmust direct users to sourceUrl when this value is incomplete.\n"}}}},"totalApr":{"type":"number","description":"Sum of currently active reward APR contributions as a public percent number."}}},"RewardsApyHistoryPoint":{"type":"object","properties":{"chainId":{"type":"integer"},"vault":{"type":"string"},"rewardsApy":{"type":"number","description":"Rewards APY as a public percent number."},"timestamp":{"type":"string","format":"date-time","description":"Bucket timestamp as an ISO-8601 UTC string."}}},"RewardBreakdown":{"type":"object","required":["chainId","vault","recipient","rewardToken","amount","campaignId","provider","timestamp"],"description":"Per-account reward breakdown row. For Merkl rows, `amount` is reconciled\nagainst direct Merkl user rewards when that data is available, so fully\nclaimed rows are omitted and positive rows use the current claimable\namount. Merkl reports one claimable amount per campaign; when a campaign\ncovers several vaults, that amount is split over the account's rows for\nthe campaign in proportion to their stored amounts, so the rows add up\nto Merkl's figure. If direct Merkl data is unavailable, stored Merkl rows\nare returned only while their snapshot is 24 hours old or newer.\n","properties":{"chainId":{"type":"integer"},"vault":{"type":"string"},"recipient":{"type":"string"},"rewardToken":{"type":"string"},"rewardTokenMetadata":{"type":"object","nullable":true,"description":"Token metadata resolved independently of campaign availability. Null when metadata is unavailable; consumers must not assume 18 decimals.","properties":{"address":{"type":"string"},"symbol":{"type":"string"},"decimals":{"type":"integer"},"name":{"type":"string"}}},"amount":{"type":"string","description":"Reward amount as a bigint string in token base units. Merkl amounts follow the reconciliation rules above. Turtle amounts are accumulated rewards, not a verified currently claimable balance."},"campaignId":{"type":"string"},"provider":{"type":"string","enum":["merkl","turtle"],"description":"Reward provider that pays this row. Claims go through that\nprovider's distributor: Merkl claims are made per reward token, so\nMerkl's per-token total and proof decide what an account can claim,\nnot a sum of these rows.\n"},"timestamp":{"type":"string","format":"date-time"}}},"IntrinsicApyHistoryPoint":{"type":"object","properties":{"timestamp":{"type":"string","format":"date-time"},"apy":{"type":"number","description":"Intrinsic APY as a percent number."},"provider":{"type":"string"},"uniquifier":{"type":"string","description":"Provider-specific identity when one provider exposes multiple APY streams."},"apyDuration":{"type":"number","description":"Duration in seconds used to compute the APY."}}},"IntrinsicApyHistoryMeta":{"type":"object","properties":{"chainId":{"type":"string"},"asset":{"type":"string"},"symbol":{"type":"string"},"resolution":{"type":"string","enum":["1h","1d"]},"startTimestamp":{"type":"string","format":"date-time"},"endTimestamp":{"type":"string","format":"date-time"},"timestamp":{"type":"string","format":"date-time"}}},"CollateralConfig":{"type":"object","description":"Current LTV configuration for a collateral vault","properties":{"collateral":{"type":"string","description":"Collateral vault address"},"vaultType":{"type":"string","enum":["evk","earn","securitize"],"description":"Vault family for the collateral address"},"collateralName":{"type":"string","description":"Collateral vault name"},"collateralSymbol":{"type":"string","description":"Collateral vault symbol"},"asset":{"type":"string","description":"Underlying asset address of the collateral vault"},"assetSymbol":{"type":"string","description":"Underlying asset symbol"},"assetDecimals":{"type":"integer","description":"Underlying asset decimals"},"borrowLTV":{"type":"string","description":"Maximum LTV for borrowing (basis points as string, e.g., \"8500\" = 85%)"},"liquidationLTV":{"type":"string","description":"LTV at which liquidation can occur (basis points as string)"},"initialLiquidationLTV":{"type":"string","description":"Initial liquidation LTV before ramping"},"targetTimestamp":{"type":"string","format":"date-time","nullable":true,"description":"ISO timestamp when LTV ramp completes"},"rampDuration":{"type":"integer","description":"Duration of LTV ramp in seconds"}}},"LtvHistoryItem":{"type":"object","description":"Historical LTV configuration change","properties":{"collateral":{"type":"string","description":"Collateral vault address"},"borrowLTV":{"type":"string","description":"Borrow LTV (basis points as string)"},"liquidationLTV":{"type":"string","description":"Liquidation LTV (basis points as string)"},"initialLiquidationLTV":{"type":"string","description":"Initial liquidation LTV before ramping"},"borrowLtv":{"type":"number","description":"Legacy decimal alias for `borrowLTV`."},"liquidationLtv":{"type":"number","description":"Legacy decimal alias for `liquidationLTV`."},"initialLiquidationLtv":{"type":"number","description":"Legacy decimal alias for `initialLiquidationLTV`."},"targetTimestamp":{"type":"string","format":"date-time","nullable":true,"description":"ISO timestamp when LTV ramp completes"},"rampDuration":{"type":"integer","description":"Duration of LTV ramp in seconds"},"blockNumber":{"type":"string","description":"Block number of the change"},"timestamp":{"type":"string","format":"date-time","description":"Timestamp of the change"},"txHash":{"type":"string","description":"Transaction hash"},"logIndex":{"type":"integer","description":"Log index within the transaction receipt."}}},"CapHistoryItem":{"type":"object","description":"Historical cap configuration change","properties":{"supplyCap":{"type":"string","description":"Raw encoded EVK uint16 supply cap as a decimal string. Encoded zero means unlimited; use supplyCapDecoded in baseline mode for the resolved amount."},"borrowCap":{"type":"string","description":"Raw encoded EVK uint16 borrow cap as a decimal string. Encoded zero means unlimited; use borrowCapDecoded in baseline mode for the resolved amount."},"blockNumber":{"type":"string","description":"Block number of the change"},"timestamp":{"type":"string","format":"date-time","description":"Timestamp of the change"},"txHash":{"type":"string","description":"Transaction hash"},"logIndex":{"type":"integer","description":"Log index within the transaction receipt."}}},"DecodedAmountCap":{"type":"object","required":["encoded","amountRaw","unlimited","unit"],"properties":{"encoded":{"type":"string","description":"Raw uint16 decimal encoding."},"amountRaw":{"type":"string","nullable":true,"description":"Exact resolved integer amount in asset base units. Null when unlimited; a finite cap can resolve to zero."},"unlimited":{"type":"boolean"},"unit":{"type":"string","enum":["asset_base_units"]}}},"DecodedCapHistoryItem":{"allOf":[{"$ref":"#/components/schemas/CapHistoryItem"},{"type":"object","required":["supplyCapDecoded","borrowCapDecoded"],"properties":{"supplyCapDecoded":{"$ref":"#/components/schemas/DecodedAmountCap"},"borrowCapDecoded":{"$ref":"#/components/schemas/DecodedAmountCap"}}}]},"CapHistoryWithBaseline":{"type":"object","required":["events","baseline","baselineStatus","eventStorage","usdValuation"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/DecodedCapHistoryItem"}},"baseline":{"oneOf":[{"$ref":"#/components/schemas/DecodedCapHistoryItem"},{"type":"object","nullable":true,"not":{"type":"object"}}],"description":"Latest retained cap event at or before from, independently of offset. A boundary event can appear both here and in events."},"baselineStatus":{"type":"string","enum":["available","unknown","unavailable"],"description":"Unknown means no retained event at or before from. Unavailable means event storage could not be read."},"eventStorage":{"type":"string","enum":["available","unavailable"],"description":"Whether retained event storage is readable, not a guarantee of complete indexed history."},"usdValuation":{"type":"string","enum":["unavailable"],"description":"Historical cap USD valuations are not supplied."}}},"VaultUtilizationHealthItem":{"type":"object","description":"Vault utilization health row","required":["chainId","vault","utilization","totalBorrows","cash","totalAssets","thresholdExceeded"],"properties":{"chainId":{"type":"integer","description":"Chain ID"},"vault":{"type":"string","description":"Vault address"},"utilization":{"type":"number","description":"Current borrowed-assets ratio"},"totalBorrows":{"type":"string","description":"Current total borrowed assets"},"cash":{"type":"string","description":"Current unborrowed assets"},"totalAssets":{"type":"string","description":"Current total supplied assets"},"thresholdExceeded":{"type":"boolean","description":"Whether utilization meets or exceeds the requested threshold"}}},"VaultCapHealthItem":{"type":"object","description":"Vault cap-usage health row","properties":{"chainId":{"type":"integer","description":"Chain ID"},"vault":{"type":"string","description":"Vault address"},"capUsage":{"type":"number","description":"Maximum of `supplyCapUsage` and `borrowCapUsage`"},"supplyCap":{"type":"string","description":"Supply cap in resolved asset units"},"supplyCapUsage":{"type":"number","description":"Current supply-cap usage ratio"},"borrowCap":{"type":"string","description":"Borrow cap in resolved asset units"},"borrowCapUsage":{"type":"number","description":"Current borrow-cap usage ratio"},"totalAssets":{"type":"string","description":"Current total supplied assets"},"totalBorrows":{"type":"string","description":"Current total borrowed assets"},"thresholdExceeded":{"type":"boolean","description":"Whether `capUsage` meets or exceeds the requested threshold"}}},"IrmHistoryItem":{"type":"object","description":"Historical interest rate model change","properties":{"interestRateModel":{"type":"string","description":"Interest rate model contract address"},"blockNumber":{"type":"string","description":"Block number of the change"},"timestamp":{"type":"string","format":"date-time","description":"Timestamp of the change"},"txHash":{"type":"string","description":"Transaction hash"},"logIndex":{"type":"integer","description":"Log index within the transaction receipt."}}},"ConfigHistoryItem":{"type":"object","description":"One configuration change of the vault.","properties":{"type":{"type":"string","enum":["ltv","cap","irm"],"description":"Kind of change."},"data":{"type":"object","additionalProperties":true,"description":"The values set by the change, by `type`. `ltv`: `collateral` (checksummed address), `borrowLTV`, `liquidationLTV` and `initialLiquidationLTV` as basis-point strings, their legacy fraction aliases `borrowLtv`, `liquidationLtv` and `initialLiquidationLtv`, `targetTimestamp` (ISO date-time, null when no ramp is set) and `rampDuration` (seconds). `cap`: `supplyCap` and `borrowCap` as the raw EVK uint16 encodings in JSON integers, not resolved amounts; encoded zero means unlimited. `irm`: `interestRateModel` (checksummed address)."},"blockNumber":{"type":"string","description":"Block number of the change"},"timestamp":{"type":"string","format":"date-time","description":"Timestamp of the change"},"txHash":{"type":"string","description":"Transaction hash"},"logIndex":{"type":"integer","description":"Log index within the transaction receipt."}}},"AddressScreeningRequest":{"type":"object","additionalProperties":false,"required":["address"],"properties":{"address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"chain":{"type":"string","minLength":1,"maxLength":50,"pattern":"^[a-zA-Z0-9_-]+$","default":"all","description":"TRM chain identifier. Defaults to `all`, which screens the address across every chain TRM supports; pass a single-chain identifier (e.g. `ethereum`) to narrow the scope."},"vpnIsUsed":{"type":"boolean","nullable":true,"description":"Optional VPN-detection flag retained for audit. Omit or send null when not measured."}}},"AddressScreeningResponse":{"type":"object","required":["address","addressIsSuspicious","screenedAt","resolvedChain","cached","ruleVersion"],"properties":{"evaluationId":{"type":"string","format":"uuid","description":"Platform sessions only. The evaluation the answer rests on."},"matchedRules":{"type":"array","items":{"type":"string"},"description":"Platform sessions only. The policy rules that matched."},"expiresAt":{"type":"string","format":"date-time","description":"Platform sessions only. Until when the evaluation is reused."},"providerStatusCode":{"type":"integer","description":"Platform sessions only."},"providerResponse":{"description":"Platform sessions only. The raw provider payload as retained."},"address":{"type":"string","description":"EIP-55 checksummed address."},"addressIsSuspicious":{"type":"boolean"},"screenedAt":{"type":"string","format":"date-time"},"resolvedChain":{"type":"string","description":"Chain accepted by TRM after its compatibility fallback, if required."},"cached":{"type":"boolean"},"ruleVersion":{"type":"string","example":"trm-custom-v1"}}},"AddressScreeningEvaluationRecord":{"type":"object","required":["id","provider","address","requestedChain","resolvedChain","addressIsSuspicious","ruleVersion","matchedRules","providerResponse","providerStatusCode","evaluatedAt","expiresAt"],"properties":{"id":{"type":"string","format":"uuid"},"provider":{"type":"string","example":"trm"},"address":{"type":"string","description":"EIP-55 checksummed address."},"requestedChain":{"type":"string"},"resolvedChain":{"type":"string"},"addressIsSuspicious":{"type":"boolean"},"ruleVersion":{"type":"string"},"matchedRules":{"type":"array","items":{"type":"string"}},"providerResponse":{"description":"The raw provider payload as retained for compliance review."},"providerStatusCode":{"type":"integer"},"evaluatedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"}}},"AddressScreeningRequestRecord":{"type":"object","required":["id","apiKeyId","apiKeyPrefix","platformAdminId","evaluationId","address","chain","vpnIsUsed","cacheHit","outcome","failureCode","providerStatusCode","requestedAt"],"properties":{"id":{"type":"string","format":"uuid"},"apiKeyId":{"type":"string","format":"uuid","nullable":true,"description":"The key that asked; null when a platform session did."},"apiKeyPrefix":{"type":"string","description":"The key's prefix, or `platform-session`."},"platformAdminId":{"type":"string","format":"uuid","nullable":true,"description":"The operator whose platform session asked; null for key requests."},"evaluationId":{"type":"string","format":"uuid","nullable":true,"description":"The evaluation the request produced or reused; null for rejected or failed requests."},"address":{"type":"string","nullable":true,"description":"EIP-55 checksummed address, or null when the request could not be parsed safely."},"chain":{"type":"string","nullable":true},"vpnIsUsed":{"type":"boolean","nullable":true},"cacheHit":{"type":"boolean"},"outcome":{"type":"string","enum":["completed","failed"]},"failureCode":{"type":"string","nullable":true},"providerStatusCode":{"type":"integer","nullable":true},"requestedAt":{"type":"string","format":"date-time"}}},"AddressScreeningActivity":{"type":"object","required":["generatedAt","windows"],"properties":{"generatedAt":{"type":"string","format":"date-time"},"windows":{"type":"array","items":{"type":"object","required":["hours","since","providerCalls","flagged","requests","cacheHits","failed"],"properties":{"hours":{"type":"integer"},"since":{"type":"string","format":"date-time"},"providerCalls":{"type":"integer","description":"Retained evaluations in the window, one per provider call."},"flagged":{"type":"integer"},"requests":{"type":"integer","description":"Every screening request in the window, whatever its outcome."},"cacheHits":{"type":"integer"},"failed":{"type":"integer"}}}}}},"UsageStatsResponse":{"type":"object","required":["identifier","key","stats","rateLimit"],"properties":{"identifier":{"type":"string"},"key":{"type":"object","required":["id","prefix","name","rateLimit","createdAt","lastUsedAt"],"properties":{"id":{"type":"string"},"prefix":{"type":"string"},"name":{"type":"string"},"rateLimit":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"lastUsedAt":{"type":"string","format":"date-time","nullable":true}}},"stats":{"type":"object","required":["daily","weekly","topEndpoints"],"properties":{"daily":{"type":"object","required":["totalRequests","avgResponseTimeMs","errorCount"],"properties":{"totalRequests":{"type":"integer"},"avgResponseTimeMs":{"type":"integer"},"errorCount":{"type":"integer"}}},"weekly":{"type":"object","required":["totalRequests","avgResponseTimeMs","errorCount"],"properties":{"totalRequests":{"type":"integer"},"avgResponseTimeMs":{"type":"integer"},"errorCount":{"type":"integer"}}},"topEndpoints":{"type":"array","items":{"type":"object","required":["path","method","count","avgResponseTimeMs"],"properties":{"path":{"type":"string"},"method":{"type":"string"},"count":{"type":"integer"},"avgResponseTimeMs":{"type":"integer"}}}}}},"rateLimit":{"type":"object","required":["limit","window"],"properties":{"limit":{"type":"integer"},"window":{"type":"string"}}}}},"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."},"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"}]}}},"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}}},"LabelCampaign":{"type":"object","additionalProperties":false,"required":["name","type"],"properties":{"name":{"type":"string"},"logo":{"type":"string","nullable":true},"type":{"type":"string","enum":["deposit","borrow"]}}},"VaultLabels":{"type":"object","required":["chainId","address","vaultType","isEscrow","isDeprecated","notExplorableLend","notExplorableBorrow","tags","resolved","createdAt","updatedAt"],"properties":{"chainId":{"type":"integer","minimum":1},"address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"vaultType":{"type":"string","enum":["evk","earn","securitize"],"description":"Vault family derived from indexed discovery. An escrow vault is `evk` with `isEscrow: true`."},"isEscrow":{"type":"boolean","description":"True for an EVK vault the escrow perspective has verified as collateral-only. Derived by Euler from the perspective and never accepted in a request body; such a vault has no entity, no product and no curator listing flags."},"visibility":{"oneOf":[{"$ref":"#/components/schemas/VaultVisibilitySummary"},{"$ref":"#/components/schemas/VaultVisibility"}],"nullable":true,"description":"Present only on `GET /v3/labels/vaults?include=visibility`: the row's visibility verdict, or null when none has been evaluated yet. The public summary for most readers; the record as evaluated (`VaultVisibility`) when the route has authenticated a platform session."},"productId":{"type":"string","nullable":true},"entityId":{"type":"string","nullable":true,"description":"Entity associated through verified on-chain ownership, or null for unclaimed and escrow vaults."},"name":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"portfolioNotice":{"type":"string","nullable":true},"isDeprecated":{"type":"boolean"},"deprecationReason":{"type":"string","nullable":true},"notExplorableLend":{"allOf":[{"$ref":"#/components/schemas/ListingFlag"}],"description":"Curator lend-side listing flag; overrides the product flag for this vault."},"notExplorableBorrow":{"allOf":[{"$ref":"#/components/schemas/ListingFlag"}],"description":"Curator borrow-side listing flag; overrides the product flag for this vault. Earn vaults have no borrow side and reject `true`."},"tags":{"type":"array","description":"Union of entity-managed label tags and platform-managed assessment tags, sorted, deduplicated. The label row may only carry the curator vocabulary (`keyring`, `access control`, `governance limited`, `suppress high utilisation warning`, `cyclical note`); every other tag (`recently added` and the Base app's `base` included) can only come from the assessment, so a non-vocabulary tag here was set by the platform. Published reads union the published row with the live assessment.","items":{"type":"string"}},"campaigns":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/LabelCampaign"}},"resolved":{"$ref":"#/components/schemas/ResolvedVaultLabels"},"assignedBy":{"type":"string","nullable":true,"description":"The platform administrator who assigned the vault to its curator (a platform registration or transfer); null for a curator's own claim and on published reads. Layer 2 verifies an assigned vault whose governing address (the governor of an EVK or Securitize vault, the owner of an Earn vault) is the zero address."},"assignedAt":{"type":"string","format":"date-time","nullable":true,"description":"When Euler assigned the vault; null when `assignedBy` is null."},"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"}]}}},"ResolvedVaultLabels":{"type":"object","readOnly":true,"description":"Read-time display cascade (vault label, else product, else indexed on-chain identity; escrow vaults get a fixed name). Raw fields stay authoritative for editing — this block is derived and never stored.","required":["name","description","portfolioNotice","deprecated","deprecationReason","entityId","url","logo"],"properties":{"name":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"portfolioNotice":{"type":"string","nullable":true},"deprecated":{"type":"boolean","description":"Vault or product deprecation."},"deprecationReason":{"type":"string","nullable":true,"description":"Reason from the nearest actively deprecated source; null when nothing is deprecated. Retained reasons on non-deprecated rows never contribute."},"entityId":{"type":"string","nullable":true,"description":"Vault entity, inherited from the product when unset."},"url":{"type":"string","nullable":true,"description":"Product url, falling back to the entity url."},"logo":{"type":"string","nullable":true,"description":"Product logo, falling back to the entity logo."}}},"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."}}},"ResolvedVaultLabelsView":{"type":"object","readOnly":true,"description":"Consumer-facing vault-label shape (`view=resolved`) — the display cascade flattened to the top level; raw label fields are omitted. entityId and deprecation are the resolved values with product inheritance applied.","required":["chainId","address","vaultType","isEscrow","productId","entityId","name","description","portfolioNotice","deprecated","deprecationReason","notExplorableLend","notExplorableBorrow","url","logo","tags","campaigns","createdAt","updatedAt"],"properties":{"chainId":{"type":"integer","minimum":1},"address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"vaultType":{"type":"string","enum":["evk","earn","securitize"],"description":"An escrow vault is `evk` with the `isEscrow` flag set."},"isEscrow":{"type":"boolean","description":"True for an EVK vault the escrow perspective has verified as collateral-only."},"visibility":{"oneOf":[{"$ref":"#/components/schemas/VaultVisibilitySummary"},{"$ref":"#/components/schemas/VaultVisibility"}],"nullable":true,"description":"Present only on `GET /v3/labels/vaults?include=visibility`: the row's visibility verdict, or null when none has been evaluated yet. The public summary for most readers; the record as evaluated (`VaultVisibility`) when the route has authenticated a platform session."},"productId":{"type":"string","nullable":true},"entityId":{"type":"string","nullable":true},"name":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"portfolioNotice":{"type":"string","nullable":true},"deprecated":{"type":"boolean"},"deprecationReason":{"type":"string","nullable":true},"notExplorableLend":{"allOf":[{"$ref":"#/components/schemas/ListingFlag"}],"description":"Raw vault-level curator flag; the effective listing is on the vault row's `visibility`."},"notExplorableBorrow":{"allOf":[{"$ref":"#/components/schemas/ListingFlag"}],"description":"Raw vault-level curator flag; the effective listing is on the vault row's `visibility`."},"url":{"type":"string","nullable":true},"logo":{"type":"string","nullable":true},"tags":{"type":"array","description":"Same union as `VaultLabels.tags` (label-row vocabulary tags plus platform assessment tags).","items":{"type":"string"}},"campaigns":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/LabelCampaign"}},"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"}]}}},"ResolvedProductLabelsView":{"type":"object","readOnly":true,"description":"Consumer-facing product shape (`view=resolved`) — entity fallbacks applied to url and logo, entityName included, resolved wrapper omitted.","required":["id","chainId","entityId","entityName","coBrandEntityIds","name","logo","description","url","portfolioNotice","isDeprecated","deprecationReason","notExplorable","governanceMode","anyExplorableLend","anyExplorableBorrow","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"chainId":{"type":"integer","minimum":1},"entityId":{"type":"string"},"entityName":{"type":"string","nullable":true},"coBrandEntityIds":{"type":"array","items":{"type":"string"}},"name":{"type":"string"},"logo":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"url":{"type":"string","nullable":true},"portfolioNotice":{"type":"string","nullable":true},"isDeprecated":{"type":"boolean"},"deprecationReason":{"type":"string","nullable":true},"notExplorable":{"$ref":"#/components/schemas/ListingFlag"},"governanceMode":{"type":"string","enum":["governed","ungoverned","unknown"],"description":"Governance mode recorded at the selected label version. See `ProductLabels.governanceMode`."},"anyExplorableLend":{"type":"boolean"},"anyExplorableBorrow":{"type":"boolean"},"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"}]}}},"GeoPolicy":{"type":"object","required":["id","countries","countriesResolved","policyType","createdAt","updatedAt","version","derivedFrom","createdBy","updatedBy"],"properties":{"id":{"type":"string","format":"uuid"},"chainId":{"type":"integer","minimum":1,"nullable":true},"productId":{"type":"string","nullable":true},"vaultAddress":{"type":"string","nullable":true,"pattern":"^0x[a-fA-F0-9]{40}$"},"assetAddress":{"type":"string","nullable":true,"pattern":"^0x[a-fA-F0-9]{40}$"},"assetSymbols":{"type":"array","nullable":true,"description":"Case-insensitive exact symbol matchers.","items":{"type":"string"}},"assetSymbolRegex":{"type":"string","nullable":true,"maxLength":512,"description":"Case-insensitive regular expression matched against token symbols."},"assetNames":{"type":"array","nullable":true,"description":"Case-insensitive exact token-name matchers.","items":{"type":"string"}},"assetNameRegex":{"type":"string","nullable":true,"maxLength":512,"description":"Case-insensitive regular expression matched against token names."},"countries":{"type":"array","minItems":1,"description":"As authored — ISO 3166-1 alpha-2 codes and group aliases (`EU`, `EEA`, `EFTA`). Unknown entries are rejected at write time.","items":{"type":"string","minLength":1}},"countriesResolved":{"type":"array","readOnly":true,"description":"Read-time expansion of `countries` — group aliases replaced by their current member codes, deduplicated and sorted. Consumers evaluate against this list; a rule authored with an alias tracks the bloc's current membership.","items":{"type":"string"}},"policyType":{"type":"string","enum":["block","restrict"]},"reason":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time","description":"When the row last changed. Rows written before it was recorded carry their creation time."},"version":{"type":"string","nullable":true,"readOnly":true,"description":"Opaque version of the row, `<updatedAt>|<changeId>`. Send it as `expectedVersion` with `POST /v3/changes` (domain `geo`, key the policy ID); a stale one records a superseded change instead of writing. Null on a derived row, which cannot be changed."},"derivedFrom":{"type":"object","nullable":true,"readOnly":true,"required":["policyId","assetAddress","relation","path"],"description":"Set on a row the server derives from a stored asset rule, null on a stored row. A derived row copies the rule's countries, type, reason and product or vault scope onto one token the app reaches that is built on an asset the rule selects (an ERC-4626 wrapper, an escrow, EVK or Earn share, an Earn allocation, a Pendle SY, PT, YT or LP). Shared code never derives a row. Its `id` is a stable UUID of version 8; it has no authors and is not writable.","properties":{"policyId":{"type":"string","format":"uuid","description":"The stored rule."},"assetAddress":{"type":"string","description":"The asset the stored rule selects."},"relation":{"type":"string","enum":["erc4626","evk-share","escrow-share","earn-share","securitize-share","earn-allocation","pendle-pt","pendle-lp","pendle-sy","pendle-yt"],"description":"The last link from the derived token to the asset."},"path":{"type":"array","items":{"type":"string"},"description":"From the derived token to the selected asset, both included."}}},"createdBy":{"$ref":"#/components/schemas/RowAuthor"},"updatedBy":{"$ref":"#/components/schemas/RowAuthor"}}},"VaultConfigOverrides":{"description":"A proposed EVK vault configuration as changes to the live one. Every kind is optional; addresses are 0x-prefixed, LTVs and caps are decimal integer strings in the units the assessment reports them (basis points for LTVs, resolved asset units for caps).","type":"object","additionalProperties":false,"properties":{"caps":{"type":"object","additionalProperties":false,"properties":{"supplyCap":{"type":"string","pattern":"^\\d+$"},"borrowCap":{"type":"string","pattern":"^\\d+$"}}},"collaterals":{"type":"array","maxItems":50,"items":{"type":"object","additionalProperties":false,"required":["collateral"],"properties":{"collateral":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"borrowLTV":{"type":"string","pattern":"^\\d+$"},"liquidationLTV":{"type":"string","pattern":"^\\d+$"},"initialLiquidationLTV":{"type":"string","pattern":"^\\d+$"},"targetTimestamp":{"type":"integer","minimum":0},"rampDuration":{"type":"integer","minimum":0},"remove":{"type":"boolean","description":"Drop the collateral row instead of changing it."}}}},"interestRateModel":{"type":"object","additionalProperties":false,"required":["address"],"properties":{"address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"}}},"resolvedVaults":{"type":"array","maxItems":50,"description":"`govSetResolvedVault(vault, resolved)` on the vault's router: the entry the lens would report after it (the vault, its asset, the unit of account, the unwrap chain) is added or removed, so a route staged in the same batch on the vault's asset prices it. A vault with an adapter configured for itself keeps answering through it either way, as the router reads the configured pair before any resolution.","items":{"type":"object","additionalProperties":false,"required":["vault","resolved"],"properties":{"vault":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"resolved":{"type":"boolean"}}}},"oracleRoutes":{"type":"array","maxItems":50,"items":{"type":"object","additionalProperties":false,"required":["base"],"properties":{"base":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"quote":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Defaults to the vault's unit of account."},"adapter":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Required unless `remove` is true."},"remove":{"type":"boolean"}}}},"hooks":{"type":"object","additionalProperties":false,"properties":{"hookTarget":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"hookedOperations":{"type":"object","additionalProperties":false,"properties":{"deposit":{"type":"boolean"},"mint":{"type":"boolean"},"withdraw":{"type":"boolean"},"redeem":{"type":"boolean"},"transfer":{"type":"boolean"},"skim":{"type":"boolean"},"borrow":{"type":"boolean"},"repay":{"type":"boolean"},"repayWithShares":{"type":"boolean"},"pullDebt":{"type":"boolean"},"convertFees":{"type":"boolean"},"liquidate":{"type":"boolean"},"flashloan":{"type":"boolean"},"touch":{"type":"boolean"},"vaultStatusCheck":{"type":"boolean"}}}}}}},"VaultConfigPreviewRequest":{"type":"object","additionalProperties":false,"properties":{"overrides":{"$ref":"#/components/schemas/VaultConfigOverrides"}}},"VaultConsistencyContext":{"type":"object","nullable":true,"description":"The findings behind a Layer 2 verdict, for the policies that grade more than ownership. An Earn vault's: whether each strategy it can hold funds in (a cap or a withdraw-queue slot) and each active collateral of those strategies is escrow or shown (claimed, assigned to a product, not suspended in its own Layer 2 check, and passing Layer 1 when the vault's entity claims it), gating always for the vault entity's own and, for another curator's, only until acceptable after the curator's latest cap increase; a deprecated one only warns. And whether its owner, unless renounced, and its curator, when one is set, are addresses an entity registers. Null for every other vault, and for an Earn vault suspended on ownership whose Earn state could not be read; replaced by each completed Layer 2 check. The first required failure is `consistencyReason`; a failed advisory badges the vault `warning`.","required":["policyId","policyVersion","outcome","evaluatedAt","blockNumber","findings"],"properties":{"policyId":{"type":"string","enum":["euler-earn-consistency"]},"policyVersion":{"type":"integer"},"outcome":{"type":"string","enum":["pass","fail","unknown","not_applicable"]},"evaluatedAt":{"type":"string","format":"date-time"},"blockNumber":{"type":"string","nullable":true},"findings":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/VaultConfigFinding"},{"type":"object","properties":{"key":{"type":"string","x-finding-keys":["governance.owner-registered","governance.curator-registered"],"x-finding-key-namespaces":[{"pattern":"strategy.<address>.<rule>","policies":["euler-earn-consistency"],"rules":["visible"],"description":"One per strategy in scope; <address> is the lowercase strategy vault address. `observed.link` is `{ phase, committedAtBlock, committedAtLogIndex, acceptedAt }`. `own` (claimed by the vault's entity) and `admission` (not acceptable since the curator's latest cap increase) gate; `accepted`, `drift` (failing after acceptance, or a collateral activated after the increase) and `uncapped` (cap zero) do not."},{"pattern":"collateral.<address>.<rule>","policies":["euler-earn-consistency"],"rules":["visible"],"description":"One per active collateral of those strategies; <address> is the lowercase collateral vault address."},{"pattern":"scheduled.<rule>","policies":["euler-earn-consistency"],"rules":["strategy.<address>.visible","collateral.<address>.visible","governance.owner-registered"],"description":"A pending change graded by the rule it will face once accepted, a strategy a pending cap adds, a collateral it brings, or an owner transfer awaiting acceptance. Never required, so outside `outcome`, `consistencyStatus` and visibility. `observed` is `{ pending, validAt, submittedAtBlock }`; `validAt` is null for an owner transfer."}]}}}]}}}},"VaultConfigFinding":{"description":"One Layer 1 finding, as in `VaultConfigAssessmentContext.findings`.","type":"object","required":["key","outcome","required","description"],"properties":{"key":{"type":"string"},"outcome":{"type":"string","enum":["pass","fail","unknown","not_applicable"]},"required":{"type":"boolean"},"description":{"type":"string"},"expected":{},"observed":{},"cause":{"type":"object","description":"Why this is not a pass. On `fail` and `unknown` it is the failure; on `not_applicable` it is why the rule did not run, and its absence on an `evidence.*` row is what separates a skipped check from an observation. The rule key alone cannot say: `hooks.zero-or-trusted` fails either because the hook target is untrusted or because a zero target disabled an exit operation, and those have opposite remedies. Switch on `code`; `subject` is the value to act on; `summary` is one sentence naming it, and is what `configReason` carries for the blocking finding.","required":["code","subject","summary","remedy"],"properties":{"code":{"type":"string","enum":["deposit-only-vault","feed-revert-tolerated","curator-unset","owner-renounced","not-a-recognized-evault","deployment-record-unavailable","liability-asset-is-evault","evc-compatible-asset-flag-set","hook-target-untrusted","exit-operations-disabled","oracle-unset","unit-of-account-unset","interest-rate-model-unset","router-not-recognized","router-has-fallback","router-config-unreadable","route-has-no-unit-of-account-adapter","collateral-route-skips-evault-asset","quote-reverted","quote-returned-zero","pyth-feed-discontinued","pyth-update-unconfirmed","pyth-feed-unattributed","pyth-receiver-incompatible","session-feed-tolerance-withdrawn","quote-unavailable","interest-rate-model-reverts","interest-rate-model-not-probed","borrow-apy-above-bound","router-governor-outside-entity","timelock-too-short","liquidation-discount-out-of-range","liquidation-cool-off-out-of-range","collateral-ltv-out-of-range","dependency-not-verified","dependency-not-assessed","route-adapter-unrecognized","route-adapter-unassessed","route-adapter-checks-failing","dependency-unclaimed","dependency-hidden","dependency-deprecated","governing-address-unregistered","vault-paused","compliance-service-unresolvable","compliance-probe-unavailable"]},"subject":{"type":"string","nullable":true,"description":"The one value to act on -- an address, or a formatted parameter value. Null when the rule names none."},"summary":{"type":"string","description":"One sentence naming the value that failed, not the requirement it failed."},"remedy":{"type":"string","nullable":true,"description":"Which way out applies. Null when the answer is not the reader's to act on.","enum":["have-euler-trust-the-hook-target","restore-the-disabled-exit-operations","make-the-vault-deposit-only","set-an-interest-rate-model","use-a-recognized-euler-router","remove-the-router-fallback","add-the-missing-oracle-route","replace-the-oracle-adapter","review-the-oracle-adapter","move-router-governance-to-the-entity","change-the-vault-parameter","wait-for-the-dependency-verdict","wait-for-euler-to-check-again","unpause-the-vault","remove-the-dependency","register-the-address","contact-euler"]}}},"exempted":{"type":"boolean"}}},"VaultAssessmentFindingChange":{"type":"object","required":["key","before","after"],"properties":{"key":{"type":"string"},"before":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/VaultConfigFinding"}],"description":"The stored finding; null when the preview introduces the key."},"after":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/VaultConfigFinding"}],"description":"The previewed finding; null when the change removes the key."}}},"VaultAssessmentPreview":{"description":"What a fresh Layer 1 check would say, in the shape of the vault's kind: `family` names the variant. EVK previews may carry applied overrides and findings whose simulation could not run; Earn and Securitize previews accept no overrides and answer both lists empty. Each variant lists the finding keys its policy can produce.","oneOf":[{"$ref":"#/components/schemas/VaultAssessmentPreviewEvk"},{"$ref":"#/components/schemas/VaultAssessmentPreviewEarn"},{"$ref":"#/components/schemas/VaultAssessmentPreviewSecuritize"}],"discriminator":{"propertyName":"family","mapping":{"evk":"#/components/schemas/VaultAssessmentPreviewEvk","earn":"#/components/schemas/VaultAssessmentPreviewEarn","securitize":"#/components/schemas/VaultAssessmentPreviewSecuritize"}}},"VaultAssessmentPreviewEvk":{"allOf":[{"$ref":"#/components/schemas/VaultAssessmentPreviewBase"},{"type":"object","required":["family","policyId"],"properties":{"family":{"type":"string","enum":["evk"]},"policyId":{"type":"string","enum":["euler-evk"]},"findings":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/VaultConfigFinding"},{"type":"object","properties":{"key":{"type":"string","x-finding-keys":["deployment.recognized-factory","deployment.no-evault-nesting","configuration.evc-compatible-asset","hooks.zero-or-trusted","market.oracle-present","market.unit-of-account-present","market.interest-rate-model-present","oracle.recognized-router","oracle.no-fallback","oracle.liability-route","oracle.liability-quote","oracle.adapters-recognized","oracle.adapters-checks","irm.rate-computation","irm.max-apy","governance.router","liquidation.max-discount","liquidation.cool-off","evidence.vault-mode","evidence.upgradeable","evidence.unit-of-account","evidence.interest-fee","evidence.fee-receiver","evidence.governance","evidence.multisig","evidence.caps","evidence.interest-rate-model","evidence.debt-socialization","evidence.inert-collateral-entries","evidence.route-adapters","evidence.resolved-vaults","evidence.liability-price","evidence.pyth-unserved-feeds","evidence.pyth-recovery-issues"],"x-finding-key-namespaces":[{"pattern":"collateral.<address>.<rule>","policies":["euler-evk"],"rules":["ltv","route","recognized","ramp","price","quote"]}]}}}]}}}}]},"VaultAssessmentPreviewEarn":{"allOf":[{"$ref":"#/components/schemas/VaultAssessmentPreviewBase"},{"type":"object","required":["family","policyId"],"properties":{"family":{"type":"string","enum":["earn"]},"policyId":{"type":"string","enum":["euler-earn"]},"findings":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/VaultConfigFinding"},{"type":"object","properties":{"key":{"type":"string","x-finding-keys":["governance.timelock","evidence.guardian","evidence.multisig","evidence.fee","evidence.queues","evidence.escrow-sink","evidence.pending-activity","evidence.scheduled-changes","evidence.asset"],"x-finding-key-namespaces":[{"pattern":"strategy.<address>.<rule>","policies":["euler-earn"],"rules":["recognized"]},{"pattern":"scheduled.<rule>","policies":["euler-earn"],"rules":["strategy.<address>.recognized","governance.timelock"]}]}}}]}},"appliedOverrides":{"type":"array","maxItems":0,"items":{"type":"string"},"description":"Always empty; this vault kind accepts no overrides."},"notSimulated":{"type":"array","maxItems":0,"items":{"type":"string"},"description":"Always empty; nothing is simulated for this vault kind."}}}]},"VaultAssessmentPreviewSecuritize":{"allOf":[{"$ref":"#/components/schemas/VaultAssessmentPreviewBase"},{"type":"object","required":["family","policyId"],"properties":{"family":{"type":"string","enum":["securitize"]},"policyId":{"type":"string","enum":["euler-securitize"]},"findings":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/VaultConfigFinding"},{"type":"object","properties":{"key":{"type":"string","x-finding-keys":["operations.not-paused","compliance.ds-token-wiring","evidence.controller-perspective","evidence.asset","evidence.supply-cap","evidence.multisig","evidence.freeze-activity","evidence.seize-activity"]}}}]}},"appliedOverrides":{"type":"array","maxItems":0,"items":{"type":"string"},"description":"Always empty; this vault kind accepts no overrides."},"notSimulated":{"type":"array","maxItems":0,"items":{"type":"string"},"description":"Always empty; nothing is simulated for this vault kind."}}}]},"VaultAssessmentPreviewBase":{"description":"The fields every preview answers, whatever the vault kind.","type":"object","required":["chainId","vaultAddress","persisted","family","policyId","policyVersion","blockNumber","blockHash","evaluatedAt","currentConfigStatus","configStatusIfApplied","outcome","localOutcome","checksStatus","summary","findings","changed","appliedOverrides","notSimulated"],"properties":{"chainId":{"type":"integer","minimum":1},"vaultAddress":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"persisted":{"type":"boolean","enum":[false]},"family":{"type":"string","enum":["evk","earn","securitize"]},"policyId":{"type":"string","enum":["euler-evk","euler-securitize","euler-earn"]},"policyVersion":{"type":"integer","minimum":1},"blockNumber":{"type":"string","pattern":"^\\d+$"},"blockHash":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$"},"evaluatedAt":{"type":"string","format":"date-time"},"currentConfigStatus":{"type":"string","enum":["unverified","pending","verified","suspended","revoked"],"description":"The stored Layer 1 status, `unverified` when nothing is stored yet."},"configStatusIfApplied":{"type":"string","enum":["unverified","pending","verified","suspended","revoked"],"description":"The status the stored check would write from `currentConfigStatus` and the previewed outcome."},"outcome":{"type":"string","enum":["pass","fail","unknown","not_applicable"]},"localOutcome":{"type":"string","enum":["pass","fail","unknown","not_applicable"]},"checksStatus":{"type":"string","enum":["positive","warning","negative"],"nullable":true,"description":"What the advisory findings would say if this configuration were applied. Same axis as `checksStatus` on the stored assessment."},"summary":{"type":"object","required":["passed","failed","unknown","notApplicable"],"properties":{"passed":{"type":"integer","minimum":0},"failed":{"type":"integer","minimum":0},"unknown":{"type":"integer","minimum":0},"notApplicable":{"type":"integer","minimum":0}}},"findings":{"type":"array","items":{"$ref":"#/components/schemas/VaultConfigFinding"}},"changed":{"type":"array","description":"Findings whose verdict differs from the stored assessment, added and removed ones included.","items":{"$ref":"#/components/schemas/VaultAssessmentFindingChange"}},"appliedOverrides":{"type":"array","items":{"type":"string"},"description":"One line per override applied, in the order applied."},"notSimulated":{"type":"array","items":{"type":"string"},"description":"Finding keys left unknown because their simulation could not run: a quote the probe could not reach, or `oracle.adapters-recognized` when the evaluate-only check refused a proposed adapter. Each finding names the reason in `observed`; the list is empty when every change the batch makes was simulated."}}},"VaultConfigAssessmentContext":{"type":"object","nullable":true,"required":["policyId","policyVersion","outcome","localOutcome","checksStatus","evaluatedAt","blockNumber","blockHash","findings","summary"],"properties":{"policyId":{"type":"string","enum":["euler-evk","euler-securitize","euler-earn"]},"policyVersion":{"type":"integer","minimum":1},"outcome":{"type":"string","enum":["pass","fail","unknown","not_applicable"]},"localOutcome":{"type":"string","description":"Verdict excluding collateral-recognition findings; used for cycle-safe recognition.","enum":["pass","fail","unknown","not_applicable"]},"checksStatus":{"type":"string","enum":["positive","warning","negative"],"nullable":true,"description":"Health of the advisory findings, orthogonal to the gating verdict in `configStatus`: the rules that disclose a curator's judgment call rather than suspend a vault. Null when the policy emitted no advisory finding. Same axis and vocabulary as an oracle adapter's `checksStatus`; a vault advisory never condemns, so this does not reach `negative`."},"evaluatedAt":{"type":"string","format":"date-time"},"blockNumber":{"type":"string","pattern":"^\\d+$"},"blockHash":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$"},"findings":{"type":"array","items":{"type":"object","required":["key","outcome","required","description"],"properties":{"key":{"type":"string","description":"Stable rule key. Static keys are listed in `x-finding-keys`; the templated namespaces are described in `x-finding-key-namespaces`. `evidence.*` keys are observations that never gate the verdict, but they are not the only non-gating findings: read `required` for that (`irm.max-apy` is advisory). A `scheduled.` key grades a pending timelocked change and never counts toward the verdict, `checksStatus`, `summary` or visibility. A required key ending in `.recognized` is a cross-entity recognition rule excluded from `localOutcome`. Keys are never renamed, only added.","x-finding-keys":["compliance.ds-token-wiring","configuration.evc-compatible-asset","deployment.no-evault-nesting","deployment.recognized-factory","evidence.asset","evidence.caps","evidence.controller-perspective","evidence.debt-socialization","evidence.escrow-sink","evidence.fee","evidence.fee-receiver","evidence.freeze-activity","evidence.governance","evidence.guardian","evidence.inert-collateral-entries","evidence.interest-fee","evidence.interest-rate-model","evidence.liability-price","evidence.multisig","evidence.pending-activity","evidence.pyth-recovery-issues","evidence.pyth-unserved-feeds","evidence.queues","evidence.resolved-vaults","evidence.route-adapters","evidence.scheduled-changes","evidence.seize-activity","evidence.supply-cap","evidence.unit-of-account","evidence.upgradeable","evidence.vault-mode","governance.router","governance.timelock","hooks.zero-or-trusted","irm.max-apy","irm.rate-computation","liquidation.cool-off","liquidation.max-discount","market.interest-rate-model-present","market.oracle-present","market.unit-of-account-present","operations.not-paused","oracle.adapters-checks","oracle.adapters-recognized","oracle.liability-quote","oracle.liability-route","oracle.no-fallback","oracle.recognized-router"],"x-finding-key-namespaces":[{"pattern":"collateral.<address>.<rule>","policies":["euler-evk"],"rules":["ltv","route","recognized","ramp","price","quote"],"description":"One group per active collateral of an EVK market vault; <address> is the lowercase collateral vault address. `recognized` reads the collateral's `localOutcome`."},{"pattern":"strategy.<address>.<rule>","policies":["euler-earn"],"rules":["recognized"],"description":"One group per active strategy of an Earn vault; <address> is the lowercase strategy vault address. `recognized` reads the strategy's full `outcome`, or its `localOutcome` when the strategy is itself an Earn vault. It is required until the strategy has passed after the curator's latest cap increase and advisory after, or while the vault caps it at zero; `observed.link` is `{ phase, committedAtBlock, committedAtLogIndex, acceptedAt }`."},{"pattern":"scheduled.<rule>","policies":["euler-earn"],"rules":["strategy.<address>.recognized","governance.timelock"],"description":"A timelocked change submitted on an Earn vault and not yet live, graded by the rule it will face once accepted, a strategy a pending cap adds or a pending timelock decrease. Never required, and outside `outcome`, `checksStatus`, `summary` and visibility. `observed` is `{ pending, validAt, submittedAtBlock }`, `pending` holding what the live rule would observe; a cause's summary starts with when the change can be accepted."}]},"outcome":{"type":"string","enum":["pass","fail","unknown","not_applicable"]},"required":{"type":"boolean","description":"Whether the finding gates the verdict. Required findings reduce into `outcome` and `localOutcome`; an advisory finding carries a real `pass`, `fail` or `unknown` outcome for the reader but never suspends the vault."},"description":{"type":"string"},"expected":{},"observed":{},"cause":{"type":"object","description":"Why this is not a pass. On `fail` and `unknown` it is the failure; on `not_applicable` it is why the rule did not run, and its absence on an `evidence.*` row is what separates a skipped check from an observation. The rule key alone cannot say: `hooks.zero-or-trusted` fails either because the hook target is untrusted or because a zero target disabled an exit operation, and those have opposite remedies. Switch on `code`; `subject` is the value to act on; `summary` is one sentence naming it, and is what `configReason` carries for the blocking finding.","required":["code","subject","summary","remedy"],"properties":{"code":{"type":"string","enum":["deposit-only-vault","feed-revert-tolerated","curator-unset","owner-renounced","not-a-recognized-evault","deployment-record-unavailable","liability-asset-is-evault","evc-compatible-asset-flag-set","hook-target-untrusted","exit-operations-disabled","oracle-unset","unit-of-account-unset","interest-rate-model-unset","router-not-recognized","router-has-fallback","router-config-unreadable","route-has-no-unit-of-account-adapter","collateral-route-skips-evault-asset","quote-reverted","quote-returned-zero","pyth-feed-discontinued","pyth-update-unconfirmed","pyth-feed-unattributed","pyth-receiver-incompatible","session-feed-tolerance-withdrawn","quote-unavailable","interest-rate-model-reverts","interest-rate-model-not-probed","borrow-apy-above-bound","router-governor-outside-entity","timelock-too-short","liquidation-discount-out-of-range","liquidation-cool-off-out-of-range","collateral-ltv-out-of-range","dependency-not-verified","dependency-not-assessed","route-adapter-unrecognized","route-adapter-unassessed","route-adapter-checks-failing","dependency-unclaimed","dependency-hidden","dependency-deprecated","governing-address-unregistered","vault-paused","compliance-service-unresolvable","compliance-probe-unavailable"]},"subject":{"type":"string","nullable":true,"description":"The one value to act on -- an address, or a formatted parameter value. Null when the rule names none."},"summary":{"type":"string","description":"One sentence naming the value that failed, not the requirement it failed."},"remedy":{"type":"string","nullable":true,"description":"Which way out applies. Null when the answer is not the reader's to act on.","enum":["have-euler-trust-the-hook-target","restore-the-disabled-exit-operations","make-the-vault-deposit-only","set-an-interest-rate-model","use-a-recognized-euler-router","remove-the-router-fallback","add-the-missing-oracle-route","replace-the-oracle-adapter","review-the-oracle-adapter","move-router-governance-to-the-entity","change-the-vault-parameter","wait-for-the-dependency-verdict","wait-for-euler-to-check-again","unpause-the-vault","remove-the-dependency","register-the-address","contact-euler"]}}},"exempted":{"type":"boolean","description":"True when a platform rule exemption downgraded this finding to evidence."}}}},"summary":{"type":"object","required":["passed","failed","unknown","notApplicable"],"properties":{"passed":{"type":"integer","minimum":0},"failed":{"type":"integer","minimum":0},"unknown":{"type":"integer","minimum":0},"notApplicable":{"type":"integer","minimum":0}}}}},"VaultAssessment":{"type":"object","required":["chainId","vaultAddress","configStatus","checksStatus","configContext","consistencyStatus","consistencyContext","riskStatus","isDeprecated","notExplorable","notExplorableLend","notExplorableBorrow","tags","schedulingTier","nextCheckAt","createdAt"],"properties":{"chainId":{"type":"integer","minimum":1},"vaultAddress":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"configStatus":{"type":"string","enum":["unverified","pending","verified","suspended","revoked"],"description":"Layer 1 (on-chain configuration safety) lifecycle. `unverified`: never verified, or the first check failed (`configContext.outcome` is `fail`). `verified`: the configuration policy passed. `suspended`: a re-check failed after the vault had been verified. `revoked`: set manually by a platform admin. `pending`: a platform admin requested a re-check through the PATCH endpoint; the automatic loop never writes this value. A due check is signalled by a non-null `configCheckAt`, not by the status, and a passing status is left unchanged while re-checks run."},"configReason":{"type":"string","nullable":true},"checksStatus":{"type":"string","enum":["positive","warning","negative"],"nullable":true,"description":"Health of the advisory findings, orthogonal to the gating verdict in `configStatus`: the rules that disclose a curator's judgment call rather than suspend a vault. Null when the policy emitted no advisory finding. Same axis and vocabulary as an oracle adapter's `checksStatus`; a vault advisory never condemns, so this does not reach `negative`."},"configContext":{"$ref":"#/components/schemas/VaultConfigAssessmentContext"},"configCheckAt":{"type":"string","format":"date-time","nullable":true,"description":"When the next Layer 1 check is due. Non-null means an on-chain change or a manual request is awaiting a check; cleared when the check completes."},"configLastCheckedAt":{"type":"string","format":"date-time","nullable":true,"description":"When Layer 1 last completed a check, whatever the outcome."},"schedulingTier":{"type":"string","enum":["active","background","static"],"description":"Which periodic sweep re-checks the vault. `active` (hourly): labeled and not deprecated in the latest published version, or total supply worth at least 100,000 USD, or a collateral or Earn strategy of such a vault; Layer 1's verdict plays no part, so a hidden vault stays hourly. `background` (daily): everything else. `static` (never swept): escrow vaults, whose configuration cannot change. Governance events trigger an immediate check whatever the tier. On a chain this deployment does not index the tier is the stored default and `nextCheckAt` is null: no sweep reaches the row."},"nextCheckAt":{"type":"string","format":"date-time","nullable":true,"description":"When the next Layer 1 check is expected: `configCheckAt` when a check is scheduled, else the last check plus the tier's sweep interval; null for a vault never checked with nothing scheduled, and for a static vault with nothing scheduled."},"configVerifiedAt":{"type":"string","format":"date-time","nullable":true,"description":"When the vault last passed Layer 1."},"consistencyStatus":{"type":"string","enum":["not_applicable","pending","verified","suspended","revoked"],"description":"Layer 2 (label to chain consistency) lifecycle. `not_applicable`: nothing to check (escrow or unclaimed vault). `verified`: the labels agree with the current on-chain governor or owner and with product membership, and an Earn vault's required `consistencyContext` findings pass. `suspended`: an inconsistency was detected, such as a governor outside the entity's addresses, a product mixing governed and ungoverned vaults, or an Earn vault's unclaimed dependency or unregistered owner or curator; resolution is a platform-admin action. `revoked`: set manually by a platform admin. `pending`: a re-check was requested manually, or the first check could not read chain state and will retry."},"consistencyReason":{"type":"string","nullable":true,"description":"The Layer 2 verdict in one sentence, for display. For a `suspended` Earn vault it is the `cause.summary` of the first required finding that failed. The findings themselves, with their keys and outcomes, are in `consistencyContext`; key on those, not on this sentence."},"consistencyContext":{"$ref":"#/components/schemas/VaultConsistencyContext"},"consistencyCheckAt":{"type":"string","format":"date-time","nullable":true,"description":"When the next Layer 2 check is due. Set by governance events on chain and by manual requests, and for an Earn vault also by configuration events of the vault, its strategies and their collaterals, by label publications that change a dependency's standing, and by registration changes of its owner or curator; label mutations run their check synchronously instead."},"consistencyLastCheckedAt":{"type":"string","format":"date-time","nullable":true,"description":"When Layer 2 last completed a check, whatever the outcome."},"riskStatus":{"type":"string","enum":["unverified","pending","ok","warning","critical","suspended","revoked"],"description":"Layer 3 (risk context) lifecycle. Not yet automated: no worker writes this field, so it stays `unverified` unless a platform admin sets it through the PATCH endpoint."},"riskContext":{"type":"object","nullable":true,"additionalProperties":true},"riskAssessedAt":{"type":"string","format":"date-time","nullable":true},"isDeprecated":{"type":"boolean"},"deprecationReason":{"type":"string","nullable":true},"notExplorable":{"type":"boolean"},"notExplorableLend":{"type":"boolean"},"notExplorableBorrow":{"type":"boolean"},"tags":{"type":"array","description":"Platform-managed tags. Every tag outside the curator vocabulary lives here (`recently added`, the Base app's `base`); vault reads union them with the label row's vocabulary tags.","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","nullable":true},"platformUpdatedAt":{"type":"string","format":"date-time","nullable":true,"description":"When a platform admin (or the label import) last wrote this assessment; null while the vault has no stored assessment. The checks never move it. The ETag of GET and PATCH is this value quoted."}}},"VaultVisibility":{"type":"object","required":["chainId","vaultAddress","status","checks","source","evaluatedAt"],"properties":{"chainId":{"type":"integer"},"vaultAddress":{"type":"string"},"status":{"type":"string","enum":["visible","warning","hidden","pending_review"]},"checks":{"type":"object","additionalProperties":true,"description":"Decision evidence: `decidedBy`, `reason`, layer statuses, the resolved deprecation, the platform `notExplorable*` overrides as authored, and `listing` — the effective per-side discovery result (`{ lend: { hidden, decidedBy }, borrow: { hidden, decidedBy } }`) after platform overrides, curator flags, and deprecation."},"source":{"type":"string"},"evaluatedAt":{"type":"string","format":"date-time","nullable":true}}}},"responses":{"Error400":{"description":"Bad request","headers":{"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"}}}},"Error403":{"description":"Forbidden","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"}}}},"Error409":{"description":"Conflict","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Error412":{"description":"Precondition failed","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"LabelContextNotFound":{"description":"The label set or version could not be resolved: `labelSet` names no label set, `version` matches no published key or alias, or a `current` or `draft` read names a set other than `public`. This is the only 404 of the label reads that carries `details.labelSet` and `details.version`, which echo the request; a missing row never does, so a client can tell \"this label set or version does not exist\" from \"this row is not labelled\".","headers":{"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"}}}},"Error415":{"description":"Unsupported media type","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Error422":{"description":"Validation error","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"}}}},"Error500":{"description":"Internal server error","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Error502":{"description":"Upstream dependency failure","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Error503":{"description":"Service unavailable","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Error504":{"description":"Upstream request timed out","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/v3":{"get":{"tags":["Protocol"],"summary":"Service metadata","x-status":"implemented","responses":{"200":{"description":"Service metadata","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string"},"docs":{"type":"string"},"openapi":{"type":"string"},"health":{"type":"string"}}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}},"operationId":"getRoot"}},"/v3/openapi.json":{"get":{"tags":["Protocol"],"summary":"OpenAPI document","x-status":"implemented","responses":{"200":{"description":"OpenAPI document"}},"operationId":"getOpenapiJson"}},"/v3/docs":{"get":{"tags":["Protocol"],"summary":"Developer documentation UI","x-status":"implemented","responses":{"200":{"description":"Documentation UI"}},"operationId":"getDocs"}},"/v3/docs/migration":{"get":{"tags":["Protocol"],"summary":"Migration guide from v1 and v2","x-status":"implemented","responses":{"200":{"description":"Human-readable migration guide.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"text/html":{"schema":{"type":"string"}}}}},"operationId":"getMigrationGuide"}},"/v3/labels/sets":{"get":{"tags":["Labels"],"summary":"List label sets","description":"Returns the available label-set channels and their metadata.","x-status":"implemented","security":[],"responses":{"200":{"description":"Label-set list.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LabelSet"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"listLabelSets"}},"/v3/labels/sets/{labelSetId}/versions":{"get":{"tags":["Labels"],"summary":"List published label versions","description":"Returns published snapshots for the label set. Draft rows are never\nincluded, and this metadata read does not require a platform session.\n","x-status":"implemented","security":[],"parameters":[{"$ref":"#/components/parameters/LabelSetIdPath"}],"responses":{"200":{"description":"Published label versions.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LabelVersion"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"404":{"$ref":"#/components/responses/Error404"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"listPublishedLabelVersions"},"post":{"tags":["Labels"],"summary":"Publish current labels","description":"Publishes an immutable snapshot of entity, product, and vault-label content.\nGeo policies remain live and are not included. The snapshot builder decides\nper row where the content comes from: a full publish takes every draft row\nthat no hold covers and keeps held rows at their published content; a\npartial publish (`selection` in the body, platform session only) takes the\nselected rows and whatever they need for a consistent version, overriding\nholds for those rows, and keeps everything else as published. Left-out\nchanges stay pending for the timer. A draft vault row with no labels (the\nrow discovery materialises for every vault it finds, a claim cleared) is not\nlabel content: no publication takes it, a selection naming one is a no-op,\nand the `report.leftOut` says how many such rows the draft holds and which\nthe selection named. The `report` also lists what went live, what\nwas pulled in, what a hold kept back and why, and which holds were\noverridden. `?dryRun=true` returns the report without writing anything.\nWhen the built content matches the latest published version, the endpoint\nreturns that version with `publishOutcome: unchanged` and does not create a\nrelease. Accepts a platform session or an API key holding the\n`labels:publish` capability; a key may only publish in full. The version\nrecords which kind of actor published it, and every publication is audited.\nTo publish exactly what a dry run showed, send its `draftToken` as\n`expectedDraftToken`: if the draft, the latest version or the holds a partial\npublish would override moved since, the answer is 412 with `details.reason`\n`draft-changed` and the current `details.draftToken`, and nothing is written.\nWithout the field, the publish takes the draft as it is at that moment; it\nwill become required for keys, and a key publish without it is logged.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/LabelSetIdPath"},{"name":"dryRun","in":"query","required":false,"description":"Build the version and return the report without publishing.","schema":{"type":"boolean"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"versionKey":{"type":"string"},"aliases":{"type":"array","items":{"type":"string"}},"sourceRepo":{"type":"string","nullable":true},"sourceRef":{"type":"string","nullable":true},"sourceSha":{"type":"string","nullable":true},"schemaAdapter":{"type":"string"},"selection":{"$ref":"#/components/schemas/LabelRowSelection"},"expectedDraftToken":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"The `draftToken` of the dry run this publish confirms. Ignored on a dry run. Optional for now; keys will have to send it."}}}}}},"responses":{"200":{"description":"Publishable label content is unchanged and the latest version is returned, or the request was a dry run and only the report is returned.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"oneOf":[{"$ref":"#/components/schemas/LabelPublishResult"},{"$ref":"#/components/schemas/LabelPublishDryRunResult"}]},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"201":{"description":"Published label snapshot created.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/LabelPublishResult"},"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"},"409":{"$ref":"#/components/responses/Error409"},"412":{"description":"`expectedDraftToken` no longer matches: what this publish would write moved since the dry run. `details.reason` is `draft-changed` and `details.draftToken` is the current token. Nothing was written; preview again before publishing.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"$ref":"#/components/responses/Error413"},"415":{"$ref":"#/components/responses/Error415"},"422":{"$ref":"#/components/responses/Error422"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"publishLabelVersion"}},"/v3/labels/sets/{labelSetId}/publication":{"get":{"tags":["Labels"],"summary":"Read publication state","description":"Returns whether automatic publication is suspended, the deployment\noverride, the configured delays, the pending schedule, and the latest\npublished version with its publisher. Accepts a platform session or a\nAPI key holding any `labels:*` capability; actor identities\nare returned to platform sessions only. Responses are private and never\ncached.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/LabelSetIdPath"}],"responses":{"200":{"description":"Publication state.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/LabelPublicationState"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"getLabelPublicationState"}},"/v3/labels/sets/{labelSetId}/publication/summary":{"get":{"tags":["Labels"],"summary":"Read the publication summary","description":"The part of the publication state a curator surface needs to say when\na draft change goes live: the publication mode, whether automatic\npublication is suspended, the pending due time, and the latest\npublished version. Carries no reason, no actor, and no revision, so it\nis readable with an entity session or without one. In `manual` mode\n`dueAt` is always null: changes go live when the platform publishes.\nResponses are private and never cached.\n","x-status":"implemented","security":[{}],"parameters":[{"$ref":"#/components/parameters/LabelSetIdPath"}],"responses":{"200":{"description":"Publication summary.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/LabelPublicationSummary"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"404":{"$ref":"#/components/responses/Error404"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"getLabelPublicationSummary"}},"/v3/labels/sets/{labelSetId}/publication/versions":{"get":{"tags":["Labels"],"summary":"List published label versions with attribution","description":"The platform-side version history: every published version with its\ncreator and publisher. Identities are returned to platform sessions;\nan API key holding any `labels:*` capability sees the\npublisher kind only. Responses are private and never cached.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/LabelSetIdPath"}],"responses":{"200":{"description":"Attributed published label versions.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AttributedLabelVersion"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"listAttributedLabelVersions"}},"/v3/labels/sets/{labelSetId}/publication/suspend":{"post":{"tags":["Labels"],"summary":"Suspend automatic publication","description":"Stops the timer from publishing the draft until publication is resumed.\nExplicit publication keeps working. The reason is required and recorded\nwith the actor in the publication audit. Accepts a platform session or a\nAPI key holding `labels:publication-control`.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/LabelSetIdPath"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["reason"],"properties":{"reason":{"type":"string","maxLength":500}}}}}},"responses":{"200":{"description":"Suspended, or already suspended, in which case controlOutcome is unchanged.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/LabelPublicationControlResult"},"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"},"422":{"$ref":"#/components/responses/Error422"},"500":{"$ref":"#/components/responses/Error500"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"suspendLabelPublication"}},"/v3/labels/sets/{labelSetId}/publication/resume":{"post":{"tags":["Labels"],"summary":"Resume automatic publication","description":"Lifts a platform suspension. The deployment override, when set, keeps\nthe timer frozen regardless. Accepts a platform session or an\nAPI key holding `labels:publication-control`.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/LabelSetIdPath"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"reason":{"type":"string","nullable":true,"maxLength":500}}}}}},"responses":{"200":{"description":"Resumed, or not suspended, in which case controlOutcome is unchanged.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/LabelPublicationControlResult"},"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"},"422":{"$ref":"#/components/responses/Error422"},"500":{"$ref":"#/components/responses/Error500"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"resumeLabelPublication"}},"/v3/labels/entities":{"get":{"tags":["Entities"],"summary":"List entity profiles","description":"Lists KYBed entity profiles from the latest published label version by default. Explicit mutable-version reads require an active platform-admin session, and so does `include=counts`.","x-status":"implemented","security":[{}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":10000,"default":0}},{"name":"query","in":"query","schema":{"type":"string","minLength":1,"pattern":"\\S"},"description":"Optional case-insensitive filter over entity id and name."},{"name":"include","in":"query","required":false,"schema":{"type":"string","enum":["counts"]},"description":"`counts` attaches `memberCount` (active members), `adminCount` (active members with the admin role) and `addressCount` (registered addresses) to every row. Team size is an operator's fact, so the include takes an active platform-admin session whichever version is read; the counts are live, not versioned."},{"$ref":"#/components/parameters/LabelSetParam"},{"$ref":"#/components/parameters/LabelVersionParam"}],"responses":{"200":{"description":"Entity profile page.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Label-Set":{"$ref":"#/components/headers/X-Label-Set"},"X-Label-Version":{"$ref":"#/components/headers/X-Label-Version"},"X-Label-Version-Id":{"$ref":"#/components/headers/X-Label-Version-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Entity"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"description":"Missing, invalid, or expired platform-admin session.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated session exists, but platform-admin access is not active.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"$ref":"#/components/responses/LabelContextNotFound"}},"operationId":"listEntities"}},"/v3/labels/entities/{id}/addresses":{"get":{"tags":["Entities"],"summary":"List entity verified addresses","description":"Publicly lists the verified addresses of a KYBed entity. Addresses are\nchain-agnostic: each one counts as ownership evidence on every supported\nchain, so there is no chain filter. A `chainId` query parameter is\nrejected with 422 rather than ignored.\n","x-status":"implemented","security":[{}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":10000,"default":0}}],"responses":{"200":{"description":"Entity verified address page.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EntityAddress"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"description":"Missing, invalid, or expired authenticated session.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Session is inactive, lacks same-entity admin access, or targets a different entity.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Entity profile was not found.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Invalid entity id or pagination, or a removed `chainId` filter was supplied.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"operationId":"listEntityAddresses"}},"/v3/labels/entities/{id}":{"get":{"tags":["Entities"],"summary":"Get entity profile","description":"Reads one KYBed entity profile from the latest published label version by default. Explicit mutable-version reads require a platform-admin session or an entity-admin session for the same entity.","x-status":"implemented","security":[{}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"}},{"$ref":"#/components/parameters/LabelSetParam"},{"$ref":"#/components/parameters/LabelVersionParam"}],"responses":{"200":{"description":"Entity profile.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Label-Set":{"$ref":"#/components/headers/X-Label-Set"},"X-Label-Version":{"$ref":"#/components/headers/X-Label-Version"},"X-Label-Version-Id":{"$ref":"#/components/headers/X-Label-Version-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Entity"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"description":"Missing, invalid, or expired authenticated session.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated session exists, but platform-admin access is not active.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The entity is not in the resolved version (`details.id`; the label context headers are set), or the label set or version could not be resolved (`details.labelSet` and `details.version`, no label context headers). Only the second carries `details.labelSet`.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Label-Set":{"$ref":"#/components/headers/X-Label-Set"},"X-Label-Version":{"$ref":"#/components/headers/X-Label-Version"},"X-Label-Version-Id":{"$ref":"#/components/headers/X-Label-Version-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Invalid entity id.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"operationId":"getEntity"}},"/v3/health":{"get":{"tags":["Health"],"summary":"Basic health check","x-status":"implemented","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/HealthResponse"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}},"operationId":"getHealth"}},"/v3/health/detailed":{"get":{"tags":["Health"],"summary":"Dependency health check","x-status":"implemented","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/DetailedHealthResponse"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"429":{"$ref":"#/components/responses/Error429"}},"operationId":"getHealthDetailed"}},"/v3/health/dashboard":{"get":{"tags":["Health"],"summary":"Human-readable dependency health dashboard","description":"Sanitized aggregate dependency and per-chain health intended for browser viewing.","x-status":"implemented","responses":{"200":{"description":"Health dashboard HTML.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"text/html":{"schema":{"type":"string"}}}},"429":{"$ref":"#/components/responses/Error429"}},"operationId":"getHealthDashboard"}},"/v3/health/live":{"get":{"tags":["Health"],"summary":"Liveness probe","x-status":"implemented","responses":{"200":{"description":"OK","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["ok"]}}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"503":{"description":"Local health-check cleanup did not terminate; process restart required","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","required":["status","reason"],"properties":{"status":{"type":"string","enum":["not_live"]},"reason":{"type":"string","enum":["health_check_cleanup_stalled"]}}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}},"operationId":"getHealthLive"}},"/v3/health/ready":{"get":{"tags":["Health"],"summary":"Public readiness status","description":"Public mirror of the readiness result. Kubernetes probes use the Service-excluded management listener and do not consume this endpoint's bounded per-process admission budget.","x-status":"implemented","responses":{"200":{"description":"Ready","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["ready"]}}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"429":{"$ref":"#/components/responses/Error429"},"503":{"description":"Not ready","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","required":["status","reasons","checks"],"properties":{"status":{"type":"string","enum":["not_ready"]},"reasons":{"type":"array","items":{"type":"string"}},"checks":{"type":"object","properties":{"database":{"type":"string","enum":["ok","error"]},"ponderRead":{"type":"string","enum":["ok","error"]},"redis":{"type":"string","enum":["ok","error"]}}}}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}},"operationId":"getHealthReady"}},"/v3/usage/stats":{"get":{"tags":["Usage"],"summary":"Usage statistics for the authenticated API key","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"responses":{"200":{"description":"Usage statistics","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/UsageStatsResponse"}}}}}},"401":{"$ref":"#/components/responses/Error401"},"404":{"$ref":"#/components/responses/Error404"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"getUsageStats"}},"/v3/compliance/address-screening":{"post":{"tags":["Compliance"],"summary":"Screen an address with TRM","description":"Screens an EVM address using TRM and the versioned Euler policy. The endpoint\nrequires an active, unexpired API key with the `compliance:screen`\ncapability, or a platform session whose operator is on the admin allowlist\n(the Toolbox, with the CSRF header); a session also receives the matched rules,\nthe evaluation id, its expiry and the retained provider payload. It applies a\ndedicated per-caller limit of 100 requests per minute by default. Results can reuse\na fresh evaluation for the configured window (24 hours by default), while every\ncapability-authorized request, including requests rejected before provider screening,\nis retained in the screening audit history. The service fails closed with 503 when screening cannot\nproduce a trustworthy result or when production enablement is off, and the two are told apart by\nthe error code rather than the status: `SERVICE_DISABLED` with `details.reason: disabled` means this\ndeployment carries no provider, so retrying can never succeed, while `SERVICE_UNAVAILABLE` with\n`details.reason: unavailable` is a configured provider that failed and is worth retrying.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressScreeningRequest"}}}},"responses":{"200":{"description":"Address screening result.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/AddressScreeningResponse"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"413":{"$ref":"#/components/responses/Error413"},"415":{"$ref":"#/components/responses/Error415"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"postComplianceAddressScreening"}},"/v3/compliance/address-screening/evaluations":{"get":{"tags":["Compliance"],"summary":"Address screening evaluations (history)","description":"Pages through the retained provider evaluations, newest first, including\nthe raw provider payload and the screened address. Requires an active,\nunexpired API key with the `compliance:screening-read`\ncapability, a separate grant from `compliance:screen`, or a platform\nsession whose operator is on the admin allowlist (the Toolbox).\nResponses are compliance data: `Cache-Control: no-store`, never log them.\n`suspicious=true|false` keeps one verdict. A query parameter this route does not\nlist answers 400 `VALIDATION_ERROR`.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AddressScreeningHistoryAddressParam"},{"$ref":"#/components/parameters/AddressScreeningHistoryChainParam"},{"$ref":"#/components/parameters/AddressScreeningHistoryFromParam"},{"$ref":"#/components/parameters/AddressScreeningHistoryToParam"},{"$ref":"#/components/parameters/AddressScreeningEvaluationSuspiciousParam"},{"$ref":"#/components/parameters/AddressScreeningHistoryLimitParam"},{"$ref":"#/components/parameters/OffsetParam"}],"responses":{"200":{"description":"Evaluations matching the filter.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AddressScreeningEvaluationRecord"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"listComplianceAddressScreeningEvaluations"}},"/v3/compliance/address-screening/requests":{"get":{"tags":["Compliance"],"summary":"Address screening request audit log (history)","description":"Pages through the append-only request audit log, newest first: which key\nasked, for which address and chain, whether a cached evaluation was\nreused, and how rejected or failed requests ended. Requires the\n`compliance:screening-read` capability or an allowlisted platform\nsession. Responses are compliance data: `Cache-Control: no-store`,\nnever log them. The log records no verdict, so there is no `suspicious`\nfilter here: it answers 400 `VALIDATION_ERROR`, like any query parameter\nthis route does not list.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/AddressScreeningHistoryAddressParam"},{"$ref":"#/components/parameters/AddressScreeningHistoryChainParam"},{"$ref":"#/components/parameters/AddressScreeningHistoryFromParam"},{"$ref":"#/components/parameters/AddressScreeningHistoryToParam"},{"$ref":"#/components/parameters/AddressScreeningHistoryLimitParam"},{"$ref":"#/components/parameters/OffsetParam"}],"responses":{"200":{"description":"Request audit rows matching the filter.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AddressScreeningRequestRecord"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"listComplianceAddressScreeningRequests"}},"/v3/compliance/address-screening/stats":{"get":{"tags":["Compliance"],"summary":"Address screening activity (usage)","description":"How much screening happened in each trailing window: provider calls\n(one per retained evaluation, the provider's billable unit), flagged\nevaluations, and the requests around them (total, cache hits, failed).\nDefaults to the last 24, 72 and 168 hours; `hours` names up to eight\nwindows. Requires the `compliance:screening-read` capability or an\nallowlisted platform session.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"name":"hours","in":"query","required":false,"description":"Comma-separated trailing windows in whole hours, 1 to 8760 each, at most eight.","schema":{"type":"string","example":"24,72,168"}}],"responses":{"200":{"description":"Activity per window.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/AddressScreeningActivity"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"getComplianceAddressScreeningStats"}},"/v3/labels/sets/{labelSetId}/holds":{"get":{"tags":["Labels"],"summary":"List active holds","description":"Every unreleased hold: quarantines raised by the reviewer and entity holds\nraised by entity suspension. Accepts a platform session or a key with\n`labels:reject` or `labels:draft-read`. Actor identities are returned to\nplatform sessions only. Only the `public` label set has holds.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/LabelSetIdPath"}],"responses":{"200":{"description":"Active holds.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LabelHold"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"listLabelHolds"},"post":{"tags":["Labels"],"summary":"Quarantine a row","description":"Rejects one entity, product, or vault-label row: the curator's draft stays\nintact, the row keeps its published content on every full publish, and the\nhash of the draft content at the time is recorded so a later edit is\ndetectable. The row must exist in the draft or in the latest published\nversion. Accepts a platform session or a key with `labels:reject`. One\nactive quarantine per row; a repeat answers 409 with the existing hold.\nSend `expectedContentHash` to hold only the revision that was reviewed: a\ndraft that moved since answers 412 `stale-review` and writes no hold and no\nevent. It will become required for keys.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/LabelSetIdPath"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabelQuarantineRequest"}}}},"responses":{"201":{"description":"Hold created.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/LabelHold"},"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"},"409":{"$ref":"#/components/responses/Error409"},"412":{"$ref":"#/components/responses/Error412"},"413":{"$ref":"#/components/responses/Error413"},"415":{"$ref":"#/components/responses/Error415"},"422":{"$ref":"#/components/responses/Error422"},"500":{"$ref":"#/components/responses/Error500"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"quarantineLabelRow"}},"/v3/labels/sets/{labelSetId}/holds/{holdId}":{"delete":{"tags":["Labels"],"summary":"Release a quarantine","description":"Releases one quarantine so the next full publish takes the row's draft.\nAccepts a platform session or a key with `labels:reject`. Entity holds are\nreleased by resuming the entity and answer 409 here. `expectedContentHash`\nreleases only the revision that was reviewed; a draft that moved since\nanswers 412 `stale-review` and nothing is released. It will become required\nfor keys.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/LabelSetIdPath"},{"name":"holdId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"expectedContentHash","in":"query","required":false,"description":"The held row's draft revision the reviewer judged, the change log's `afterContentHash`. To name a row the draft no longer has, use POST `…/release` with `expectedContentHash: null`.","schema":{"type":"string","pattern":"^[0-9a-f]{64}$"}}],"responses":{"200":{"description":"Hold released.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/LabelHold"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"412":{"$ref":"#/components/responses/Error412"},"500":{"$ref":"#/components/responses/Error500"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"releaseLabelHold"}},"/v3/labels/sets/{labelSetId}/holds/{holdId}/release":{"post":{"tags":["Labels"],"summary":"Release a quarantine with a reason","description":"Releases one quarantine like DELETE on the hold, and records an optional\n`reason` on the hold (`releaseReason`) and in the publication event. An empty\nbody releases with no reason. Accepts a platform session or a key with\n`labels:reject`. Entity holds are released by resuming the entity and answer\n409 here. `expectedContentHash` releases only the revision that was reviewed;\na draft that moved since answers 412 `stale-review` and nothing is released.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/LabelSetIdPath"},{"name":"holdId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabelReleaseRequest"}}}},"responses":{"200":{"description":"Hold released.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/LabelHold"},"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"},"409":{"$ref":"#/components/responses/Error409"},"412":{"$ref":"#/components/responses/Error412"},"422":{"$ref":"#/components/responses/Error422"},"500":{"$ref":"#/components/responses/Error500"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"releaseLabelHoldWithReason"}},"/v3/labels/sets/{labelSetId}/changes":{"get":{"tags":["Labels"],"summary":"List the label change log","description":"One row per label mutation with the actor, the before and after content,\nand the changed fields, written in the row's own transaction. `pending`\nrows wait for a publish, `published` rows name the version that carried\nthem, `quarantined` rows are held, and `superseded` rows were replaced by a\nlater change to the same row. Newest first. Accepts a platform session or a\nkey with `labels:draft-read`, `labels:reject`, or `labels:publish`; actor\nidentities and request ids are returned to platform sessions only. Only the\n`public` label set has a change log.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/LabelSetIdPath"},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","published","quarantined","superseded"]}},{"name":"entityId","in":"query","required":false,"description":"The entity that owned the row when it changed.","schema":{"type":"string"}},{"name":"resourceType","in":"query","required":false,"description":"One row's changes; pair with `resourceEntityId`, or `chainId` plus `productId` or `vaultAddress`.","schema":{"type":"string","enum":["entity","product","vault"]}},{"name":"resourceEntityId","in":"query","required":false,"schema":{"type":"string"}},{"name":"chainId","in":"query","required":false,"schema":{"type":"integer"}},{"name":"productId","in":"query","required":false,"schema":{"type":"string"}},{"name":"vaultAddress","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":10000,"default":0}}],"responses":{"200":{"description":"Change log rows.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LabelChange"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"422":{"$ref":"#/components/responses/Error422"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"listLabelChanges"}},"/v3/labels/products":{"get":{"tags":["Labels"],"summary":"List curation products","description":"Publicly reads the latest published product snapshot by default. Explicit `current` or `draft` reads expose the mutable working copy. Platform operators can read every entity; entity-member sessions are restricted to their own entity.","x-status":"implemented","security":[{}],"parameters":[{"$ref":"#/components/parameters/LabelSetParam"},{"$ref":"#/components/parameters/LabelVersionParam"},{"$ref":"#/components/parameters/LimitParam"},{"$ref":"#/components/parameters/OffsetParam"},{"name":"chainId","in":"query","schema":{"type":"integer","minimum":1},"description":"Keeps rows on this chain. Any positive integer is accepted, including chains the deployment does not serve: an archived chain keeps its stored labels and an unknown one answers an empty page, never 404 `CHAIN_NOT_SUPPORTED`. A value that is not a positive integer answers 422."},{"name":"entityId","in":"query","schema":{"type":"string"}},{"name":"id","in":"query","required":false,"style":"form","explode":true,"schema":{"type":"array","maxItems":100,"items":{"type":"string","minLength":1}},"description":"Repeat once per product (`?id=core&id=prime`, at most 100): keeps only the listed product ids. Combines with `chainId` and every other filter, and with `version=` for a pinned read. An empty value answers 422."},{"$ref":"#/components/parameters/LabelViewParam"},{"name":"tags","in":"query","required":false,"style":"form","explode":true,"schema":{"type":"array","maxItems":10,"items":{"type":"string","minLength":1}},"description":"Repeat once per tag (`?tags=base&tags=keyring`); each value is one tag, matched exactly as stored, so a tag containing a comma or spaces is queryable. A vault matches when its exposed tag set (label-row tags plus platform assessment tags, the live assessment also for published reads) carries every listed tag; a product matches when at least one of its member vaults does. `tags=base` selects the Base app subset."}],"responses":{"200":{"description":"Product page. Item shape follows the `view` parameter.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Label-Set":{"$ref":"#/components/headers/X-Label-Set"},"X-Label-Version":{"$ref":"#/components/headers/X-Label-Version"},"X-Label-Version-Id":{"$ref":"#/components/headers/X-Label-Version-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/ProductLabels"},{"$ref":"#/components/schemas/ResolvedProductLabelsView"}]}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/LabelContextNotFound"},"422":{"$ref":"#/components/responses/Error422"}},"operationId":"listProducts"}},"/v3/labels/products/{chainId}/{id}":{"get":{"tags":["Labels"],"summary":"Get curation product","description":"Publicly reads the product and its vault rows from the latest published snapshot by default. Explicit `current` or `draft` reads expose the mutable working copy. Platform operators can read every entity; entity-member sessions are restricted to products owned by their entity.","x-status":"implemented","security":[{}],"parameters":[{"$ref":"#/components/parameters/LabelSetParam"},{"$ref":"#/components/parameters/LabelVersionParam"},{"$ref":"#/components/parameters/ChainIdPath"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/LabelViewParam"}],"responses":{"200":{"description":"Product with associated vault labels. Shapes follow the `view` parameter.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Label-Set":{"$ref":"#/components/headers/X-Label-Set"},"X-Label-Version":{"$ref":"#/components/headers/X-Label-Version"},"X-Label-Version-Id":{"$ref":"#/components/headers/X-Label-Version-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"allOf":[{"oneOf":[{"$ref":"#/components/schemas/ProductLabels"},{"$ref":"#/components/schemas/ResolvedProductLabelsView"}]},{"type":"object","required":["vaults"],"properties":{"vaults":{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/VaultLabels"},{"$ref":"#/components/schemas/ResolvedVaultLabelsView"}]}}}}]},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"description":"A draft read (`version=current` or `draft`) of a product another entity holds; products always carry an owner, so an entity session reads only its own. Platform sessions and keys with `labels:draft-read` read every product.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The product is not in the resolved version (no `details.labelSet`), or the label set or version could not be resolved: `labelSet` names no label set, `version` matches no published key or alias, or a `current` or `draft` read names a set other than `public`. Only the second carries `details.labelSet` and `details.version`, which echo the request.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"operationId":"getProduct"}},"/v3/labels/vaults":{"get":{"tags":["Labels"],"summary":"List curation vault labels","description":"Publicly reads the latest published vault-label snapshot by default. Explicit `current` or `draft` reads expose the mutable working copy. Platform operators can read every entity; entity-member sessions list their own entity's rows only (the single-vault read below also answers a row nobody holds). Vault labels live under `/v3/labels`.","x-status":"implemented","security":[{}],"parameters":[{"name":"include","in":"query","required":false,"schema":{"type":"string","enum":["visibility"]},"description":"`visibility` attaches each row's verdict. For a request the route has authenticated as a platform session (a `current` or `draft` read with the session cookie) it is the verdict as evaluated, the `VaultVisibility` record that `/visibility/platform` answers per vault; for every other request it is the public `VaultVisibilitySummary` the quantitative vault lists carry inline. Labels are the only enumeration that reaches a chain without an indexer, so this is how a consumer gets the displayable set there; it stays opt-in so reads that do not need it do not pay for the join. A row the evaluator has no verdict for answers `null` rather than being dropped."},{"$ref":"#/components/parameters/LabelSetParam"},{"$ref":"#/components/parameters/LabelVersionParam"},{"$ref":"#/components/parameters/LimitParam"},{"$ref":"#/components/parameters/OffsetParam"},{"name":"chainId","in":"query","schema":{"type":"integer","minimum":1},"description":"Keeps rows on this chain. Any positive integer is accepted, including chains the deployment does not serve: an archived chain keeps its stored labels and an unknown one answers an empty page, never 404 `CHAIN_NOT_SUPPORTED`. A value that is not a positive integer answers 422."},{"name":"entityId","in":"query","schema":{"type":"string"}},{"name":"address","in":"query","required":false,"style":"form","explode":true,"schema":{"type":"array","maxItems":100,"items":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}},"description":"Repeat once per vault (`?address=0x…&address=0x…`, at most 100, any case): keeps only the listed addresses. Combines with `chainId` and every other filter, and with `version=` for a pinned read. An address that is not listed is simply absent from the page; a malformed one answers 422."},{"name":"claimed","in":"query","required":false,"schema":{"type":"boolean"},"description":"`true` keeps only vaults a curator holds (an entity is set), `false` only vaults nobody holds; unset lists both."},{"name":"q","in":"query","required":false,"schema":{"type":"string","minLength":1,"maxLength":100},"description":"Case-insensitive substring of the label name or of the address; whitespace around the value is trimmed. Matches nothing but the labels: not the on-chain symbol."},{"$ref":"#/components/parameters/LabelViewParam"},{"name":"vaultType","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated vault-type filter (`evk,earn,securitize`, any case). Defaults to all vault types; any other value, `escrow` included, answers 400 `BAD_REQUEST` with `details` `{ \"param\": \"vaultType\", \"unknown\": [...], \"allowed\": [\"evk\", \"earn\", \"securitize\"] }`. Escrow vaults are `evk`: filter on `isEscrow=true`."},{"name":"isEscrow","in":"query","required":false,"schema":{"type":"boolean"},"description":"`true` lists only escrow vaults, `false` only vaults that are not escrow; unset lists every vault. Combines with the other filters."},{"name":"tags","in":"query","required":false,"style":"form","explode":true,"schema":{"type":"array","maxItems":10,"items":{"type":"string","minLength":1}},"description":"Repeat once per tag (`?tags=base&tags=keyring`); each value is one tag, matched exactly as stored, so a tag containing a comma or spaces is queryable. A vault matches when its exposed tag set (label-row tags plus platform assessment tags, the live assessment also for published reads) carries every listed tag; a product matches when at least one of its member vaults does. `tags=base` selects the Base app subset."}],"responses":{"200":{"description":"Vault-label page. Item shape follows the `view` parameter.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Label-Set":{"$ref":"#/components/headers/X-Label-Set"},"X-Label-Version":{"$ref":"#/components/headers/X-Label-Version"},"X-Label-Version-Id":{"$ref":"#/components/headers/X-Label-Version-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/VaultLabels"},{"$ref":"#/components/schemas/ResolvedVaultLabelsView"}]}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/LabelContextNotFound"},"422":{"$ref":"#/components/responses/Error422"}},"operationId":"listVaultLabels"}},"/v3/labels/vaults/{chainId}/{address}":{"get":{"tags":["Labels"],"summary":"Get curation vault labels","description":"Publicly reads the vault-label row from the latest published snapshot by default. Explicit `current` or `draft` reads expose the mutable working copy. Platform operators can read every entity; entity-member sessions are restricted to vault labels owned by their entity.","x-status":"implemented","security":[{}],"parameters":[{"$ref":"#/components/parameters/LabelSetParam"},{"$ref":"#/components/parameters/LabelVersionParam"},{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"$ref":"#/components/parameters/LabelViewParam"}],"responses":{"200":{"description":"Vault labels. Shape follows the `view` parameter.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Label-Set":{"$ref":"#/components/headers/X-Label-Set"},"X-Label-Version":{"$ref":"#/components/headers/X-Label-Version"},"X-Label-Version-Id":{"$ref":"#/components/headers/X-Label-Version-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"oneOf":[{"$ref":"#/components/schemas/VaultLabels"},{"$ref":"#/components/schemas/ResolvedVaultLabelsView"}]},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"description":"A draft read (`version=current` or `draft`) of a row another entity holds. An entity session reads the rows its entity holds and any row nobody holds (`entityId` null), so a curator can tell a released or never-claimed vault from one another curator holds before claiming it; platform sessions and keys with `labels:draft-read` read every row. Published reads never answer this.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The vault is not in the resolved version (no `details.labelSet`), or the label set or version could not be resolved: `labelSet` names no label set, `version` matches no published key or alias, or a `current` or `draft` read names a set other than `public`. Only the second carries `details.labelSet` and `details.version`, which echo the request.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"operationId":"getVaultLabelsRow"}},"/v3/config-trust":{"get":{"tags":["Labels"],"summary":"List config trust entries","description":"Lists platform-managed trust entries used by Layer 1 configuration policies (trusted hook targets, per-vault rule exemptions, and reviewed custom oracle adapters).","x-status":"implemented","security":[{}],"parameters":[{"name":"chainId","in":"query","schema":{"type":"integer","minimum":1}},{"name":"kind","in":"query","schema":{"type":"string","enum":["hook-target","rule-exemption","custom-adapter","adapter-check-exemption"]}}],"responses":{"200":{"description":"Trust entry list.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ConfigTrustEntry"}}}}}}},"422":{"$ref":"#/components/responses/Error422"}},"operationId":"listConfigTrustEntries"}},"/v3/geo-policies":{"get":{"tags":["Labels"],"summary":"List geo policies","description":"Publicly reads the live geo-policy table. Label-set and version selectors are accepted for request compatibility and do not change the result. The stored rules come first, in creation order, then the derived address rows (`derivedFrom` set): for each stored rule with an asset selector, one row per token the app reaches that is built on an asset the rule selects, so an evaluator that knows only address rules enforces the rule on wrappers too. Tokens that only share code with a restricted asset get no row. Derived rows follow the exposure sweep and may be up to a minute behind it; `meta.total` counts both kinds, and `chainId` filters both.","x-status":"implemented","security":[{}],"parameters":[{"name":"labelSet","in":"query","required":false,"description":"Accepted for compatibility. Geo-policy reads always use live policy data.","schema":{"type":"string"}},{"name":"version","in":"query","required":false,"description":"Accepted for compatibility. Geo-policy reads always use live policy data.","schema":{"type":"string"}},{"$ref":"#/components/parameters/LimitParam"},{"$ref":"#/components/parameters/OffsetParam"},{"name":"chainId","in":"query","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"Geo-policy page.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GeoPolicy"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"422":{"$ref":"#/components/responses/Error422"}},"operationId":"listGeoPolicies"}},"/v3/evk/vaults/{chainId}/{address}/assessment":{"get":{"tags":["Labels"],"summary":"Get EVK vault assessment","x-status":"implemented","description":"The stored assessment, or default unevaluated statuses when this deployment serves the\nchain and the vault has genuinely never been checked. A chain the deployment does not\nserve answers `404 CHAIN_NOT_SUPPORTED` instead, so \"never assessed\" is never reported\nfor a vault Euler could not have assessed; an archived metadata-only chain is unserved\ntoo but carries imported rows, and those are still answered.\n","parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"}],"responses":{"200":{"description":"Vault assessment or default unevaluated statuses.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"ETag":{"$ref":"#/components/headers/AssessmentETag"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/VaultAssessment"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"}},"operationId":"getEvkVaultAssessment"}},"/v3/evk/vaults/{chainId}/{address}/assessment/preview":{"post":{"tags":["Labels"],"summary":"Preview the Layer 1 verdict of a EVK vault, for the live configuration or a proposed one","description":"Answers what a fresh Layer 1 check would say, without storing anything. With an empty body\n(or no body) it is a fresh check of the live vault under its policy family; with\n`overrides` it is the EVK policy judging the live snapshot with the proposed configuration\napplied: caps, LTV rows (change, add, remove), the interest rate model (its rates re-probed\nwith the vault impersonated at the pinned block), router resolutions (`resolvedVaults`),\noracle routes (base to adapter; a proposed adapter's verdict comes from the registry when\nit knows it and from the evaluate-only adapter check when it does not, and every quote a\nchanged route or resolution answers is simulated through the proposed adapter at the pinned\nblock, one unit of the base converted through the resolved vaults the way the router\nconverts it) and the hook configuration. The answer names the findings whose verdict\ndiffers from the stored assessment (`changed`), the status the vault would land on\n(`configStatusIfApplied`, from `currentConfigStatus` and the outcome) and, in\n`notSimulated`, the findings left unknown because their simulation could not run (the\nchain unreachable for a quote, the evaluate-only adapter check refused), each naming the\nreason in its `observed`. Platform rule exemptions apply as the\nstored check applies them. One vault is previewed at most 6 times per minute (429 with\n`Retry-After`) and the reads get 12 seconds (504). Accepts a platform session or a\nAPI key holding `assessments:evaluate`; a curator session is never enough.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VaultConfigPreviewRequest"}}}},"responses":{"200":{"description":"The preview; `persisted` is always false.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/VaultAssessmentPreview"}}}}}},"400":{"description":"Malformed JSON, or an invalid address in the path.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"description":"A key without `assessments:evaluate`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The chain is not served (`CHAIN_NOT_SUPPORTED`), or no Layer 1 policy family matches the vault (`VAULT_NOT_FOUND`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"$ref":"#/components/responses/Error413"},"415":{"$ref":"#/components/responses/Error415"},"422":{"description":"The body fails validation (`error.details.issues`), or overrides were sent for a vault outside the EVK family (`error.details.family`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The vault was previewed more than 6 times in the last minute; `Retry-After` says when to retry.","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/Error500"},"503":{"$ref":"#/components/responses/Error503"},"504":{"description":"The on-chain reads did not finish within the 12-second budget (`UPSTREAM_TIMEOUT`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"operationId":"previewEVKVaultAssessment"}},"/v3/earn/vaults/{chainId}/{address}/assessment/preview":{"post":{"tags":["Labels"],"summary":"Preview the Layer 1 verdict of a Earn vault, for the live configuration or a proposed one","description":"Answers what a fresh Layer 1 check would say, without storing anything. With an empty body\n(or no body) it is a fresh check of the live vault under its policy family; with\n`overrides` it is the EVK policy judging the live snapshot with the proposed configuration\napplied: caps, LTV rows (change, add, remove), the interest rate model (its rates re-probed\nwith the vault impersonated at the pinned block), router resolutions (`resolvedVaults`),\noracle routes (base to adapter; a proposed adapter's verdict comes from the registry when\nit knows it and from the evaluate-only adapter check when it does not, and every quote a\nchanged route or resolution answers is simulated through the proposed adapter at the pinned\nblock, one unit of the base converted through the resolved vaults the way the router\nconverts it) and the hook configuration. The answer names the findings whose verdict\ndiffers from the stored assessment (`changed`), the status the vault would land on\n(`configStatusIfApplied`, from `currentConfigStatus` and the outcome) and, in\n`notSimulated`, the findings left unknown because their simulation could not run (the\nchain unreachable for a quote, the evaluate-only adapter check refused), each naming the\nreason in its `observed`. Platform rule exemptions apply as the\nstored check applies them. One vault is previewed at most 6 times per minute (429 with\n`Retry-After`) and the reads get 12 seconds (504). Accepts a platform session or a\nAPI key holding `assessments:evaluate`; a curator session is never enough. Overrides are refused for an Earn vault (422); an empty body previews the live vault under the Earn policy.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VaultConfigPreviewRequest"}}}},"responses":{"200":{"description":"The preview; `persisted` is always false.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/VaultAssessmentPreview"}}}}}},"400":{"description":"Malformed JSON, or an invalid address in the path.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"description":"A key without `assessments:evaluate`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The chain is not served (`CHAIN_NOT_SUPPORTED`), or no Layer 1 policy family matches the vault (`VAULT_NOT_FOUND`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"$ref":"#/components/responses/Error413"},"415":{"$ref":"#/components/responses/Error415"},"422":{"description":"The body fails validation (`error.details.issues`), or overrides were sent for a vault outside the EVK family (`error.details.family`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The vault was previewed more than 6 times in the last minute; `Retry-After` says when to retry.","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/Error500"},"503":{"$ref":"#/components/responses/Error503"},"504":{"description":"The on-chain reads did not finish within the 12-second budget (`UPSTREAM_TIMEOUT`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"operationId":"previewEarnVaultAssessment"}},"/v3/earn/vaults/{chainId}/{address}/assessment":{"get":{"tags":["Labels"],"summary":"Get Earn vault assessment","x-status":"implemented","description":"The stored assessment, or default unevaluated statuses when this deployment serves the\nchain and the vault has genuinely never been checked. A chain the deployment does not\nserve answers `404 CHAIN_NOT_SUPPORTED` instead, so \"never assessed\" is never reported\nfor a vault Euler could not have assessed; an archived metadata-only chain is unserved\ntoo but carries imported rows, and those are still answered.\n","parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"}],"responses":{"200":{"description":"Vault assessment or default unevaluated statuses.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"ETag":{"$ref":"#/components/headers/AssessmentETag"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/VaultAssessment"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"}},"operationId":"getEarnVaultAssessment"}},"/v3/protocol/stats":{"get":{"tags":["Protocol"],"summary":"Protocol-wide lending stats across chains","description":"Returns lending aggregates across the selected chains. The stats count what the app shows, plus the vaults kept out of it only by deprecation, for every vault from Euler's factories (the EVK factory, escrow vaults included; the Earn factory; the Securitize factory). Shown means the verdict is `visible` or `warning` with at least one listing side not hidden, as the app and the work items read it, so Layer 1, Layer 2, advisories, claims and listing flags apply exactly as in the app. An escrow or Securitize vault counts while a counted vault accepts it as collateral with a liquidation LTV above zero, even when Layer 1 hides it. Vaults hidden by checks, hidden by a platform admin or a curator verdict, pending review, unclaimed, or without a Layer 1 verdict yet are left out. Prices are the selected current price at most 24 hours old, the on-chain fallback included. A vault that holds a balance without such a price, or whose balance was read more than 15 minutes ago, is left out and its chain still counts with what was priced, however much of the chain that vault holds. `meta.excludedVaults` reports what was left out and why. `earnTotalAssetsUsd` is reported separately and is not part of `totalSuppliedUsd` or `utilization`. Chains with incomplete membership or stale source state are omitted and reported in response metadata; a chain with unread balances still contributes the vaults it read. Partial responses use `Cache-Control: no-store`.","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdParam"}],"responses":{"200":{"description":"Protocol stats","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":{"$ref":"#/components/schemas/ProtocolStats"},"meta":{"$ref":"#/components/schemas/ProtocolStatsMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"getProtocolStats"}},"/v3/protocol/stats/history":{"get":{"tags":["Protocol"],"summary":"Daily protocol or selected-chain lending history","description":"Days written from this release on count the vaults `/v3/protocol/stats` counts; earlier days keep the earlier rule and are not recomputed. A row written after its day closed (catch-up, repair, backfill) has no daily Securitize balances, so it leaves Securitize deposits out, and a backfill row has no Earn total. A day is written with what was priced: a vault without a usable price that day is left out, and the day stays as written. Returns complete retained daily aggregates by default. With includePartial=true, days with only some chain rows are also returned with explicit point coverage and Cache-Control no-store. Missing dates and per-metric availability are reported in meta.coverage in either mode. Empty scopes remain empty; no zero-valued days are synthesized. Only 1d resolution is supported, ranges are inclusive, the default window is 30 days, and the maximum is 732 buckets. With groupBy=chain, data.chains adds chain-ID-ordered series from the same database snapshot and eligible days as data.history. Additive EVK values reconcile to the aggregate; utilization is a ratio, not a sum. Without an explicit chain filter, groups contain retained chain IDs only, not an inferred historical registry.","x-status":"implemented","x-cache-ttl":300,"parameters":[{"name":"groupBy","in":"query","required":false,"description":"Add per-chain series with independent range and metric coverage.","schema":{"type":"string","enum":["chain"]}},{"name":"includePartial","in":"query","required":false,"description":"Include retained healthy-chain subtotals on incomplete days. Does not reconstruct missing vaults or chains.","schema":{"type":"boolean","default":false}},{"$ref":"#/components/parameters/ChainIdParam"},{"name":"resolution","in":"query","required":false,"schema":{"type":"string","enum":["1d"],"default":"1d"}},{"$ref":"#/components/parameters/HistoryFromParam"},{"$ref":"#/components/parameters/HistoryToParam"}],"responses":{"200":{"description":"Protocol stats daily history","headers":{"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","required":["history"],"properties":{"history":{"type":"array","items":{"$ref":"#/components/schemas/ProtocolStatsHistoryPoint"}},"chains":{"type":"array","description":"Present only with groupBy=chain. Sorted by numeric chain ID, with history ordered by ascending UTC day.","items":{"$ref":"#/components/schemas/ProtocolStatsChainHistory"}}}},"meta":{"$ref":"#/components/schemas/ProtocolStatsHistoryMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"getProtocolStatsHistory"}},"/v3/flows/history":{"get":{"tags":["Protocol"],"summary":"Daily EVK supplied net flows and event-category USD totals","description":"Returns retained daily EVK deposit, withdrawal, borrow, repay and liquidation USD totals. Net supplied flow is depositsUsd minus withdrawalsUsd; borrows, repays and liquidations are reported separately and do not enter the net formula. Each category is independently nullable; missing chain rows or unavailable category valuation are not reported as zero. Net supplied flow remains available when deposits and withdrawals are available even if another category is not. Values use eligible positive historical asset prices at or before each event, within 15 minutes and bounded by the event block. Rollups and backfills cover retained raw EVK events; coverage describes the requested range and does not prove complete historical source retention. Protocol, chain and vault scopes use the current visible labelled EVK vault membership; Earn and unlabelled vaults are excluded. Historical label membership is not reconstructed. Omitting chainId selects the currently configured chains. A vault filter requires exactly one selected chain. Only 1d resolution is supported, ranges are inclusive, the default window is 30 days, and the maximum is 732 buckets. Only closed UTC days are published; the current open day is omitted. With groupBy=chain, data.chains adds a series and independent coverage for every selected chain, including empty series. Missing days remain absent; no zero-valued days are synthesized. Incomplete range coverage uses Cache-Control no-store. Complete HTTP responses may remain cached for up to 300 seconds after source invalidation; fresh database reads exclude pending buckets, including after the cached response expires. Unknown or repeated query parameters, duplicate chain IDs and invalid ranges return 400. An unsupported chainId returns 404 with error code CHAIN_NOT_SUPPORTED.","x-status":"implemented","x-cache-ttl":300,"parameters":[{"$ref":"#/components/parameters/ChainIdParam"},{"name":"vault","in":"query","required":false,"description":"Filter to one EVK vault; requires exactly one selected configured chain.","schema":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"}},{"name":"resolution","in":"query","required":false,"schema":{"type":"string","enum":["1d"],"default":"1d"}},{"$ref":"#/components/parameters/HistoryFromParam"},{"$ref":"#/components/parameters/HistoryToParam"},{"name":"groupBy","in":"query","required":false,"description":"Add series ordered by numeric chain ID, each ordered by ascending UTC day.","schema":{"type":"string","enum":["chain"]}}],"responses":{"200":{"description":"Daily retained EVK flows with explicit range and metric coverage.","headers":{"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","required":["history"],"properties":{"history":{"type":"array","items":{"$ref":"#/components/schemas/FlowsHistoryPoint"}},"chains":{"type":"array","description":"Present only with groupBy=chain.","items":{"$ref":"#/components/schemas/FlowsChainHistory"}}}},"meta":{"$ref":"#/components/schemas/FlowsHistoryMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"getFlowsHistory"}},"/v3/chains":{"get":{"tags":["Chains"],"summary":"List supported chains","x-status":"implemented","x-cache-ttl":300,"responses":{"200":{"description":"Chains","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/Chain"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}},"operationId":"getChains"}},"/v3/chains/{chainId}/stats":{"get":{"tags":["Chains"],"summary":"Chain-level stats","description":"Returns the chain's protocol stats under the same rule as `/v3/protocol/stats`: lending totals over the counted EVK, escrow and Securitize vaults, and `earnTotalAssetsUsd` over the counted Earn vaults, reported separately and not part of `totalSuppliedUsd` or `utilization`. `meta.excludedVaults` says which vaults the totals leave out and why. An incomplete chain is omitted from the aggregate, reported in response metadata, and served with `Cache-Control: no-store`.","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"}],"responses":{"200":{"description":"Chain stats","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":{"$ref":"#/components/schemas/ChainStats"},"meta":{"$ref":"#/components/schemas/ProtocolStatsMeta"}}}}}}},"operationId":"getChainsByChainIdStats"}},"/v3/chains/{chainId}/borrowable-vaults":{"get":{"tags":["Chains"],"summary":"Borrowable vaults for a chain","deprecated":true,"description":"Legacy location for this collection.","x-status":"implemented","x-cache-ttl":300,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"}],"responses":{"200":{"description":"Borrowable 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":{"type":"string"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}},"operationId":"getChainsByChainIdBorrowableVaults"}},"/v3/evk/vaults":{"get":{"tags":["Vaults"],"summary":"List vaults","description":"Returns a list of vaults.\n`minTvl`/`maxTvl` apply to `totalSupplyUsd` where\n`totalSupplyUsd = (cash + totalBorrows) * price`.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdParam"},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"},{"name":"asset","in":"query","required":false,"schema":{"type":"string"}},{"name":"minTvl","in":"query","required":false,"schema":{"type":"number"}},{"name":"maxTvl","in":"query","required":false,"schema":{"type":"number"}},{"name":"visibility","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated visibility filter (`visible,warning,hidden,pending_review`). Defaults to `visible,warning` — hidden and pending_review vaults are excluded from discovery unless requested explicitly."}],"responses":{"200":{"description":"Vault list","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/Vault"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"}},"operationId":"getVaults"}},"/v3/evk/vaults/batch":{"post":{"tags":["Vaults"],"summary":"Batch vault details","description":"Returns canonical EVK vault detail entities for an explicit address set.\nUse this to avoid high client-side fanout when you already know the vault\naddresses you want to render.\n\nNotes:\n  - Request order is preserved for found vaults.\n  - `meta.notFound` returns requested addresses that were not resolved.\n  - `include=[\"collaterals\"]` expands collateral detail for every returned vault.\n  - The request cap is 1000 vault addresses and 256 KiB of JSON body.\n","x-status":"implemented","x-cache-ttl":60,"operationId":"postEvkVaultBatch","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvkVaultBatchRequest"}}}},"responses":{"200":{"description":"Batched EVK vault details","headers":{"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvkVaultBatchResponse"}}}},"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"}}}},"/v3/resolve/vaults":{"get":{"tags":["Vaults"],"summary":"Resolve a vault address to its family","description":"Resolve a single `(chainId, address)` pair to `vaultType`, `factory`, and the canonical resource path when one exists.","x-status":"implemented","x-cache-ttl":60,"operationId":"getVaultResolve","parameters":[{"name":"chainId","in":"query","required":true,"schema":{"type":"integer"}},{"name":"address","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Resolved vault family","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/VaultResolveEntry"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"404":{"description":"Vault not found"},"504":{"$ref":"#/components/responses/Error504"}}},"post":{"tags":["Vaults"],"summary":"Resolve multiple vault addresses to their families","description":"Bulk resolver for SDK/meta-routing use cases. Supports up to 500 addresses per request.","x-status":"implemented","x-cache-ttl":60,"operationId":"postVaultResolve","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chainId","addresses"],"properties":{"chainId":{"type":"integer"},"addresses":{"type":"array","minItems":1,"maxItems":500,"items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Resolved vault families","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/VaultResolveEntry"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"413":{"$ref":"#/components/responses/Error413"},"415":{"$ref":"#/components/responses/Error415"},"504":{"$ref":"#/components/responses/Error504"}}}},"/v3/evk/vaults/health/utilization":{"get":{"tags":["Vaults"],"summary":"Vault utilization health","description":"Lists vaults ordered by utilization severity (descending).\n- `chainId` is required.\n- If `threshold` is omitted, returns all vaults.\n- Threshold filter is inclusive (`utilization >= threshold`).\n- `onlyOverThreshold` is accepted for compatibility and currently does not alter filtering.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"name":"chainId","in":"query","required":true,"schema":{"type":"integer"}},{"name":"threshold","in":"query","required":false,"schema":{"type":"number","minimum":0,"maximum":1}},{"name":"onlyOverThreshold","in":"query","required":false,"schema":{"type":"boolean"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Vault utilization health list","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/VaultUtilizationHealthItem"}},"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":"getVaultsHealthUtilization"}},"/v3/evk/vaults/health/caps":{"get":{"tags":["Vaults"],"summary":"Vault cap usage health","description":"Lists vaults ordered by cap-usage severity (descending).\nCap usage is computed as `max(supplyCapUsage, borrowCapUsage)`, and the\nresponse includes both supply-cap and borrow-cap fields.\n- `chainId` is required.\n- If `threshold` is omitted, returns all vaults.\n- Threshold filter is inclusive (`capUsage >= threshold`).\n- `onlyOverThreshold` is accepted for compatibility and currently does not alter filtering.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"name":"chainId","in":"query","required":true,"schema":{"type":"integer"}},{"name":"threshold","in":"query","required":false,"schema":{"type":"number","minimum":0,"maximum":1}},{"name":"onlyOverThreshold","in":"query","required":false,"schema":{"type":"boolean"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Vault cap health list","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/VaultCapHealthItem"}},"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":"getVaultsHealthCaps"}},"/v3/evk/vaults/{chainId}/{address}":{"get":{"tags":["Vaults"],"summary":"Vault details","description":"Returns vault detail. Optional `include` expands related resources in a single response.\nSupported values: `collaterals`, `apy`, `totals`, `prices`.\nThe single-vault detail response uses `totalBorrowed` as the canonical borrow-total field.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"$ref":"#/components/parameters/IncludeParam"}],"responses":{"200":{"description":"Vault details","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":{"$ref":"#/components/schemas/VaultDetailResponseWithIncludes"}}}}}}},"operationId":"getVaultsByChainIdByAddress"}},"/v3/evk/vaults/{chainId}/{address}/visibility":{"get":{"tags":["Vaults"],"summary":"Visibility verdict for a vault","description":"Platform-computed visibility verdict with the decision evidence in `checks` (`decidedBy`,\n`reason`, layer statuses, deprecation, platform overrides, and the per-side `listing`\nresult that folds in curator flags and deprecation). Curated inputs come from the latest\npublished label version; reasons that would reveal a draft claim are reported as their\npublished equivalent. Platform operators read the verdict as evaluated at\n`.../visibility/platform`.\n\nThe verdict is a labels answer, so it is served for any chain that has labels: on a chain\nthis deployment cannot index, Layer 1 and Layer 2 report that they could not run\n(`decidedBy: unassessable`) and the curated inputs still decide, rather than the read\nbeing refused.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"}],"responses":{"200":{"description":"Current visibility status and check results","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":{"$ref":"#/components/schemas/VaultVisibility"},"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":"getVaultsByChainIdByAddressVisibility"}},"/v3/earn/vaults/{chainId}/{address}/visibility":{"get":{"tags":["Earn"],"summary":"Visibility verdict for an earn vault","description":"Platform-computed visibility verdict with the decision evidence in `checks` (`decidedBy`, `reason`, layer statuses, deprecation, platform overrides, and the per-side `listing` result that folds in curator flags and deprecation). Curated inputs come from the latest published label version; reasons that would reveal a draft claim are reported as their published equivalent. Platform operators read the verdict as evaluated at `.../visibility/platform`.","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"}],"responses":{"200":{"description":"Current visibility status and check results","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":{"$ref":"#/components/schemas/VaultVisibility"},"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":"getEarnVaultsByChainIdByAddressVisibility"}},"/v3/evk/vaults/{chainId}/{address}/apy":{"get":{"tags":["APYs"],"summary":"Vault APY (current + historical)","description":"Returns current and historical vault APY. The effective end is `to` or the\ncurrent time. When `from` is omitted, the effective window is 7 days for\n`1h` and 30 days for `1d`. Ranges count both endpoint buckets and support\nat most 744 hourly buckets or 732 daily buckets.\n","x-status":"implemented","x-cache-ttl":600,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"$ref":"#/components/parameters/HistoryFromParam"},{"$ref":"#/components/parameters/HistoryToParam"},{"name":"resolution","in":"query","required":false,"schema":{"type":"string","enum":["1h","1d"],"default":"1d"},"description":"Defaults to `1d`. If omitted, uses last 30 days for `1d` and last 7 days for `1h`."},{"$ref":"#/components/parameters/SortParam"}],"responses":{"200":{"description":"Vault APY","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":{"$ref":"#/components/schemas/VaultApy"},"meta":{"$ref":"#/components/schemas/VaultApyMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"}},"operationId":"getVaultsByChainIdByAddressApy"}},"/v3/evk/vaults/{chainId}/{address}/positions":{"get":{"tags":["Vaults"],"summary":"Positions in a vault","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"},{"name":"addressPrefix","in":"query","required":false,"schema":{"type":"string","pattern":"^0x[a-fA-F0-9]{8}$"},"description":"Optional 4-byte account prefix filter (`0x` + 8 hex chars)."},{"name":"blockNumber","in":"query","required":false,"schema":{"type":"string"},"description":"Not supported for this endpoint. If provided, returns 400."}],"responses":{"200":{"description":"Vault positions","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/VaultPosition"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"}},"operationId":"getVaultsByChainIdByAddressPositions"}},"/v3/accounts/{address}/portfolio":{"get":{"tags":["Accounts"],"summary":"Account portfolio","description":"Returns a position-first portfolio view for an owner on a single chain.\nThe backend builds SDK Account and Portfolio entities from internal V3\naccount, vault, price, and label data sources; it does not recursively\ncall `/v3/accounts/{address}/positions`. When `forceFresh=true`, the\nendpoint enqueues or promotes account snapshot refresh work and waits\nbriefly for refreshed snapshots before falling back to the current\nindexed portfolio view. Freshness metadata indicates whether the refresh\ncompleted, timed out, or was rate-limited. When any EVK position has\nunknown debt or controller state, affected SDK rows are omitted and the\naggregate `portfolio.totals` properties are omitted instead of reporting\nan incomplete result as zero.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/AddressPath"},{"name":"chainId","in":"query","required":true,"schema":{"type":"integer"},"description":"Chain ID. Exactly one chain is required."},{"name":"labeledVaultsOnly","in":"query","required":false,"schema":{"type":"boolean"},"description":"Filter positions to the product-facing labeled vault universe."},{"name":"includeAccount","in":"query","required":false,"schema":{"type":"boolean"},"description":"Include the backing SDK account-shaped payload for debugging and migration."},{"name":"forceFresh","in":"query","required":false,"schema":{"type":"boolean"},"description":"When true, enqueue or promote account snapshot refresh for discovered tuples.\nThe endpoint waits briefly for refreshed snapshots before falling back to\nthe current indexed portfolio view. Inspect `data.freshness` for completion,\ntimeout, rate-limit, and fallback metadata.\n"}],"responses":{"200":{"description":"Account portfolio","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":{"$ref":"#/components/schemas/AccountPortfolioResponse"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"504":{"$ref":"#/components/responses/Error504"}},"operationId":"getAccountsByAddressPortfolio"}},"/v3/accounts/{address}/positions":{"get":{"tags":["Accounts"],"summary":"Account positions across chains","description":"Returns paginated account positions across the selected chain scope.\nUses `meta.hasMore` for pagination continuation on the hot path rather than an exact `meta.total`.\nEVK debt and controller nulls mean unknown, not zero. A failed partial\nlive refresh retains a coherent last-known snapshot and its timestamp\nwhen one exists; otherwise the unknown fields remain null.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/AddressPath"},{"$ref":"#/components/parameters/ChainIdParam"},{"$ref":"#/components/parameters/AccountPositionsOffsetParam"},{"$ref":"#/components/parameters/LimitParam"},{"name":"forceFresh","in":"query","required":false,"schema":{"type":"boolean"},"description":"When true, trigger bounded synchronous account snapshot refresh for the returned tuples.\nOn timeout/failure, response safely falls back to stored snapshots and indicates cached mode in freshness metadata.\n"}],"responses":{"200":{"description":"Account positions","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/AccountPosition"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"},"freshness":{"type":"object","properties":{"latestSnapshotTimestamp":{"type":"string","format":"date-time","nullable":true},"ageSeconds":{"type":"integer","nullable":true},"timestamp":{"type":"string","format":"date-time"},"mode":{"type":"string","enum":["fresh","cached"]},"forceFreshRequested":{"type":"boolean"},"refreshTriggered":{"type":"boolean"},"refreshCompleted":{"type":"boolean"},"timedOut":{"type":"boolean"},"rateLimited":{"type":"boolean"},"fallbackReason":{"type":"string","nullable":true},"waitedMs":{"type":"integer"}}}}}}}},"400":{"$ref":"#/components/responses/Error400"},"504":{"$ref":"#/components/responses/Error504"}},"operationId":"getAccountsByAddressPositions"}},"/v3/activity/vaults/{chainId}/{vault}/events":{"get":{"tags":["Activity"],"summary":"Normalized vault activity events","description":"Returns a deterministic event timeline for one EVK, Euler Earn, or Securitize vault.\n`eventType` filters the normalized `type`; `rawType` preserves the indexed source name.\nCoverage reflects the categories applicable to the requested vault type. Unsupported or\nincomplete indexed sources are reported in `meta.coverage`. Any positive safe-integer chain\nID is accepted; chains without V3 Activity indexing return HTTP 200 with an empty timeline and\n`meta.coverage.status: unsupported`. Structurally unavailable sources report unsupported\ncoverage; transient projection failures retain indexed events and report partial coverage.\nEVK governance activity includes events from an EulerRouter used as the vault's immutable\noracle only when that router is recorded as deployed by EulerRouterFactory. Routers outside\nthat factory registry are not decoded or projected.\nGovernance actor and before/after enrichment, underlying-asset metadata and valuation, and\nswap asset/vault mapping can be unavailable. Missing normalized values stay\nabsent, source fields remain in `payload`, and coverage continues to describe indexed event-family\navailability. Missing valuation is explicit and never synthesized as zero.\n","x-status":"implemented","x-cache-ttl":30,"parameters":[{"name":"chainId","in":"path","required":true,"schema":{"type":"integer","minimum":1,"maximum":9007199254740991},"description":"A positive safe-integer chain ID. V3 indexing support is reported at runtime in `meta.coverage`."},{"name":"vault","in":"path","required":true,"schema":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}},{"name":"vaultType","in":"query","required":true,"schema":{"type":"string","enum":["evk","earn","securitize"]}},{"name":"category","in":"query","required":false,"description":"Comma-separated normalized category filter. Empty or unknown values return 400.","schema":{"type":"string","maxLength":1024}},{"name":"eventType","in":"query","required":false,"description":"Comma-separated normalized event type filter. Empty or unknown values return 400.","schema":{"type":"string","maxLength":1024}},{"name":"cursor","in":"query","required":false,"description":"Opaque keyset cursor bound to the complete query shape.","schema":{"type":"string","maxLength":2048}},{"name":"from","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":9007199254740991},"description":"Inclusive unix timestamp in seconds."},{"name":"to","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":9007199254740991},"description":"Inclusive unix timestamp in seconds."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Normalized vault activity timeline and indexed-source coverage.","headers":{"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityResponse"}}}},"400":{"$ref":"#/components/responses/Error400"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"getActivityVaultEvents"}},"/v3/activity/accounts/{owner}/events":{"get":{"tags":["Activity"],"summary":"Normalized owner activity events","description":"Returns one deterministic timeline across the requested chains and the owner's complete\n256-address EVC account family, spanning the owner at ID 0 through subaccount ID 255.\nAccount identities are excluded from request logs and persisted endpoint telemetry.\nCoverage is aggregated across chains and reports incomplete\nreward claims or unclassified multiply intent as partial. Unsupported sources and indexer\nsynchronization state are explicit in `meta.coverage`. Any positive safe-integer chain ID is\naccepted; chains without V3 Activity indexing return HTTP 200 with an empty timeline and\nper-chain `unsupported` coverage. Governance actor and before/after enrichment,\nunderlying-asset metadata and valuation, and swap asset/vault mapping can be unavailable.\nMissing normalized values stay absent, source fields remain in `payload`, and coverage continues\nto describe indexed event-family availability. Transient projection failures retain indexed events\nand report partial coverage rather than authoritative unsupported or complete coverage.\n","x-status":"implemented","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string","maxLength":42,"pattern":"^0x[0-9a-fA-F]{40}$"}},{"name":"chainId","in":"query","required":true,"description":"Comma-separated positive safe-integer chain IDs. Values are deduplicated and sorted; maximum 20. V3 indexing support is reported per chain at runtime in `meta.coverage`.","schema":{"type":"string","maxLength":256}},{"name":"category","in":"query","required":false,"description":"Comma-separated normalized category filter. Empty or unknown values return 400.","schema":{"type":"string","maxLength":1024}},{"name":"eventType","in":"query","required":false,"description":"Comma-separated normalized event type filter. Empty or unknown values return 400.","schema":{"type":"string","maxLength":1024}},{"name":"cursor","in":"query","required":false,"description":"Opaque keyset cursor bound to the complete query shape.","schema":{"type":"string","maxLength":2048}},{"name":"from","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":9007199254740991},"description":"Inclusive unix timestamp in seconds."},{"name":"to","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":9007199254740991},"description":"Inclusive unix timestamp in seconds."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Normalized owner activity timeline and per-chain indexed-source coverage.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityResponse"}}}},"400":{"$ref":"#/components/responses/Error400"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"getActivityAccountEvents"}},"/v3/accounts/{address}/activity":{"get":{"tags":["Accounts"],"summary":"Account vault activity discovery","description":"Discovers vault tuples an account interacts with (shares and/or controller-enabled debt),\nincluding sub-accounts when available.\nUses `meta.hasMore` for pagination continuation on the hot path rather than an exact `meta.total`.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/AddressPath"},{"$ref":"#/components/parameters/ChainIdParam"},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Account activity","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AccountActivity"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"504":{"$ref":"#/components/responses/Error504"}},"operationId":"getAccountsByAddressActivity"}},"/v3/tokens":{"get":{"tags":["Tokens"],"summary":"Token list","x-status":"implemented","x-cache-ttl":300,"parameters":[{"$ref":"#/components/parameters/ChainIdParam"},{"name":"address","in":"query","required":false,"description":"Filter by a token address. May be repeated. Combine with chainId for the fastest lookup path. Counts toward the 100-address filter cap. When address filters are present and limit is omitted, the default limit is the requested address count capped at 100.","schema":{"type":"string","example":"0x0000000000085d4780B73119b644AE5ecd22b376"}},{"name":"addresses","in":"query","required":false,"description":"Filter by comma-separated token addresses. May be repeated. Maximum 100 addresses. Combine with chainId for the fastest lookup path. When address filters are present and limit is omitted, the default limit is the requested address count capped at 100.","schema":{"type":"string","example":"0x0000000000085d4780B73119b644AE5ecd22b376,0x00000000eFE302BEAA2b3e6e1b18d08D69a9012a"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/TokenLimitParam"},{"name":"search","in":"query","required":false,"description":"Literal token name or symbol search. Supply once, with at most 128 UTF-8 bytes and no control characters.","schema":{"type":"string"}},{"name":"type","in":"query","required":false,"description":"Filter by token classification. Comma-separated values: base, debt, unitOfAccount, oracleAsset, reward, swapAsset","schema":{"type":"string","example":"base,debt"}}],"responses":{"200":{"description":"Tokens","headers":{"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"example":{"data":[{"chainId":1,"address":"0x000000000085d4780B73119b644AE5ecd22b376","name":"TrueUSD","symbol":"TUSD","decimals":18,"logoURI":"https://v3.euler.finance/v3/images/tokens/1/0x000000000085d4780B73119b644AE5ecd22b376?v=3f9c2a71","hasLogo":true,"tags":["usd"]}],"meta":{"total":1874,"offset":0,"limit":1,"timestamp":"2026-03-30T13:04:02.594Z","chainId":"1"}},"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Token"}},"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":"getTokens"}},"/v3/tokens/{chainId}/{address}/price":{"get":{"tags":["Prices"],"summary":"Token price","x-status":"implemented","x-cache-ttl":300,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"}],"responses":{"200":{"description":"Token price","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":{"$ref":"#/components/schemas/Price"},"meta":{"type":"object","properties":{"timestamp":{"type":"string","format":"date-time"}}}}}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"getTokensByChainIdByAddressPrice"}},"/v3/prices":{"get":{"tags":["Prices"],"summary":"Batch prices for tokens","description":"Current prices, one row per priced token. A token without a current price is left out, not returned as null. With `addresses` and a single `chainId`, rows follow the order of `addresses` and repeated addresses (in any case) give one row. `limit` and `offset` page over the priced rows only: `meta.hasMore` is true while more priced rows follow. `meta.total` is not returned. To read up to 100 addresses in one call, send `limit=100` and follow `meta.hasMore`.","x-status":"implemented","x-cache-ttl":300,"parameters":[{"$ref":"#/components/parameters/ChainIdParam"},{"name":"addresses","in":"query","required":false,"schema":{"type":"string","minLength":1,"pattern":"\\S"},"description":"Comma-separated token addresses (maximum 100). When both `addresses` and the deprecated `assets` alias are supplied, `addresses` takes precedence. More than 100 values, or an invalid address, answers 400."},{"name":"assets","in":"query","required":false,"deprecated":true,"schema":{"type":"string","minLength":1,"pattern":"\\S"},"description":"Deprecated alias for `addresses`, used only when `addresses` is absent. Maximum 100 addresses."},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Prices","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/Price"}},"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":"getPrices"}},"/v3/prices/history":{"get":{"tags":["Prices"],"summary":"Historical prices","description":"Historical prices for explicit token addresses over a bounded time range.\nRequired query params: `chainId`, `from`, `to`, and at least one of\n`addresses` or its deprecated `assets` alias. When both address parameters\nare supplied, `addresses` takes precedence.\nMaximum allowed window is 30 days per request.\n","x-status":"implemented","x-cache-ttl":300,"parameters":[{"name":"chainId","in":"query","required":true,"schema":{"type":"integer"}},{"name":"addresses","in":"query","required":false,"schema":{"type":"string","minLength":1,"pattern":"\\S"},"description":"Comma-separated token addresses (maximum 100)."},{"name":"assets","in":"query","required":false,"deprecated":true,"schema":{"type":"string","minLength":1,"pattern":"\\S"},"description":"Deprecated alias for `addresses`, used only when `addresses` is absent. Maximum 100 addresses."},{"name":"from","in":"query","required":true,"schema":{"type":"integer"},"description":"Inclusive start of the history window as a unix timestamp in seconds (UTC)."},{"name":"to","in":"query","required":true,"schema":{"type":"integer"},"description":"Inclusive end of the history window as a unix timestamp in seconds (UTC)."},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Historical prices","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/Price"}},"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":"getPricesHistory"}},"/v3/apys/intrinsic":{"get":{"tags":["APYs"],"summary":"Intrinsic APYs","description":"Returns one row per chain and asset. The newest provider observation is selected; equal timestamps use provider and uniquifier ascending as deterministic tie-breakers. An asset whose newest non-zero observation is older than 7 days is left out. A provider set up per token (a yield-source entry, or a DefiLlama pool mapping) is served only while the asset has an enabled entry for it, and a DefiLlama pool APY only while the mapping names that pool; other providers, such as Pendle, are not set up per token.","x-status":"implemented","x-cache-ttl":600,"parameters":[{"$ref":"#/components/parameters/ChainIdParam"},{"name":"assets","in":"query","required":false,"schema":{"type":"string"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Intrinsic APYs","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/IntrinsicApy"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"}},"operationId":"getApysIntrinsic"}},"/v3/apys/intrinsic/history":{"get":{"tags":["APYs"],"summary":"Intrinsic APY history","x-status":"implemented","x-cache-ttl":300,"parameters":[{"$ref":"#/components/parameters/ChainIdParam"},{"name":"asset","in":"query","required":true,"schema":{"type":"string"},"description":"Asset address to query."},{"name":"resolution","in":"query","required":true,"schema":{"type":"string","enum":["1h","1d"]},"description":"Bucket size for aggregation."},{"$ref":"#/components/parameters/StartTimestampParam"},{"$ref":"#/components/parameters/EndTimestampParam"}],"responses":{"200":{"description":"Intrinsic APY history","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/IntrinsicApyHistoryPoint"}},"meta":{"$ref":"#/components/schemas/IntrinsicApyHistoryMeta"}}}}}}},"operationId":"getApysIntrinsicHistory"}},"/v3/apys/rewards":{"get":{"tags":["Rewards"],"summary":"Rewards APYs","description":"Reward campaigns per vault: upcoming, active, and ended in the last 30 days.\nA campaign that ended more than 30 days ago is not listed, and a vault whose\ncampaigns all ended more than 30 days ago has no row. `totalApr` adds up\nactive campaigns only. Past reward rates are in `/v3/apys/rewards/history`.\n","x-status":"implemented","x-cache-ttl":900,"parameters":[{"$ref":"#/components/parameters/ChainIdParam"},{"name":"vault","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Rewards APYs","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/RewardsApy"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}},"operationId":"getApysRewards"}},"/v3/apys/rewards/history":{"get":{"tags":["Rewards"],"summary":"Rewards APY history","description":"Rewards APY history for a required time range.\nRequired query params: `chainId`, `from`, `to`.\nOptional filters: `vault`, `resolution`, `offset`, `limit`.\nMaximum allowed window is 30 days per request.\n","x-status":"implemented","x-cache-ttl":300,"parameters":[{"name":"chainId","in":"query","required":true,"schema":{"type":"integer"}},{"name":"from","in":"query","required":true,"schema":{"type":"integer"}},{"name":"to","in":"query","required":true,"schema":{"type":"integer"}},{"name":"resolution","in":"query","required":false,"schema":{"type":"string","enum":["1h","1d"],"default":"1d"}},{"name":"vault","in":"query","required":false,"schema":{"type":"string"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Rewards APY history","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/RewardsApyHistoryPoint"}},"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":"getApysRewardsHistory"}},"/v3/oracles/adapter-assessments":{"get":{"tags":["Oracles"],"summary":"Oracle adapter assessments","description":"Returns persisted recognition and health findings for adapters discovered on one chain.","x-status":"implemented","x-cache-ttl":300,"parameters":[{"name":"chainId","in":"query","required":true,"schema":{"type":"integer","minimum":1}},{"name":"recognized","in":"query","required":false,"schema":{"type":"boolean"}},{"name":"active","in":"query","required":false,"description":"Filter on current active-route membership.","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Oracle adapter assessments","headers":{"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OracleAdapterAssessment"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"listOracleAdapterAssessments"}},"/v3/oracles/adapter-assessments/{address}":{"get":{"tags":["Oracles"],"summary":"Oracle adapter assessment","description":"Returns the persisted recognition and health findings for one adapter on one chain.","x-status":"implemented","x-cache-ttl":300,"parameters":[{"name":"address","in":"path","required":true,"schema":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"}},{"name":"chainId","in":"query","required":true,"schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"Oracle adapter assessment","headers":{"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/OracleAdapterAssessment"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"getOracleAdapterAssessment"}},"/v3/oracles/adapter-assessments/evaluate":{"post":{"tags":["Oracles"],"summary":"Evaluate an oracle adapter without recording it","description":"Runs the adapter policy against the address at one pinned block and answers the verdict\nin the stored assessment's shape. Nothing is written: no registry row, no assessment; the\nadapter is recorded when a router installs it (the indexer's `ConfigSet` handler) or when\nthe hourly router-history sweep finds it. Cross-adapter legs the registry does not know\nare evaluated inline at the same block, two levels deep, and reported in `legs`; Pyth\nreads carry a fresh Hermes update like the stored checks. The address must have bytecode\non the chain (422 otherwise), one address is evaluated at most 6 times per minute (429 with\n`Retry-After`), a repeated request within 30 seconds answers the same evaluation, and the\non-chain reads are given 12 seconds (504 when exceeded). Accepts a platform session or a\nAPI key holding `assessments:evaluate`; a curator session is never enough.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OracleAdapterEvaluationRequest"}}}},"responses":{"200":{"description":"The evaluate-only verdict; `persisted` is always false.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/OracleAdapterEvaluation"}}}}}},"400":{"description":"Malformed JSON request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"description":"A key without `assessments:evaluate`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The chain is not served by this deployment (`CHAIN_NOT_SUPPORTED`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"$ref":"#/components/responses/Error413"},"415":{"$ref":"#/components/responses/Error415"},"422":{"description":"A body that is not `{ chainId, address }` (`error.details.issues`), or no contract is deployed at the address (`error.details.blockNumber` names the block checked).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The address was evaluated more than 6 times in the last minute; `Retry-After` and `error.details.retryAfterSeconds` say when to retry.","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/Error500"},"503":{"$ref":"#/components/responses/Error503"},"504":{"description":"The on-chain reads did not finish within the 12-second budget (`UPSTREAM_TIMEOUT`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"operationId":"evaluateOracleAdapter"}},"/v3/oracles/prices":{"get":{"tags":["Oracles"],"summary":"Vault-scoped oracle prices","description":"Supports exact mode (`chainId + vault + asset`) and list mode (`chainId` + pagination).\n- Exact mode requires the full key.\n- Exact mode returns `200` with `price: null` when the tuple is known but currently unpriced.\n- Non-null `price` values are exact contract-derived prices encoded as 18-decimal bigint strings in `unitOfAccount` terms.\n- Exact mode returns `404` only when the `(chainId, vault, asset)` tuple is unknown.\n- Partial exact key requests return `400`.\n- List mode returns flat rows sorted by `vault ASC, asset ASC`.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"name":"chainId","in":"query","required":true,"schema":{"type":"integer"}},{"name":"vault","in":"query","required":false,"schema":{"type":"string"}},{"name":"asset","in":"query","required":false,"schema":{"type":"string"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Oracle prices","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":{"oneOf":[{"type":"object","properties":{"chainId":{"type":"integer"},"vault":{"type":"string"},"asset":{"type":"string"},"price":{"type":"string","nullable":true},"unitOfAccount":{"type":"string","nullable":true},"unitOfAccountDecimals":{"type":"integer","nullable":true},"source":{"type":"string","enum":["onchain","offchain","hardcoded"],"nullable":true},"timestamp":{"type":"string","format":"date-time","nullable":true}}},{"type":"array","items":{"type":"object","properties":{"chainId":{"type":"integer"},"vault":{"type":"string"},"asset":{"type":"string"},"price":{"type":"string","nullable":true},"unitOfAccount":{"type":"string","nullable":true},"unitOfAccountDecimals":{"type":"integer","nullable":true},"source":{"type":"string","enum":["onchain","offchain","hardcoded"],"nullable":true},"timestamp":{"type":"string","format":"date-time","nullable":true}}}}]},"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"},"502":{"$ref":"#/components/responses/Error502"}},"operationId":"getOraclesPrices"}},"/v3/oracles/routers":{"get":{"tags":["Oracles"],"summary":"Oracle router state","description":"Factory-deployed EulerRouter list with latest indexed config and resolved-vault state.\n- `chainId` is required.\n- Optional filters: `vault`, `adapter`, `offset`, `limit`.\n","x-status":"implemented","x-cache-ttl":300,"parameters":[{"name":"chainId","in":"query","required":true,"schema":{"type":"integer"}},{"name":"vault","in":"query","required":false,"schema":{"type":"string"}},{"name":"adapter","in":"query","required":false,"schema":{"type":"string"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Router states","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"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"getOraclesRouters"}},"/v3/oracles/historical-adapters":{"get":{"tags":["Oracles"],"summary":"Historical oracle adapters","description":"Distinct oracle adapter addresses ever configured through `ConfigSet` events\non any EulerRouter deployed by OracleRouterFactory for the requested chain.\n- `chainId` is required.\n- Supports `offset` and `limit`.\n","x-status":"implemented","x-cache-ttl":300,"parameters":[{"name":"chainId","in":"query","required":true,"schema":{"type":"integer"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Historical adapter addresses","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":{"type":"object","properties":{"chainId":{"type":"integer"},"adapter":{"type":"string"},"firstSeenTimestamp":{"type":"string","format":"date-time"},"lastSeenTimestamp":{"type":"string","format":"date-time"}}}},"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":"getOraclesHistoricalAdapters"}},"/v3/earn/vaults":{"get":{"tags":["Earn"],"summary":"Earn vaults","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdParam"},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"},{"name":"visibility","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated visibility filter (`visible,warning,hidden,pending_review`). Defaults to `visible,warning` — hidden and pending_review vaults are excluded from discovery unless requested explicitly."}],"responses":{"200":{"description":"Earn vaults","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EarnVaultSummary"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"504":{"$ref":"#/components/responses/Error504"}},"operationId":"getEarnVaults"}},"/v3/securitize/vaults/batch":{"post":{"tags":["Securitize"],"summary":"Securitize vault batch","description":"Returns Securitize vault rows for explicit addresses on one chain, in request\norder after address deduplication; `meta.notFound` lists the rest. The\ngoverning address is `governorAdmin`. Serves what the EVK routes never\nlist: Securitize vaults come from their own factory and their own indexed\ntable. A chain this deployment does not index answers 404\n`CHAIN_NOT_SUPPORTED`; an indexed chain with no Securitize factory answers\nevery address as not found. When the indexed positions or the prices\ncannot be read, the rows still answer, with the affected deposit fields\nnull, the source named in `meta.degradedProviders`, and\n`Cache-Control: no-store`.\nRequest cap: 1000 vault addresses and 256 KiB of JSON body.\n","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\nresolves an address by family reads the EVK detail first, then Earn, then\nthis route; each answers 404 `VAULT_NOT_FOUND` for a vault of another\nfamily. When the indexed positions or the prices cannot be read, the vault\nstill answers, with the affected deposit fields null, the source named in\n`meta.degradedProviders`, and `Cache-Control: no-store`.\n","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"}},"/v3/earn/vaults/batch":{"post":{"tags":["Earn"],"summary":"Earn vault batch","description":"Returns earn vault summaries for explicit addresses on one chain.\nPass `include: [\"strategies\"]` to add the same strategy objects\nreturned by earn vault detail.\nResponse preserves request order after address deduplication.\nRequest cap: 1000 vault addresses and 256 KiB of JSON body.\n","x-status":"implemented","x-cache-ttl":60,"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EarnVaultBatchRequest"}}}},"responses":{"200":{"description":"Earn vault batch","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EarnVaultBatchResponse"}}}},"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":"postEarnVaultBatch"}},"/v3/earn/vaults/{chainId}/{address}/totals":{"get":{"tags":["Earn"],"summary":"Earn vault totals history","description":"Returns aggregator-level Earn vault totals history. This endpoint uses\nEarn semantics and intentionally omits EVK-only borrowed, cash, and\nutilization fields. Fresh Earn snapshots serve current totals, APY, and\nshare price without Ponder or RPC work; missing or stale snapshots retain\nthe indexed/live fallback. Historical USD values use bucket-aligned asset\nprices when available and remain null when pricing is unavailable. The\neffective end is `to` or the current time. When\n`from` is omitted, the effective window is 7 days for `1h` and 30 days for\n`1d`. Ranges count both endpoint buckets and support at most 744 hourly\nbuckets or 732 daily buckets.\nEach point includes a nullable sharePriceQuote with exact assets per whole\nshare and block provenance. Coverage evaluates assetsPerShare separately\nfrom the raw sharePrice ratio and APY. Quote unavailability does not suppress\nother available metrics or synthesize historical quotes.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"name":"resolution","in":"query","required":false,"schema":{"type":"string","enum":["1h","1d"],"default":"1d"}},{"$ref":"#/components/parameters/HistoryFromParam"},{"$ref":"#/components/parameters/HistoryToParam"}],"responses":{"200":{"description":"Earn vault totals history","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/EarnTotalsHistory"},"meta":{"$ref":"#/components/schemas/EarnTotalsHistoryMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"},"503":{"$ref":"#/components/responses/Error503"},"504":{"$ref":"#/components/responses/Error504"}},"operationId":"getEarnVaultsByChainIdByAddressTotals"}},"/v3/earn/vaults/{chainId}/{address}":{"get":{"tags":["Earn"],"summary":"Earn vault detail","description":"Returns earn vault detail. Optional `include` expands related resources.\nSupported values: `apy`, `totals`, `prices`.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"$ref":"#/components/parameters/IncludeParam"}],"responses":{"200":{"description":"Earn vault detail","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":{"$ref":"#/components/schemas/EarnVaultDetailsWithIncludes"},"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"},"504":{"$ref":"#/components/responses/Error504"}},"operationId":"getEarnVaultsByChainIdByAddress"}},"/v3/earn/vaults/{chainId}/{address}/events":{"get":{"tags":["Earn"],"summary":"Unified Euler Earn vault event timeline","description":"Unified stream of user, interest/reallocation, and governance earn-vault events.\nRequires a bounded time window (`from` + `to`), max 30 days.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"name":"from","in":"query","required":true,"schema":{"type":"integer"}},{"name":"to","in":"query","required":true,"schema":{"type":"integer"}},{"name":"type","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated event type filter. Unknown values return 400."},{"$ref":"#/components/parameters/IndexedEventsOffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Earn vault events","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"chainId":{"type":"integer"},"type":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"blockNumber":{"type":"string"},"txHash":{"type":"string"},"logIndex":{"type":"integer"},"payload":{"type":"object"}}}},"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":"getEarnVaultsByChainIdByAddressEvents"}},"/v3/liquidations":{"get":{"tags":["Liquidations"],"summary":"Liquidation events","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdParam"},{"name":"vault","in":"query","required":false,"schema":{"type":"string"}},{"name":"violator","in":"query","required":false,"schema":{"type":"string"}},{"name":"liquidator","in":"query","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","required":true,"schema":{"type":"integer"}},{"name":"to","in":"query","required":true,"schema":{"type":"integer"}},{"$ref":"#/components/parameters/SortParam"},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Liquidations","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LiquidationEvent"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"}},"operationId":"getLiquidations"}},"/v3/evk/vaults/{chainId}/{address}/config-history":{"get":{"tags":["Vaults"],"summary":"Vault configuration history","description":"LTV (`ltv`), cap (`cap`) and interest rate model (`irm`) changes of this vault in one\ntimeline, newest first; `meta.total` counts all three kinds. There is no type filter:\nuse cap-history, ltv-history or irm-history for one kind. Without `from` and `to` the\ntimeline is unbounded.\n","x-status":"implemented","x-cache-ttl":300,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"$ref":"#/components/parameters/FromParam"},{"$ref":"#/components/parameters/ToParam"},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Vault config history","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/ConfigHistoryItem"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"description":"A `from` or `to` that is not a whole number of seconds (digits only).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"operationId":"getVaultsByChainIdByAddressConfigHistory"}},"/v3/evk/vaults/{chainId}/{address}/collaterals":{"get":{"tags":["Vaults"],"summary":"Current accepted collaterals with LTV configurations","description":"Returns the list of vaults accepted as collateral for this vault,\nalong with their current LTV configurations. Use this to understand\nwhat assets can be used as collateral when borrowing from this vault.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"}],"responses":{"200":{"description":"Accepted collaterals with LTV configs","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/CollateralConfig"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"404":{"$ref":"#/components/responses/Error404"}},"operationId":"getVaultsByChainIdByAddressCollaterals"}},"/v3/evk/vaults/{chainId}/{address}/ltv-history":{"get":{"tags":["Vaults"],"summary":"Vault LTV history","x-status":"implemented","x-cache-ttl":300,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"name":"collateral","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by collateral vault address"},{"$ref":"#/components/parameters/FromParam"},{"$ref":"#/components/parameters/ToParam"},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Vault LTV history","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LtvHistoryItem"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"}},"operationId":"getVaultsByChainIdByAddressLtvHistory"}},"/v3/evk/vaults/{chainId}/{address}/cap-history":{"get":{"tags":["Vaults"],"summary":"Vault cap history (supply/borrow)","description":"Returns retained supply and borrow cap changes. With includeBaseline=true, data contains events plus the latest captured cap at or before from, exact cap decoding and availability. Missing baselines are not inferred as zero or unlimited. Count, page and baseline use one database snapshot. No full-range indexer continuity or historical USD valuation is asserted.","x-status":"implemented","x-cache-ttl":300,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"name":"includeBaseline","in":"query","required":false,"schema":{"type":"boolean","default":false}},{"name":"from","in":"query","required":false,"description":"Inclusive Unix-seconds range start; required with includeBaseline=true.","schema":{"type":"integer"}},{"name":"to","in":"query","required":false,"description":"Inclusive Unix-seconds range end.","schema":{"type":"integer"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Vault cap history","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"oneOf":[{"type":"array","items":{"$ref":"#/components/schemas/CapHistoryItem"}},{"$ref":"#/components/schemas/CapHistoryWithBaseline"}]},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"}},"operationId":"getVaultsByChainIdByAddressCapHistory"}},"/v3/evk/vaults/{chainId}/{address}/irm-history":{"get":{"tags":["Vaults"],"summary":"Vault interest rate model history","description":"Returns historical changes to the interest rate model for this vault.","x-status":"implemented","x-cache-ttl":300,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"$ref":"#/components/parameters/FromParam"},{"$ref":"#/components/parameters/ToParam"},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Vault IRM history","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/IrmHistoryItem"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"}},"operationId":"getVaultsByChainIdByAddressIrmHistory"}},"/v3/evk/vaults/{chainId}/{address}/events":{"get":{"tags":["Vaults"],"summary":"Unified core vault event timeline","description":"Unified stream of deposit, withdraw, borrow, repay, and transfer events for one vault.\nRequires a bounded time window (`from` + `to`), max 30 days.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"$ref":"#/components/parameters/FromParam"},{"$ref":"#/components/parameters/ToParam"},{"name":"type","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated event type filter. Unknown values return 400."},{"$ref":"#/components/parameters/IndexedEventsOffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Vault events","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"chainId":{"type":"integer"},"type":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"blockNumber":{"type":"string"},"txHash":{"type":"string"},"logIndex":{"type":"integer"},"payload":{"type":"object"}}}},"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":"getVaultsByChainIdByAddressEvents"}},"/v3/evk/vaults/{chainId}/{address}/totals":{"get":{"tags":["Vaults"],"summary":"Vault totals with historical series","description":"Returns totalAssets, totalBorrows, utilization, and APY from dynamic\nsnapshots. Raw amount fields are bigint strings; USD fields use the latest\nasset price for current and bucket-aligned historical asset prices for\nhistory entries when available. The effective end is `to` or the current\ntime. When `from` is omitted, the effective window is 7 days for `1h` and\n30 days for `1d`. Ranges count both endpoint buckets and support at most\n744 hourly buckets or 732 daily buckets.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"name":"resolution","in":"query","required":false,"schema":{"type":"string","enum":["1h","1d"],"default":"1d"}},{"$ref":"#/components/parameters/HistoryFromParam"},{"$ref":"#/components/parameters/HistoryToParam"},{"name":"forceFresh","in":"query","required":false,"schema":{"type":"boolean"},"description":"When true, trigger bounded synchronous vault dynamic refresh before reading totals.\nOn timeout/failure, response safely falls back to stored snapshots and indicates cached mode in freshness metadata.\n"}],"responses":{"200":{"description":"Vault totals with current + historical data","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/VaultTotals"},"meta":{"$ref":"#/components/schemas/VaultTotalsMeta"},"freshness":{"$ref":"#/components/schemas/VaultTotalsFreshness"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"503":{"description":"Vault totals history concurrency is at capacity","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"operationId":"getVaultsByChainIdByAddressTotals"}},"/v3/evk/vaults/{chainId}/{address}/holders":{"get":{"tags":["Vaults"],"summary":"Vault share holders","description":"Returns all holders with non-zero share balances via transfer aggregation (raw holder set). This endpoint does not unwrap Euler Earn depositors and therefore aligns with legacy behavior when `resolveEulerEarn=false`. Supports 4-byte `addressPrefix` filter for wallet-scoped scans. Balance values are integer strings in raw mode; when resolve flags are enabled, balances may be proportional decimal strings.","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"name":"addressPrefix","in":"query","required":false,"schema":{"type":"string","pattern":"^0x[a-fA-F0-9]{8}$"},"description":"Optional 4-byte account prefix filter (`0x` + 8 hex chars)."},{"name":"resolveEulerEarn","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"When true, expands Euler Earn vault-holder addresses into underlying depositors (v1 parity mode)."},{"name":"resolveSubAccounts","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"When true, aggregates sub-account holders into their owner addresses."},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Vault share holders","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"holder":{"type":"string"},"balance":{"type":"string","description":"Numeric string; integer in raw mode, may be decimal when resolve flags are enabled."},"lastTransferBlock":{"type":"string"},"lastTransferTimestamp":{"type":"string"}}}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"}},"operationId":"getVaultsByChainIdByAddressHolders"}},"/v3/evk/vaults/{chainId}/{address}/debt-holders":{"get":{"tags":["Vaults"],"summary":"Vault debt holder candidates","description":"Returns addresses that have the vault enabled as a controller. Optimistic set - some may have zero debt.","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Vault debt holder candidates","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"account":{"type":"string"},"enabledAtBlock":{"type":"string"},"enabledAtTimestamp":{"type":"string"}}}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"}},"operationId":"getVaultsByChainIdByAddressDebtHolders"}},"/v3/evk/vaults/open-interest":{"get":{"tags":["Vaults"],"summary":"Open interest across vaults","description":"Event-based aggregation of total borrows and borrower counts. Uses MV-backed query path (`open_interest_debt_mv`) with safe fallback to raw aggregation when unavailable. Prices should be composed separately via /v3/prices.","x-status":"implemented","x-cache-ttl":300,"parameters":[{"name":"chainId","in":"query","required":true,"description":"Chain ID (required)","schema":{"type":"string"}},{"name":"vault","in":"query","required":false,"schema":{"type":"string"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Open interest data","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"vault":{"type":"string"},"asset":{"type":"string"},"totalBorrows":{"type":"string"},"borrowerCount":{"type":"integer","minimum":0,"description":"Number of indexed account-vault positions with positive event-derived debt. Subaccounts count separately. Controller registrations with zero debt are excluded."},"timestamp":{"type":"string","format":"date-time"}}}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"}},"operationId":"getVaultsOpenInterest"}},"/v3/evk/vaults/open-interest/by-collateral":{"get":{"tags":["Vaults"],"summary":"Collateral-covered debt by collateral vault","description":"Collateral-covered USD borrow exposure as a nested map keyed by borrow vault, then collateral vault. Underwater debt is capped at current attributable collateral value, so this endpoint is not gross open interest. The expensive account-level debt/collateral composition is worker-computed and stored in a latest projection table; the request path only reads that projection. Redis may cache this response, but PostgreSQL projection rows are the source of truth.\n","x-status":"implemented","x-cache-ttl":300,"parameters":[{"name":"chainId","in":"query","required":true,"description":"Chain ID (required)","schema":{"type":"string"}}],"responses":{"200":{"description":"Collateral-covered borrow exposure map","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"type":"number","format":"double","description":"USD collateral-covered debt attributable to this collateral vault"}},"description":"Borrow-vault to collateral-vault USD collateral-covered exposure map"},"meta":{"allOf":[{"$ref":"#/components/schemas/PaginationMeta"},{"type":"object","properties":{"refreshedAt":{"type":["string","null"],"format":"date-time"},"calculationTimestamp":{"type":["string","null"],"format":"date-time"},"priceTimestamp":{"type":["string","null"],"format":"date-time","description":"Newest of the per-row oldest prices: each row records the oldest price it used, and this is the most recent of those.\n"},"oldestPriceTimestamp":{"type":["string","null"],"format":"date-time","description":"Oldest price used across the chain's rows. Null when no row was priced.\n"},"ageSeconds":{"type":["integer","null"]}}}]}}}}}}},"operationId":"getVaultsOpenInterestByCollateral"}},"/v3/evk/vaults/bad-debt":{"get":{"tags":["Vaults"],"summary":"Bad debt by borrow vault","description":"Borrow-vault aggregate of asset-value bad debt. Rows include only underwater account/borrow-vault positions where gross debt value exceeds the current value of enabled collateral considered for that debt position. Healthy accounts are omitted and no chain-level bad-debt total is exposed. Values use asset-value insolvency, not risk-adjusted LTV shortfall. Enabled collateral without a usable current price (feed stopped, asset collapsed) is valued at zero, so the debt it secures stays in the calculation rather than being dropped.\n","x-status":"implemented","x-cache-ttl":300,"parameters":[{"name":"chainId","in":"query","required":true,"description":"Chain ID (required)","schema":{"type":"string"}},{"name":"borrowVault","in":"query","required":false,"description":"Optional borrow vault/controller address filter","schema":{"type":"string"}},{"name":"minBadDebtUsd","in":"query","required":false,"description":"Minimum bad debt USD threshold. Defaults to 0.","schema":{"type":"number","minimum":0,"default":0}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Borrow-vault bad-debt rows","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"chainId":{"type":"integer"},"borrowVault":{"type":"string"},"borrowAsset":{"type":"string"},"accountCount":{"type":"integer","description":"Number of underwater accounts contributing to this borrow-vault row."},"debtUsd":{"type":"number","format":"double","description":"Gross USD debt for underwater account/borrow-vault positions."},"collateralUsd":{"type":"number","format":"double","description":"Current enabled collateral value considered for those underwater positions."},"coveredDebtUsd":{"type":"number","format":"double","description":"Portion of debt covered by current collateral value."},"badDebtUsd":{"type":"number","format":"double","description":"Uncovered debt, equal to debtUsd minus coveredDebtUsd within tolerance."},"unpricedBadDebtUsd":{"type":"number","format":"double","description":"Part of badDebtUsd from positions where at least one enabled collateral had no usable current price and was valued at zero.\n"},"unpricedCollateralCount":{"type":"integer","description":"Number of collateral positions without a usable current price in the underwater positions of this borrow vault.\n"},"calculationTimestamp":{"type":"string","format":"date-time"},"priceTimestamp":{"type":["string","null"],"format":"date-time"},"refreshedAt":{"type":"string","format":"date-time"}}}},"meta":{"allOf":[{"$ref":"#/components/schemas/PaginationMeta"},{"type":"object","properties":{"refreshedAt":{"type":["string","null"],"format":"date-time"},"calculationTimestamp":{"type":["string","null"],"format":"date-time"},"priceTimestamp":{"type":["string","null"],"format":"date-time","description":"Newest of the per-row oldest prices: each row records the oldest price it used, and this is the most recent of those.\n"},"oldestPriceTimestamp":{"type":["string","null"],"format":"date-time","description":"Oldest price used across the chain's rows. Null when no row was priced.\n"},"ageSeconds":{"type":["integer","null"]}}}]}}}}}},"400":{"$ref":"#/components/responses/Error400"}},"operationId":"getVaultsBadDebt"}},"/v3/accounts/{address}/sub-accounts":{"get":{"tags":["Accounts"],"summary":"Sub-accounts for an EVC-enabled account","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/AddressPath"},{"name":"chainId","in":"query","required":true,"schema":{"type":"string"},"description":"Comma-separated list of chain IDs (single value allowed).","example":"1"},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Sub-accounts","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SubAccount"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"}},"operationId":"getAccountsByAddressSubAccounts"}},"/v3/evc/accounts/{address}/events":{"get":{"tags":["EVC"],"summary":"Unified EVC account event timeline","description":"Account-primary EVC event stream. `chainId`, `from`, and `to` are required.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/AddressPath"},{"name":"chainId","in":"query","required":true,"schema":{"type":"string"},"description":"Comma-separated chain IDs."},{"name":"from","in":"query","required":true,"schema":{"type":"integer"}},{"name":"to","in":"query","required":true,"schema":{"type":"integer"}},{"name":"type","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated event type filter. Unknown values return 400."},{"$ref":"#/components/parameters/IndexedEventsOffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"EVC account events","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"chainId":{"type":"integer"},"type":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"blockNumber":{"type":"string"},"txHash":{"type":"string"},"logIndex":{"type":"integer"},"payload":{"type":"object"}}}},"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":"getEvcAccountsByAddressEvents"}},"/v3/public-allocator/events":{"get":{"tags":["PublicAllocator"],"summary":"Unified Public Allocator event timeline","description":"Unified stream of public allocator events. `chainId`, `from`, and `to` are required.\nPagination reports `hasMore`; this endpoint does not compute an exact `total`.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"name":"chainId","in":"query","required":true,"schema":{"type":"string"},"description":"Comma-separated chain IDs."},{"name":"from","in":"query","required":true,"schema":{"type":"integer"}},{"name":"to","in":"query","required":true,"schema":{"type":"integer"}},{"name":"type","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated event type filter. Unknown values return 400."},{"$ref":"#/components/parameters/IndexedEventsOffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Public allocator events","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"chainId":{"type":"integer"},"type":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"blockNumber":{"type":"string"},"txHash":{"type":"string"},"logIndex":{"type":"integer"},"payload":{"type":"object"}}}},"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":"getPublicAllocatorEvents"}},"/v3/fee-flow/events":{"get":{"tags":["FeeFlow"],"summary":"Unified fee-flow event timeline","description":"Unified stream of fee-flow events with current indexed coverage (`buy`).\n`chainId`, `from`, and `to` are required.\nPagination reports `hasMore`; this endpoint does not compute an exact `total`.\n","x-status":"implemented","x-cache-ttl":60,"parameters":[{"name":"chainId","in":"query","required":true,"schema":{"type":"string"},"description":"Comma-separated chain IDs."},{"name":"from","in":"query","required":true,"schema":{"type":"integer"}},{"name":"to","in":"query","required":true,"schema":{"type":"integer"}},{"name":"type","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated event type filter. Current supported value is `buy`. Unknown values return 400."},{"$ref":"#/components/parameters/IndexedEventsOffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Fee-flow events","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"chainId":{"type":"integer"},"type":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"blockNumber":{"type":"string"},"txHash":{"type":"string"},"logIndex":{"type":"integer"},"payload":{"type":"object"}}}},"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":"getFeeFlowEvents"}},"/v3/rewards/breakdown":{"get":{"tags":["Rewards"],"summary":"Per-user reward breakdowns","description":"Returns current per-account reward breakdown rows by chain and optional\nvault. Merkl rows are reconciled with direct Merkl user reward data at\nquery time when available; fully claimed Merkl rows are omitted, and\nstored Merkl rows older than 24 hours are hidden when live Merkl data\ncannot be read. Chain filters accept at most 12 distinct supported chain\nIDs and normalize duplicates before database and external requests. Each\naccount/filter combination is privately cached for five minutes, with a\nstale copy available for up to fifteen additional minutes when the\nhandler fails. Responses with a degraded live provider are marked in\n`meta.degradedProviders` and are not cached.\n","x-status":"implemented","x-cache-ttl":300,"parameters":[{"$ref":"#/components/parameters/RewardsBreakdownChainIdParam"},{"name":"account","in":"query","required":true,"schema":{"type":"string"}},{"name":"vault","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Reward breakdowns","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/RewardBreakdown"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"description":"Invalid account, vault, or chain filter. Chain filter failures use\n`INVALID_CHAIN_ID`; malformed values report `details.reason: invalid`,\nwhile more than 12 distinct IDs report `details.reason: too_many` and\n`details.maxDistinctChainIds: 12`.\n","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"One or more parsed chain IDs are not in the supported chain registry.\nThe response uses `CHAIN_NOT_SUPPORTED` with\n`details.reason: unsupported`.\n","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"operationId":"getRewardsBreakdown"}},"/v3/terms-of-use/signatures":{"get":{"tags":["TermsOfUse"],"summary":"Terms-of-use signature history","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/ChainIdParam"},{"name":"address","in":"query","required":false,"schema":{"type":"string"},"description":"Optional signer/account filter."},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"Terms-of-use signatures","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"chainId":{"type":"integer"},"signer":{"type":"string"},"account":{"type":"string"},"termsOfUseHash":{"type":"string"},"signedAt":{"type":"string","format":"date-time"},"message":{"type":"string"},"blockNumber":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"txHash":{"type":"string"}}}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"}},"operationId":"getTermsOfUseSignatures"}},"/v3/terms-of-use/check/{address}":{"get":{"tags":["TermsOfUse"],"summary":"Check whether an address signed terms of use","x-status":"implemented","x-cache-ttl":60,"parameters":[{"$ref":"#/components/parameters/AddressPath"},{"$ref":"#/components/parameters/ChainIdParam"}],"responses":{"200":{"description":"Terms-of-use signature status","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"signed":{"type":"boolean"},"signature":{"type":"object","nullable":true}}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"}},"operationId":"getTermsOfUseCheckByAddress"}},"/v3/graphql":{"post":{"tags":["GraphQL"],"summary":"GraphQL endpoint","x-status":"implemented","description":"GraphQL endpoint (shared auth/rate limit with REST), proxied to the\nPonder GraphQL API.\nPonder LIKE filter operators reject unescaped `%` and `_` wildcard values.\nBefore proxying, the API bounds the complete request including unused runtime variables,\nvariable defaults, inline arguments, input bytes/nodes/depth, boolean clauses, list entries,\naliases, `totalCount`, execution cost, `limit` (default maximum 1,000), and `offset`\n(default maximum 10,000). Offset scan cost is `offset + limit`; selected output expansion\nremains based on `limit`. Resource violations return `QUERY_TOO_BROAD` and malformed\ndocuments return `VALIDATION_ERROR` without contacting Ponder. Ponder 0.15.17 does not use\n`first` or `last` pagination arguments.\nEach API process also enforces a shared upstream concurrency cap (default 8), one total\nfetch-and-stream timeout (default 10 seconds), redirect rejection, GraphQL JSON media-type\nand object-shape validation, and a streamed decoded response cap (default 5,242,880 bytes).\nA non-queueing per-process query-cost bucket defaults to 100,000 units of capacity and a\n25,000-unit-per-second refill. Exhaustion returns 429 before an upstream slot is acquired;\nthe shared per-client API rate limiter remains the outer control.\nSelect a supported chain with the `chainId` query parameter, then\n`X-Chain-Id`, then the JSON body `chainId`, in that precedence order.\n","parameters":[{"name":"chainId","in":"query","required":false,"description":"Supported chain to query. Takes precedence over `X-Chain-Id` and body `chainId`.","schema":{"type":"integer","minimum":1}},{"name":"X-Chain-Id","in":"header","required":false,"description":"Supported chain to query when the query parameter is absent. Takes precedence over body `chainId`.","schema":{"type":"integer","minimum":1}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","minLength":1,"pattern":"\\S"},"variables":{"type":"object"},"operationName":{"type":"string"},"chainId":{"description":"Supported chain to query when neither the query parameter nor `X-Chain-Id` is supplied.","oneOf":[{"type":"integer","minimum":1},{"type":"string","pattern":"^[1-9]\\d*$"}]}}}}}},"responses":{"200":{"description":"GraphQL response","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error400"},"413":{"$ref":"#/components/responses/Error413"},"415":{"$ref":"#/components/responses/Error415"},"429":{"$ref":"#/components/responses/Error429"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"postGraphql"}},"/v3/images":{"get":{"tags":["Images"],"summary":"Get the public image base URL","description":"Public. Returns the base URL that every `logoURI` V3 serves starts with, for example `https://v3.euler.finance/v3/images`, so a client loads images from the same V3 as its data. Image paths go under it: `/tokens/{chainId}/{address}`, `/chains/{chainId}` and `/{namespace}/{assetKey}`. Cached as `public, max-age=3600`.","x-status":"implemented","responses":{"200":{"description":"The image base URL.","headers":{"Cache-Control":{"schema":{"type":"string","example":"public, max-age=3600"}},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","required":["publicBaseUrl"],"properties":{"publicBaseUrl":{"type":"string","format":"uri","description":"The configured image base URL without a trailing slash."}}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}}},"operationId":"getImageBase"}},"/v3/images/tokens/{chainId}/{address}":{"get":{"tags":["Images"],"summary":"Get a token image","description":"Returns the managed token image, or the managed `defaults/token` image when the token image is missing. Default responses use `public, max-age=300` even with a version query, and return 404 if the default is unavailable. A request whose `v` names the token's own current image digest is cached as `public, max-age=31536000, immutable`; other managed token image requests get `public, max-age=3600, stale-while-revalidate=86400`.","x-status":"implemented","parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"$ref":"#/components/parameters/ImageVersionQuery"}],"responses":{"200":{"description":"Normalized token image or managed default.","headers":{"ETag":{"schema":{"type":"string"}},"Last-Modified":{"schema":{"type":"string"}},"Cache-Control":{"schema":{"type":"string"}}},"content":{"image/webp":{"schema":{"type":"string","format":"binary"}}}},"304":{"description":"The supplied ETag is current."},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"getTokenImage"},"head":{"tags":["Images"],"summary":"Get token image headers","description":"Returns the token image or managed defaults/token headers without an image body. Default responses use public, max-age=300 even with a version query; a missing default returns 404.","x-status":"implemented","parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"},{"$ref":"#/components/parameters/ImageVersionQuery"}],"responses":{"200":{"description":"Normalized token image or managed default headers.","headers":{"Content-Type":{"schema":{"type":"string","enum":["image/webp"]}},"Content-Length":{"schema":{"type":"integer","minimum":0}},"ETag":{"schema":{"type":"string"}},"Last-Modified":{"schema":{"type":"string"}},"Cache-Control":{"schema":{"type":"string"}}}},"304":{"description":"The supplied ETag is current."},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"headTokenImage"}},"/v3/images/{namespace}/{assetKey}":{"get":{"tags":["Images"],"summary":"Get a managed image","description":"Serves any managed image, for example chain logos at `/v3/images/chains/{chainId}` and the default token image at `/v3/images/defaults/token`. Caching follows the token image route: immutable when `v` names the current digest, an hour otherwise. Token namespace misses serve `defaults/token` with a five-minute cache. Missing labels and other non-token assets return 404.","x-status":"implemented","parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,63}$"}},{"name":"assetKey","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9._-]{0,254}$"}},{"$ref":"#/components/parameters/ImageVersionQuery"}],"responses":{"200":{"description":"Normalized managed image.","headers":{"ETag":{"schema":{"type":"string"}},"Last-Modified":{"schema":{"type":"string"}},"Cache-Control":{"schema":{"type":"string"}}},"content":{"image/webp":{"schema":{"type":"string","format":"binary"}}}},"304":{"description":"The supplied ETag is current."},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"getManagedImage"},"head":{"tags":["Images"],"summary":"Get managed image headers","description":"Returns the managed image status and cache headers without an image body.","x-status":"implemented","parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,63}$"}},{"name":"assetKey","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9._-]{0,254}$"}}],"responses":{"200":{"description":"Normalized managed image headers.","headers":{"Content-Type":{"schema":{"type":"string","enum":["image/webp"]}},"Content-Length":{"schema":{"type":"integer","minimum":0}},"ETag":{"schema":{"type":"string"}},"Last-Modified":{"schema":{"type":"string"}},"Cache-Control":{"schema":{"type":"string"}}}},"304":{"description":"The supplied ETag is current."},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"500":{"$ref":"#/components/responses/Error500"}},"operationId":"headManagedImage"}},"/v3/work-items":{"get":{"tags":["Images","Prices"],"summary":"List work items of one type","description":"`token-logo-missing` requires `token-images:read` or an allowlisted Toolbox session. It returns in-scope assets (an asset of a vault the app shows, or of a collateral such a vault accepts) on enabled chains without a managed image, excluding applied removals and dismissals, with the worker's latest outcome, provider, attempt time and next retry time when available, and returns 503 until legacy occupancy is verified and source cutover is enabled. Scope inputs may be up to a minute old. With `state=reviewed` it lists dismissals instead.\n\n`token-price-missing` requires `price-sources:read` or an allowlisted Toolbox session. It is computed on each read for every in-scope asset (an asset of a vault the app shows) that is not priced, ordered by priority, then by deposits in USD at the last price. Inputs other than reviews may be up to a minute old; a dismissal or resume shows on the next read. A proposed dismissal leaves the item outstanding until an admin approves it.\n\n`asset-newly-exposed` requires `geo:read` or an allowlisted Toolbox session. It lists every asset a vault users can act on reaches, read from the exposure sweep (every 15 minutes): the assets of every EVK, Earn and Securitize vault that is not deprecated, verified or not, explorable or not; the assets of the collaterals the shown vaults accept; and what those are built on. A rule covers an asset when one of its asset selectors picks the asset, or picks a token the asset is built on; a rule limited to one product or vault leaves the item outstanding and is named in `rules`. Ordered by priority (exposure), then deposits in USD, then the newest exposure. `state` is, first match wins, `covered` (a rule applies on the whole chain), `reviewed` (a standing review), `baseline` (exposed when the chain's first sweep ran, so an existing asset is never new), `unverified-only` (reached only through vaults the app does not show) or `new`. The default `outstanding` is `new` only, and only `new` items count in the open-items gauge; `baseline` and `unverified-only` items are listed and reviewable with their own `state`.\n\nEach `asset-newly-exposed` item carries `coverage`, an onboarding checklist of five decisions: logo, price, category (`tags`), intrinsic APY (`yield`) and geo. A piece is settled when it has its data, an automatic match, or an applied \"none\" review; a settled piece is never a need. `needs` keeps the items with a need in any of the named pieces: not settled, no open proposal, in scope and not paused. Each piece has its write path, with no route of its own: logo: `POST /v3/changes/uploads` then a `token-images` `fill` (or a verified `fill` with `trustedSource`, or a PT `derive`) on `POST /v3/changes`; \"none\": `POST /v3/work-items/token-logo-missing/{id}/dismiss` with `no-logo-available`. price: a `price-sources` change on `POST /v3/changes` (key `<source>/<chainId>:<address>`); \"none\": `POST /v3/work-items/token-price-missing/{id}/dismiss` with `onchain-only` or `no-price-source`. tags: a `token-tags` change on `POST /v3/changes` (key `<tag>:<ruleType>:<value>`; the `addresses` rule type tags one token, value `<chainId>:<address>`); \"none\": `POST /v3/work-items/token-category-missing/{id}/dismiss` with `no-category`. yield: a `yield-sources` change (key `<source>/<chainId>:<address>`) or a `yield-pools` change (key `<chainId>:<address>`) on `POST /v3/changes`; \"none\": `POST /v3/work-items/token-intrinsic-apy-missing/{id}/dismiss` with `no-intrinsic-apy`. geo: the `/v3/geo-policies` routes or a `geo` change on `POST /v3/changes`; \"none\": `POST /v3/work-items/asset-newly-exposed/{id}/dismiss` with `no-rule-needed`. `token-category-missing` and `token-intrinsic-apy-missing` have no list of their own: this route returns 400 for them.\n\nFor every type, `review.decidedBy` is null for API-key readers. A missing or unknown `type` returns 400 before any capability check.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"type","in":"query","required":true,"schema":{"type":"string","enum":["token-logo-missing","token-price-missing","asset-newly-exposed"]}},{"name":"state","in":"query","description":"Outstanding items (default) or reviewed items. `token-price-missing` also accepts `all` and one outstanding state: `unpriced`, `aging`, `source-stopped` or `onchain-only`. For `token-logo-missing`, reviewed lists dismissals: in-scope tokens without a logo that carry an applied dismissal, each with its `review` (`WorkItemReview`). `asset-newly-exposed` also accepts `all`, `new`, `baseline`, `unverified-only` and `covered`; its `outstanding` is `new` only, with or without `needs`.\n","schema":{"type":"string","enum":["outstanding","reviewed","all","unpriced","aging","source-stopped","onchain-only","new","baseline","unverified-only","covered"],"default":"outstanding"}},{"name":"needs","in":"query","description":"`asset-newly-exposed` only. Comma-separated pieces of `logo`, `price`, `tags`, `yield` and `geo`; keeps the items where any of them has `need` true in `coverage`, within `state`.\n","schema":{"type":"string","example":"logo,price"}},{"name":"chainId","in":"query","schema":{"type":"integer","minimum":1}},{"name":"limit","in":"query","description":"Page size; a value above 100 is clamped to 100.","schema":{"type":"integer","minimum":1,"default":50}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":10000,"default":0}}],"responses":{"200":{"description":"Work items of the requested type","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/PriceCoverageWorkItemList"},{"$ref":"#/components/schemas/TokenLogoWorkItemList"},{"$ref":"#/components/schemas/GeoExposureWorkItemList"}]}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"listWorkItems"}},"/v3/changes/targets/token-images/{chainId}/{address}":{"get":{"tags":["Images"],"summary":"Read token image state, open proposals, and current sourcing suppression","description":"Requires `token-images:read` or an allowlisted Toolbox session. The open proposals (oldest first, at most 50) and the applied removal or dismissal that suppresses automatic sourcing are change records, as on every change route. API-key responses omit operator attribution from the provenance and the records.","x-status":"implemented","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"}],"responses":{"200":{"description":"Current digest, provenance, open proposals, and applied removal or dismissal","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/TokenImageTarget"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"getTokenImageChangeTarget"}},"/v3/changes/targets/price-sources/{chainId}/{address}":{"get":{"tags":["Changes","Prices"],"summary":"Read a token's price sources before proposing a change","description":"Requires `price-sources:read` or an allowlisted Toolbox session. Returns each configured source entry with its `version` (send it as `expectedVersion`; a source without an entry is filled with `expectedVersion: null`), the open proposals on the token, oldest first, and the current review of its price work item. API-key responses omit operator attribution, and `review.decidedBy` is null for them.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]}],"parameters":[{"$ref":"#/components/parameters/ChainIdPath"},{"$ref":"#/components/parameters/AddressPath"}],"responses":{"200":{"description":"The token's price sources","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/PriceSourceTarget"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"getPriceSourceTarget"}},"/v3/changes/targets/{domain}":{"get":{"tags":["Changes"],"summary":"Read one target of any domain before proposing a change","description":"Requires the domain's `:read` capability or an allowlisted Toolbox session; a domain no key may change (for example `trust-entries`) is session-only. `key` is the domain's target key (`keyFormat` in `GET /v3/changes/domains`). Returns the current value with the `version` to send as `expectedVersion`, the open proposals oldest first, and up to 50 decided changes newest first. API-key responses omit operator attribution.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":500}}],"responses":{"200":{"description":"The target","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/ChangeTarget"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"getChangeTarget"}},"/v3/changes/uploads":{"post":{"tags":["Images"],"summary":"Stage a private token image candidate","description":"Requires `token-images:propose` or an allowlisted Toolbox session. The normalized image is not served by `/v3/images` until a change is applied. Unclaimed stages expire after 24 hours; decided proposal stages are deleted on a best-effort basis after the decision commits.","x-status":"implemented","security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}},"image/svg+xml":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"Upload ID and digest","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"413":{"$ref":"#/components/responses/Error413"},"415":{"$ref":"#/components/responses/Error415"},"422":{"$ref":"#/components/responses/Error422"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"stageTokenImageChangeUpload"}},"/v3/changes":{"get":{"tags":["Changes"],"summary":"List changes in a domain","description":"Requires the domain's `:read` capability or an allowlisted Toolbox session. Without `domain` (or with `domain=all`) it lists every domain for a session and the domains a key may read. Without `status` it lists open proposals, oldest first; with a status (or `all`), newest first. `meta.total` is exact. A key may filter by its own key ID only. API-key responses omit operator attribution and other actors' IDs. Token-image rows add their image details. The admin secret is recorded as `actorKind=system` with `actorId=admin-secret`; rows from before carry `actorKind=admin-secret`.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"domain","in":"query","schema":{"type":"string","enum":["all","token-images","price-sources","yield-sources","yield-pools","token-tags","trust-entries","geo"],"default":"all"}},{"name":"status","in":"query","schema":{"type":"string","enum":["proposed","applied","rejected","superseded","reverted","withdrawn","failed","expired","all"]}},{"name":"actorKind","in":"query","schema":{"type":"string","enum":["api-key","platform-admin","admin-secret","system","entity-admin"]}},{"name":"actorId","in":"query","schema":{"type":"string"}},{"name":"targetKey","in":"query","schema":{"type":"string"}},{"name":"token","in":"query","description":"`<chainId>:<address>`. Keeps the changes whose target is that token, in every domain the reader may read, read by exact keys: `price-sources` `<source>/<chainId>:<address>` for every price source; `yield-sources` `<source>/<chainId>:<address>` for every yield source configured now; `yield-pools` and `token-images` `<chainId>:<address>`; `token-tags` rules of type `addresses` that name the token, `<tag>:addresses:<chainId>:<address>`; `geo` rules that apply to the token now (by address, symbol, name or lineage, as on `asset-newly-exposed`) and open rule proposals that name the token's address; and work-item reviews of the token, `<chainId>:<address>`, in every domain that records them. Not included: geo rules that were deleted or no longer apply to the token, token tag rules that match by symbol, symbol prefix, symbol fragment or CoinGecko category, and trust entries. Combines with the other filters.","schema":{"type":"string","pattern":"^[1-9][0-9]{0,15}:0x[0-9a-fA-F]{40}$"}},{"name":"since","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","description":"Page size; a value above 100 is refused, not clamped.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":10000,"default":0}}],"responses":{"200":{"description":"Changes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeList"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"listChanges"},"post":{"tags":["Changes"],"summary":"Submit a change in any registered domain","description":"One body for every domain, token images included; an API key must send `evidence`. A key needs the domain's `:propose` or `:write` capability; the server computes the op class, runs its checks and decides with the domain policy, and an active suspension turns an auto-apply into a proposal. A stale `expectedVersion` records a superseded change; the same actor's open proposal on the target is superseded by the new one. A token keeps one intrinsic APY source. A `yield-sources` or `yield-pools` change that turns an entry on, as an add or an enable, returns 409 with `details.reason` `one-apy-source` while the token has another enabled yield source or DefiLlama pool, or is a Pendle PT that has not matured; `details.apySources` names the other source and the message says how to switch. This holds for every actor, platform sessions included. A key's proposal is refused at submit, and an approval or a revert that would turn a second source on is refused the same way. Disabling, removing or editing a source is always allowed. To switch, send the new source and the change that disables or removes the old one together to `POST /v3/changes/batch`. A platform session's `dismiss` applies only while the work list's dismiss rule holds, and returns 409 otherwise; a key's dismissal is a proposal, checked again when an admin approves it. A geo `update` or `remove` must name a stored rule; a derived address row from `GET /v3/geo-policies` cannot be changed and returns 404. A price-sources `fill` from a key or a system actor applies on its own only when every fill check passes, `provider-fresh` included, which needs the provider's own time for its price (CoinGecko `last_updated_at`, DefiLlama `timestamp`, Pyth `publish_time`, or for an ERC-4626 share the time of the underlying's stored V3 price) to be at most 24 hours old and at most 5 minutes ahead. An ERC-4626 fill also needs `asset()` to be the identifier, any decimals override to equal the chain's, and the underlying to have a positive V3 price, taken as V3 selects it from any source, the on-chain fallback and other shares included. Pendle gives no price time; its price is a current quote, so the time of the read stands for it. A Pendle fill applies on its own only for the PT itself, when V3 has a Pendle market for it on a chain the Pendle price source supports and Pendle prices it above 0; a matured PT that Pendle still prices qualifies, at its redemption value. A Pyth source never applies on its own. When a provider or the chain cannot answer for a fill that could apply on its own (no current entry, a CoinGecko, DefiLlama, ERC-4626 or Pendle source, not disabled, from a key with `price-sources:write` or a system actor, and no active suspension), the change is not recorded and the request returns 503; send it again later. Any other change is recorded as a proposal with the failed checks. For token images, dispatches permissions by registered domain. `token-images:propose` permits staged candidates and `token-images:write` permits a verified CoinGecko or Pendle fill. Replacements and removals always remain proposals. The `derive` operation builds a Pendle PT's logo server-side from the current managed image of the token named in the optional `value.source` (by default the PT's recorded underlying in `token_integrations`), as a circle crop with the teal `#17e3c2` PT ring, recorded with `derivedFrom` (source digest) in its `derive-source` check. A platform session applies a derive; a system actor applies only an empty-slot fill from the recorded underlying's verified-provider image; any other derive is a proposal. A target that is not a Pendle PT returns 400; a source without a managed image, or one that already carries the ring, returns 409. A verified fill requires an eligible token class, empty managed slot, exact chain-and-contract provider match, and verified legacy cutover. Incomplete cutover or provider unavailability returns 503. API-key responses omit operator attribution. The generic change has expected/resulting versions and database decision order; token image snapshots and provider evidence are stored in a domain detail record.","x-status":"implemented","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"dryRun","in":"query","description":"Runs the checks and the policy and returns the decision without writing or staging anything.","schema":{"type":"boolean","default":false}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeSubmitRequest"}}}},"responses":{"200":{"description":"No exact provider candidate (token images), or a dry-run decision","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ChangeDryRunResult"},{"type":"object","additionalProperties":true}]}}}},"201":{"description":"Applied, proposed, or superseded change","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"429":{"$ref":"#/components/responses/Error429"},"503":{"$ref":"#/components/responses/Error503"}},"operationId":"submitChange"}},"/v3/changes/{id}":{"get":{"tags":["Changes"],"summary":"Read a change with its events","description":"Any registered domain; a row in an unregistered domain returns 400. Requires the domain's `:read` capability or an allowlisted Toolbox session. The record carries its event log, oldest first. API-key responses omit operator attribution from the change, its events and its image snapshots.","x-status":"implemented","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Recorded change, decision, and before and after digests","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"}},"operationId":"getChange"}},"/v3/changes/{id}/withdraw":{"post":{"tags":["Changes"],"summary":"Withdraw an open proposal","description":"Only the actor that submitted the proposal may withdraw it, while it is still proposed.","x-status":"implemented","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"description":"Optional; stored as the decision comment.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"reason":{"type":"string","minLength":3,"maxLength":1000}}}}}},"responses":{"200":{"description":"Withdrawn change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDecisionResult"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"429":{"$ref":"#/components/responses/Error429"}},"operationId":"withdrawChange"}},"/v3/changes/domains":{"get":{"tags":["Changes"],"summary":"List the data domains that changes go through","description":"An allowlisted Toolbox session sees every domain; an API key sees the domains it holds a capability for.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Registered domains","content":{"application/json":{"schema":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ChangeDomainDescriptor"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Error401"}},"operationId":"listChangeDomains"}},"/v3/work-items/{type}/{id}/dismiss":{"post":{"tags":["Changes"],"summary":"Review a work item (\"reviewed, no action\")","description":"The same route for every work list. An allowlisted Toolbox session with CSRF records an applied review. An API key with the domain's `:propose` or `:write` capability records a proposed review, which an admin approves in the Changes inbox; machine actors must send `evidence`. The kind must be one the work list recognizes, or null to stop for now: a null-kind price review lapses like `no-price-source`, a null-kind logo review holds until resumed, a null-kind geo review lapses when the asset is exposed again. A geo review needs `geo:propose` or `geo:write` from a key. `token-category-missing` records `no-category` in `token-tags` and `token-intrinsic-apy-missing` records `no-intrinsic-apy` in `yield-sources`, keyed `<chainId>:<address>`; neither takes a null kind. 409 when a standing review exists, or, for an admin, when another admin's review landed first. A proposed review leaves the item outstanding.\n","x-status":"implemented","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"type","in":"path","required":true,"schema":{"type":"string","enum":["token-logo-missing","token-price-missing","asset-newly-exposed","token-category-missing","token-intrinsic-apy-missing"]}},{"$ref":"#/components/parameters/WorkItemIdPath"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkItemDismissRequest"}}}},"responses":{"201":{"description":"The recorded review","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDecisionResult"}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"429":{"$ref":"#/components/responses/Error429"}},"operationId":"dismissWorkItemOfType"}}}}