Euler Finance Auth API
Authentication and authorization conventions used across the API, including API keys, admin secrets, and rate-limit behavior.
Authentication and authorization conventions used across the API, including API keys, admin secrets, and rate-limit behavior.
openapi: 3.1.0
info:
title: Euler Data API (V3) Accounts Auth API
version: 3.0.0
description: "API specification for Euler Data v3. This spec defines the current\nresource-oriented contract for the platform, with emphasis on consistent\nschemas, predictable REST semantics, caching, observability, and a uniform\ndeveloper experience.\n\nMigration notes\n- Euler Data v3 is not a path-for-path clone of v1/v2. Some endpoints map\n directly, some require multiple v3 calls, and some legacy aggregates were\n intentionally removed.\n- The live [migration guide](/v3/docs/migration) explains how legacy v1/v2\n endpoints and payloads map into the v3 resource model.\n- Important semantic changes:\n - Vault base APY and rewards APY are exposed separately in v3.\n - Account positions are flattened into account-vault rows instead of the\n legacy nested sub-account shape.\n - All supported API paths live under `/v3`; legacy paths return `410`.\n - Summary endpoints prefer smaller, focused resources over large\n BFF-style payloads.\n\nBase path: /v3\n\nConventions\n- JSON field naming: camelCase\n- Addresses: accept lowercase or checksum; responses are EIP-55 checksummed\n- Public APY values (`*Apy`, `apy*`): percent numbers with 6 decimal places (e.g., 5.123456 = 5.123456%)\n- Contract interest-rate fields (`borrowAPY`, `supplyAPY` in `interestRates`): decimal strings in contract fraction units\n- Ratios (utilization, LTV, etc.): numbers with 6 decimal places\n- Response timestamps: ISO-8601 strings (UTC). Some legacy fields still expose unix\n seconds for compatibility and include `*Iso` companions.\n- Query time ranges: unix seconds (from/to)\n\nUnit policy\n- v3 separates market metadata from contract verdicts by both name and type.\n- Market-normalized USD prices and USD values are JSON numbers. These are values\n derived from off-chain pricing, cached price snapshots, or API-level market math.\n This includes `/v3/prices`, token price routes, vault/earn/protocol USD totals,\n portfolio market values, portfolio USD liquidation/risk fields such as\n `liabilityValueUsd`, `totalCollateralValueUsd`, `borrowLiquidationPriceUsd`,\n and `collateralLiquidationPricesUsd`, and vault holder `assetsUsd`.\n- Contract-derived oracle and raw account-liquidity verdict values are exact strings.\n These preserve the integer value used by contracts, normalized to 18 decimals\n for API exposure. Oracle prices are quoted in the vault unit of account, which\n can be USD, ETH, or another asset. This includes `/v3/oracles/prices`, raw\n account-liquidity `liabilityValue` and `totalCollateralValue` objects,\n `liabilityValueBorrowing`, `liabilityValueLiquidation`, and collateral verdict\n values.\n- On-chain token quantities are bigint strings in their native unit scale. This\n includes amounts, balances, shares, assets, borrows, reward amounts, liquidation\n repay/yield amounts, and block numbers.\n- Caps are also bigint strings, but EVK caps are exposed as resolved underlying\n asset-unit amounts rather than packed contract config words.\n- LTV config values use canonical basis-point strings. Legacy decimal aliases\n may remain on config-history payloads for compatibility when explicitly named.\n\nRate limiting\n- Optional API keys for higher limits\n- Default limits are configurable; current defaults: free tier 100 req/min (IP-based)\n and authenticated 1000 req/min (per API key), 60s window.\n- By default, proxy headers are not trusted for IP identity unless explicitly enabled.\n- Redis failures default to fail-closed (503) for strict enforcement; fail-open is opt-in.\n- RateLimit-* (IETF draft-6) and legacy X-RateLimit-* headers are returned.\n\nCORS\n- Public API responses use wildcard CORS, including preflight responses for unsafe methods.\n- Unsafe methods with request bodies must use a JSON media type.\n\nCaching\n- Cache-Control headers are returned for cacheable endpoints.\n- Defaults (may be adjusted in config):\n - Prices: 300s\n - APYs: 600s\n - Rewards: 900s\n - General responses: 60s (short 30s, long 300s)\n\nErrors\n- All errors use a standard envelope: { error: { code, message, requestId, details? } }\n- Domain error codes are documented in this spec.\n- JSON request bodies must use `Content-Type: application/json` or another `application/*+json` media type.\n- Request bodies larger than 1 MiB are rejected before route parsing with `413 PAYLOAD_TOO_LARGE`.\n"
servers:
- url: /
description: Current environment
security: []
tags:
- name: Auth
description: Authentication and authorization conventions used across the API, including API keys, admin secrets, and rate-limit behavior.
paths:
/v3/auth/login:
get:
tags:
- Auth
summary: Start platform-operator Google SSO
description: Redirects the browser to Google OAuth/OIDC and sets a signed OAuth state cookie.
x-status: implemented
responses:
'302':
description: Redirect to configured Google OAuth authorization URL.
headers:
Location:
description: Google authorization URL.
schema:
type: string
format: uri
Set-Cookie:
description: Signed OAuth state cookie with httpOnly, SameSite, path, and expiry.
schema:
type: string
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
operationId: startPlatformAuthLogin
/v3/auth/callback:
get:
tags:
- Auth
summary: Complete platform-operator Google SSO callback
description: Validates state, nonce, Google ID-token claims, and active platform-admin access.
x-status: implemented
parameters:
- name: code
in: query
required: true
schema:
type: string
description: OAuth authorization code. Never returned in responses.
- name: state
in: query
required: true
schema:
type: string
description: OAuth anti-forgery state bound to the signed state cookie.
responses:
'302':
description: Successful callback; session and CSRF cookies are set, then browser is redirected.
headers:
Location:
description: Configured post-login redirect URL.
schema:
type: string
format: uri
Set-Cookie:
description: Signed httpOnly session cookie, readable CSRF cookie, and cleared OAuth state cookie.
schema:
type: string
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
'400':
description: Invalid callback, state, nonce, or ID token.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Google identity is not an active platform admin.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
operationId: completePlatformAuthCallback
/v3/auth/session:
get:
tags:
- Auth
summary: Get current platform-operator session
x-status: implemented
security:
- PlatformSession: []
responses:
'200':
description: Active platform-admin session identity.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
type: object
required:
- data
- meta
properties:
data:
$ref: '#/components/schemas/PlatformAuthSession'
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'
operationId: getPlatformAuthSession
/v3/auth/logout:
post:
tags:
- Auth
summary: End current platform-operator session
x-status: implemented
security:
- PlatformSession: []
PlatformCsrf: []
responses:
'200':
description: Session cookies were cleared.
headers:
Set-Cookie:
description: Expired session and CSRF cookies.
schema:
type: string
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
type: object
required:
- data
- meta
properties:
data:
type: object
required:
- loggedOut
properties:
loggedOut:
type: boolean
meta:
$ref: '#/components/schemas/PaginationMeta'
'401':
description: Invalid signed platform-admin session.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Missing or mismatched CSRF token, or inactive platform-admin access.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
operationId: logoutPlatformAuthSession
/v3/platform-admins:
post:
tags:
- Auth
summary: Grant platform-admin access
description: 'Creates an active platform-admin access row for a Google email address.
Requires a valid platform session and CSRF token because this is an unsafe
cookie-authenticated write.
'
x-status: implemented
security:
- PlatformSession: []
PlatformCsrf: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformAdminAccessRequest'
responses:
'200':
description: Existing revoked platform-admin access was reactivated.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
type: object
required:
- data
- meta
properties:
data:
$ref: '#/components/schemas/PlatformAdminCreateAccessResult'
meta:
$ref: '#/components/schemas/PaginationMeta'
'201':
description: Platform-admin access was 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/PlatformAdminCreateAccessResult'
meta:
$ref: '#/components/schemas/PaginationMeta'
'400':
description: Malformed JSON request body.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'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: Inactive platform-admin access, missing CSRF token, or mismatched CSRF token.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
description: Platform-admin access already exists.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'422':
description: Missing or invalid Google email.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
operationId: createPlatformAdminAccess
/v3/platform-admins/revoke:
post:
tags:
- Auth
summary: Revoke platform-admin access
description: 'Soft-revokes platform-admin access for a Google email address. Requires a
valid platform session and CSRF token because this is an unsafe
cookie-authenticated write.
'
x-status: implemented
security:
- PlatformSession: []
PlatformCsrf: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PlatformAdminAccessRequest'
responses:
'200':
description: Platform-admin access was revoked.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
type: object
required:
- data
- meta
properties:
data:
$ref: '#/components/schemas/PlatformAdminRevokeAccessResult'
meta:
$ref: '#/components/schemas/PaginationMeta'
'400':
description: Malformed JSON request body.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'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: Inactive platform-admin access, missing CSRF token, or mismatched CSRF token.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Platform-admin access was not found.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
description: Platform-admin access was already revoked.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'422':
description: Missing or invalid Google email.
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
operationId: revokePlatformAdminAccess
/v3/toolbox/admin/api-keys:
get:
tags:
- Auth
summary: List API keys for toolbox Admin
description: Lists API key metadata for the toolbox Admin screen. Requires an active platform-admin session and a Google email present in `TOOLBOX_ADMIN_EMAILS`.
x-status: implemented
security:
- PlatformSession: []
responses:
'200':
description: API key metadata visible to toolbox admins.
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/ApiKeyResponse'
meta:
$ref: '#/components/schemas/PaginationMeta'
'401':
$ref: '#/components/responses/Error401'
'403':
$ref: '#/components/responses/Error403'
'500':
$ref: '#/components/responses/Error500'
operationId: getToolboxAdminApiKeys
/v3/admin/api-keys:
post:
tags:
- Auth
summary: Create an API key (admin)
x-status: implemented
security:
- AdminSecret: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ApiKeyCreateRequest'
responses:
'201':
description: API key created
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
type: object
properties:
data:
$ref: '#/components/schemas/ApiKeyCreateResponse'
'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'
'500':
$ref: '#/components/responses/Error500'
operationId: postAdminApiKeys
get:
tags:
- Auth
summary: List API keys (admin)
x-status: implemented
security:
- AdminSecret: []
responses:
'200':
description: API keys
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/ApiKeyResponse'
'401':
$ref: '#/components/responses/Error401'
'403':
$ref: '#/components/responses/Error403'
'500':
$ref: '#/components/responses/Error500'
operationId: getAdminApiKeys
/v3/admin/api-keys/{id}:
get:
tags:
- Auth
summary: Get API key by id (admin)
x-status: implemented
security:
- AdminSecret: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: API key
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
type: object
properties:
data:
$ref: '#/components/schemas/ApiKeyResponse'
'401':
$ref: '#/components/responses/Error401'
'403':
$ref: '#/components/responses/Error403'
'404':
$ref: '#/components/responses/Error404'
'500':
$ref: '#/components/responses/Error500'
operationId: getAdminApiKeysById
patch:
tags:
- Auth
summary: Update API key (admin)
x-status: implemented
security:
- AdminSecret: []
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
rateLimit:
type: integer
isActive:
type: boolean
keyType:
type: string
enum:
- standard
- curator
scopeMode:
type: string
enum:
- all_vaults
- allowlist
vaultAllowlist:
type: array
items:
type: object
required:
- chainId
- vaultAddress
properties:
chainId:
type: integer
vaultAddress:
type: string
responses:
'200':
description: Updated
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
type: object
properties:
data:
type: object
'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'
'500':
$ref: '#/components/responses/Error500'
operationId: patchAdminApiKeysById
delete:
tags:
- Auth
summary: Revoke API key (admin)
x-status: implemented
security:
- AdminSecret: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Revoked
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
type: object
properties:
data:
type: object
'401':
$ref: '#/components/responses/Error401'
'403':
$ref: '#/components/responses/Error403'
'404':
$ref: '#/components/responses/Error404'
'500':
$ref: '#/components/responses/Error500'
operationId: deleteAdminApiKeysById
/v3/admin/api-keys/{id}/usage:
get:
tags:
- Auth
summary: Usage stats for an API key (admin)
x-status: implemented
security:
- AdminSecret: []
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: days
in: query
required: false
schema:
type: integer
responses:
'200':
description: Usage stats
headers:
X-Request-Id:
$ref: '#/components/headers/X-Request-Id'
content:
application/json:
schema:
type: object
properties:
data:
$ref: '#/components/schemas/ApiKeyUsageResponse'
'401':
$ref: '#/components/responses/Error401'
'403':
$ref: '#/components/responses/Error403'
'404':
$ref: '#/components/responses/Error404'
'500':
$ref: '#/components/responses/Error500'
operationId: getAdminApiKeysByIdUsage
components:
schemas:
ApiKeyUsageResponse:
type: object
required:
- period
- summary
- endpoints
properties:
period:
type: object
required:
- days
- since
properties:
days:
type: integer
since:
type: string
format: date-time
summary:
type: object
required:
- totalRequests
- avgResponseTimeMs
- errorCount
properties:
totalRequests:
type: integer
avgResponseTimeMs:
type: integer
errorCount:
type: integer
endpoints:
type: array
items:
type: object
required:
- endpoint
- method
- count
- avgResponseTime
properties:
endpoint:
type: string
method:
type: string
count:
type: integer
avgResponseTime:
type: integer
PlatformAdminAccess:
type: object
required:
- id
- googleEmail
- createdAt
- revokedAt
properties:
id:
type: string
format: uuid
googleEmail:
type: string
format: email
createdAt:
type: string
format: date-time
revokedAt:
type: string
format: date-time
nullable: true
ApiKeyResponse:
type: object
required:
- id
- name
- keyType
- rateLimit
- isActive
- createdAt
properties:
id:
type: string
keyPrefix:
type: string
name:
type: string
ownerEmail:
type: string
nullable: true
keyType:
type: string
enum:
- standard
- curator
scopeMode:
type: string
enum:
- all_vaults
- allowlist
nullable: true
vaultAllowlist:
type: array
items:
type: object
required:
- chainId
- vaultAddress
properties:
chainId:
type: integer
vaultAddress:
type: string
rateLimit:
type: integer
isActive:
type: boolean
createdAt:
type: string
format: date-time
lastUsedAt:
type: string
format: date-time
nullable: true
expiresAt:
type: string
format: date-time
nullable: true
PlatformAdminAccessRequest:
type: object
additionalProperties: false
required:
- googleEmail
properties:
googleEmail:
type: string
format: email
description: Google Workspace email address to grant or revoke.
ErrorResponse:
type: object
required:
- error
properties:
error:
type: object
required:
- code
- message
- requestId
properties:
code:
type: string
description: 'Domain error code. Examples:
- INVALID_ADDRESS
- CHAIN_NOT_SUPPORTED
- VAULT_NOT_FOUND
- TOKEN_NOT_FOUND
- ACCOUNT_NOT_FOUND
- VALIDATION_ERROR
- RATE_LIMIT_EXCEEDED
- UNSUPPORTED_MEDIA_TYPE
- UNAUTHORIZED
- FORBIDDEN
- INTERNAL_ERROR
'
message:
type: string
requestId:
type: string
details:
type: object
additionalProperties: true
ApiKeyCreateRequest:
type: object
required:
- name
properties:
name:
type: string
ownerEmail:
type: string
format: email
keyType:
type: string
enum:
- standard
- curator
default: standard
scopeMode:
type: string
enum:
- all_vaults
- allowlist
vaultAllowlist:
type: array
items:
type: object
required:
- chainId
- vaultAddress
properties:
chainId:
type: integer
vaultAddress:
type: string
rateLimit:
type: integer
expiresInDays:
type: integer
ApiKeyCreateResponse:
type: object
required:
- message
- key
- keyPrefix
- id
- name
- keyType
- rateLimit
properties:
message:
type: string
key:
type: string
keyPrefix:
type: string
id:
type: string
name:
type: string
keyType:
type: string
enum:
- standard
- curator
scopeMode:
type: string
enum:
- all_vaults
- allowlist
nullable: true
vaultAllowlist:
type: array
items:
type: object
required:
- chainId
- vaultAddress
properties:
chainId:
type: integer
vaultAddress:
type: string
rateLimit:
type: integer
expiresAt:
type: string
format: date-time
nullable: true
PlatformAdminCreateAccessResult:
type: object
required:
- admin
- state
properties:
admin:
$ref: '#/components/schemas/PlatformAdminAccess'
state:
type: string
enum:
- created
- reactivated
PlatformAdminRevokeAccessResult:
type: object
required:
- admin
- state
properties:
admin:
$ref: '#/components/schemas/PlatformAdminAccess'
state:
type: string
enum:
- revoked
PlatformAuthSession:
type: object
required:
- platformAdminId
- googleEmail
- googleSubject
- active
- expiresAt
properties:
platformAdminId:
type: string
format: uuid
googleEmail:
type: string
format: email
googleSubject:
type: string
active:
type: boolean
const: true
expiresAt:
type: string
format: date-time
PaginationMeta:
type: object
required:
- timestamp
properties:
total:
type: integer
description: Exact total count when the endpoint provides one.
hasMore:
type: boolean
description: Indicates whether another page exists beyond the current page.
offset:
type: integer
limit:
type: integer
description: Echoed page size after endpoint-side clamping.
timestamp:
type: string
# --- truncated at 32 KB (34 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/euler/refs/heads/main/openapi/euler-auth-api-openapi.yml