{ "openapi": "3.1.0", "info": { "title": "Turtle Earn API — v2", "version": "v2.0.0" }, "paths": { "/v2/chains/": { "get": { "tags": [ "Chains" ], "summary": "Get Supported Chains", "description": "Returns all supported chains with pagination. Chains are filtered to active status only.", "operationId": "GetChains", "parameters": [ { "name": "page", "in": "query", "schema": { "type": "integer" } }, { "name": "limit", "in": "query", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginationPaginatedResponseGithubComTurtleDAOTurtlePartnersGoServicesEarnHandlersV2SharedChainResponse" } } } }, "500": { "description": "Internal Server Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } } } } }, "/v2/opportunities/{chainId}/{vaultAddress}/historical": { "get": { "tags": [ "Historical Data" ], "summary": "Get Vault Historical Data", "description": "Get combined historical time-series (TVL, share price, base APY) for a vault, bucketed by interval over [from, to].", "operationId": "GetOpportunityHistorical", "parameters": [ { "name": "intervalSeconds", "in": "query", "description": "Bucket width in seconds. Defaults to 86400 (1 day)", "schema": { "default": 86400, "description": "Bucket width in seconds. Defaults to 86400 (1 day)", "minimum": 1, "type": "integer" } }, { "name": "fromTimestamp", "in": "query", "description": "Unix seconds, inclusive. Defaults to now - 30d when omitted", "schema": { "description": "Unix seconds, inclusive. Defaults to now - 30d when omitted", "type": "integer" } }, { "name": "toTimestamp", "in": "query", "description": "Unix seconds, inclusive. Defaults to now when omitted", "schema": { "description": "Unix seconds, inclusive. Defaults to now when omitted", "type": "integer" } }, { "name": "chainId", "in": "path", "description": "EVM chain ID (e.g. 1 for Ethereum)", "required": true, "schema": { "description": "EVM chain ID (e.g. 1 for Ethereum)", "minimum": 1, "type": "integer" } }, { "name": "vaultAddress", "in": "path", "description": "0x-prefixed 40-hex vault contract address", "required": true, "schema": { "description": "0x-prefixed 40-hex vault contract address", "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/V2GetOpportunityHistoricalResponse" } } } }, "400": { "description": "Bad Request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } }, "500": { "description": "Internal Server Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } } } } }, "/v2/opportunities/{chainId}/{vaultAddress}/historical/apr": { "get": { "tags": [ "Historical Data" ], "summary": "Get Vault Historical APR", "description": "Adjacent-pair simple-rate (non-compound) APR per bucket over [from, to]. Reward APR is reserved for future rewards indexing and is always 0.", "operationId": "GetOpportunityHistoricalAPR", "parameters": [ { "name": "intervalSeconds", "in": "query", "description": "Bucket width in seconds. Defaults to 86400 (1 day)", "schema": { "default": 86400, "description": "Bucket width in seconds. Defaults to 86400 (1 day)", "minimum": 1, "type": "integer" } }, { "name": "fromTimestamp", "in": "query", "description": "Unix seconds, inclusive. Defaults to now - 30d when omitted", "schema": { "description": "Unix seconds, inclusive. Defaults to now - 30d when omitted", "type": "integer" } }, { "name": "toTimestamp", "in": "query", "description": "Unix seconds, inclusive. Defaults to now when omitted", "schema": { "description": "Unix seconds, inclusive. Defaults to now when omitted", "type": "integer" } }, { "name": "chainId", "in": "path", "description": "EVM chain ID (e.g. 1 for Ethereum)", "required": true, "schema": { "description": "EVM chain ID (e.g. 1 for Ethereum)", "minimum": 1, "type": "integer" } }, { "name": "vaultAddress", "in": "path", "description": "0x-prefixed 40-hex vault contract address", "required": true, "schema": { "description": "0x-prefixed 40-hex vault contract address", "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/V2GetOpportunityHistoricalAPRResponse" } } } }, "400": { "description": "Bad Request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } }, "500": { "description": "Internal Server Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } } } } }, "/v2/opportunities/{chainId}/{vaultAddress}/historical/apy": { "get": { "tags": [ "Historical Data" ], "summary": "Get Vault Historical APY", "description": "Adjacent-pair compound APY per bucket over [from, to]. Reward APY is reserved for future rewards indexing and is always 0.", "operationId": "GetOpportunityHistoricalAPY", "parameters": [ { "name": "intervalSeconds", "in": "query", "description": "Bucket width in seconds. Defaults to 86400 (1 day)", "schema": { "default": 86400, "description": "Bucket width in seconds. Defaults to 86400 (1 day)", "minimum": 1, "type": "integer" } }, { "name": "fromTimestamp", "in": "query", "description": "Unix seconds, inclusive. Defaults to now - 30d when omitted", "schema": { "description": "Unix seconds, inclusive. Defaults to now - 30d when omitted", "type": "integer" } }, { "name": "toTimestamp", "in": "query", "description": "Unix seconds, inclusive. Defaults to now when omitted", "schema": { "description": "Unix seconds, inclusive. Defaults to now when omitted", "type": "integer" } }, { "name": "chainId", "in": "path", "description": "EVM chain ID (e.g. 1 for Ethereum)", "required": true, "schema": { "description": "EVM chain ID (e.g. 1 for Ethereum)", "minimum": 1, "type": "integer" } }, { "name": "vaultAddress", "in": "path", "description": "0x-prefixed 40-hex vault contract address", "required": true, "schema": { "description": "0x-prefixed 40-hex vault contract address", "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/V2GetOpportunityHistoricalAPYResponse" } } } }, "400": { "description": "Bad Request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } }, "500": { "description": "Internal Server Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } } } } }, "/v2/opportunities/{chainId}/{vaultAddress}/historical/share-price": { "get": { "tags": [ "Historical Data" ], "summary": "Get Vault Historical Share Price", "description": "Get historical share-price time-series for a vault, bucketed by interval over [from, to]. Native is denominated in the vault's underlying (base) asset; USD is null when the underlying price is unavailable for the bucket.", "operationId": "GetOpportunityHistoricalSharePrice", "parameters": [ { "name": "intervalSeconds", "in": "query", "description": "Bucket width in seconds. Defaults to 86400 (1 day)", "schema": { "default": 86400, "description": "Bucket width in seconds. Defaults to 86400 (1 day)", "minimum": 1, "type": "integer" } }, { "name": "fromTimestamp", "in": "query", "description": "Unix seconds, inclusive. Defaults to now - 30d when omitted", "schema": { "description": "Unix seconds, inclusive. Defaults to now - 30d when omitted", "type": "integer" } }, { "name": "toTimestamp", "in": "query", "description": "Unix seconds, inclusive. Defaults to now when omitted", "schema": { "description": "Unix seconds, inclusive. Defaults to now when omitted", "type": "integer" } }, { "name": "chainId", "in": "path", "description": "EVM chain ID (e.g. 1 for Ethereum)", "required": true, "schema": { "description": "EVM chain ID (e.g. 1 for Ethereum)", "minimum": 1, "type": "integer" } }, { "name": "vaultAddress", "in": "path", "description": "0x-prefixed 40-hex vault contract address", "required": true, "schema": { "description": "0x-prefixed 40-hex vault contract address", "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/V2GetOpportunityHistoricalSharePriceResponse" } } } }, "400": { "description": "Bad Request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } }, "500": { "description": "Internal Server Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } } } } }, "/v2/opportunities/{chainId}/{vaultAddress}/historical/tvl": { "get": { "tags": [ "Historical Data" ], "summary": "Get Vault Historical TVL", "description": "Get historical TVL time-series for a vault, bucketed by interval over [from, to]. Values are denominated in the vault's underlying (base) asset; USD is null when the underlying price is unavailable for the bucket.", "operationId": "GetOpportunityHistoricalTVL", "parameters": [ { "name": "intervalSeconds", "in": "query", "description": "Bucket width in seconds. Defaults to 86400 (1 day)", "schema": { "default": 86400, "description": "Bucket width in seconds. Defaults to 86400 (1 day)", "minimum": 1, "type": "integer" } }, { "name": "fromTimestamp", "in": "query", "description": "Unix seconds, inclusive. Defaults to now - 30d when omitted", "schema": { "description": "Unix seconds, inclusive. Defaults to now - 30d when omitted", "type": "integer" } }, { "name": "toTimestamp", "in": "query", "description": "Unix seconds, inclusive. Defaults to now when omitted", "schema": { "description": "Unix seconds, inclusive. Defaults to now when omitted", "type": "integer" } }, { "name": "chainId", "in": "path", "description": "EVM chain ID (e.g. 1 for Ethereum)", "required": true, "schema": { "description": "EVM chain ID (e.g. 1 for Ethereum)", "minimum": 1, "type": "integer" } }, { "name": "vaultAddress", "in": "path", "description": "0x-prefixed 40-hex vault contract address", "required": true, "schema": { "description": "0x-prefixed 40-hex vault contract address", "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/V2GetOpportunityHistoricalTVLResponse" } } } }, "400": { "description": "Bad Request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } }, "500": { "description": "Internal Server Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } } } } }, "/v2/protocols/": { "get": { "tags": [ "Protocols" ], "summary": "Get Supported Protocols", "description": "Returns supported DeFi protocols with pagination. A protocol is an organization referenced as a lending protocol or vault infra provider in an earn product.", "operationId": "GetProtocols", "parameters": [ { "name": "page", "in": "query", "schema": { "type": "integer" } }, { "name": "limit", "in": "query", "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginationPaginatedResponseGithubComTurtleDAOTurtlePartnersGoServicesEarnHandlersV2ProtocolResponse" } } } }, "500": { "description": "Internal Server Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } } } } }, "/v2/tokens/": { "get": { "tags": [ "Tokens" ], "summary": "Get Supported Tokens", "description": "Returns active supported tokens with pagination. Optional filters: chainId (numeric) and search (partial match on address, name or symbol).", "operationId": "GetTokens", "parameters": [ { "name": "page", "in": "query", "schema": { "type": "integer" } }, { "name": "limit", "in": "query", "schema": { "type": "integer" } }, { "name": "chainId", "in": "query", "description": "Filter by numeric chain ID", "schema": { "description": "Filter by numeric chain ID", "type": "integer" } }, { "name": "search", "in": "query", "description": "Case-insensitive partial match across address, name and symbol", "schema": { "description": "Case-insensitive partial match across address, name and symbol", "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginationPaginatedResponseGithubComTurtleDAOTurtlePartnersGoServicesEarnHandlersV2SharedTokenResponse" } } } }, "500": { "description": "Internal Server Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } } } } }, "/v2/tokens/{chainId}/{address}": { "get": { "tags": [ "Tokens" ], "summary": "Get Token by Chain and Address", "description": "Returns a single active token identified by its numeric chain ID and contract address.", "operationId": "GetTokenByAddress", "parameters": [ { "name": "chainId", "in": "path", "description": "Numeric chain ID", "required": true, "schema": { "description": "Numeric chain ID", "type": "integer" } }, { "name": "address", "in": "path", "description": "Token contract address (case-insensitive)", "required": true, "schema": { "description": "Token contract address (case-insensitive)", "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SharedTokenResponse" } } } }, "400": { "description": "Bad Request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } }, "404": { "description": "Not Found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } }, "500": { "description": "Internal Server Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestErrResponse" } } } } } } } }, "components": { "schemas": { "PaginationPaginatedResponseGithubComTurtleDAOTurtlePartnersGoServicesEarnHandlersV2ProtocolResponse": { "properties": { "data": { "items": { "$ref": "#/components/schemas/V2ProtocolResponse" }, "type": [ "array", "null" ] }, "pagination": { "$ref": "#/components/schemas/PaginationPaginationMetadata" } }, "type": "object" }, "PaginationPaginatedResponseGithubComTurtleDAOTurtlePartnersGoServicesEarnHandlersV2SharedChainResponse": { "properties": { "data": { "items": { "$ref": "#/components/schemas/SharedChainResponse" }, "type": [ "array", "null" ] }, "pagination": { "$ref": "#/components/schemas/PaginationPaginationMetadata" } }, "type": "object" }, "PaginationPaginatedResponseGithubComTurtleDAOTurtlePartnersGoServicesEarnHandlersV2SharedTokenResponse": { "properties": { "data": { "items": { "$ref": "#/components/schemas/SharedTokenResponse" }, "type": [ "array", "null" ] }, "pagination": { "$ref": "#/components/schemas/PaginationPaginationMetadata" } }, "type": "object" }, "PaginationPaginationMetadata": { "properties": { "limit": { "type": "integer" }, "page": { "type": "integer" }, "total": { "type": "integer" }, "totalPages": { "type": "integer" } }, "type": "object" }, "RestErrResponse": { "properties": { "code": { "description": "Application-specific error code.", "type": "integer" }, "context": { "additionalProperties": {}, "description": "Application context.", "type": "object" }, "error": { "description": "Error message.", "type": "string" }, "status": { "description": "Status text.", "type": "string" } }, "type": "object" }, "SharedChainResponse": { "properties": { "chainId": { "description": "Numeric chain ID (e.g. 1 for Ethereum, 43114 for Avalanche)", "type": "integer" }, "explorerUrl": { "description": "Block explorer base URL", "type": "string" }, "logoUrl": { "description": "Chain logo image URL", "type": "string" }, "name": { "description": "Chain full name", "type": "string" } }, "type": "object" }, "SharedTokenResponse": { "properties": { "address": { "description": "Token contract address", "type": "string" }, "chainId": { "description": "Numeric chain ID the token belongs to", "type": "integer" }, "decimals": { "description": "ERC20 decimals", "type": "integer" }, "logoUrl": { "description": "Token logo image URL", "type": "string" }, "symbol": { "description": "Token symbol (e.g. USDC, ETH)", "type": "string" } }, "type": "object" }, "V2APRBreakdown": { "properties": { "base": { "description": "APR from share-price growth alone (simple, non-compound)", "type": "number" }, "reward": { "description": "Reward APR; reserved for future rewards indexing, currently always 0", "type": "number" }, "total": { "description": "base + reward", "type": "number" } }, "type": "object" }, "V2APYBreakdown": { "properties": { "base": { "description": "APY from share-price growth alone (vaults.fyi compound formula)", "type": "number" }, "reward": { "description": "Reward APY; reserved for future rewards indexing, currently always 0", "type": "number" }, "total": { "description": "base + reward", "type": "number" } }, "type": [ "object", "null" ] }, "V2GetOpportunityHistoricalAPRResponse": { "properties": { "data": { "items": { "$ref": "#/components/schemas/V2HistoricalAPRPoint" }, "type": [ "array", "null" ] } }, "type": "object" }, "V2GetOpportunityHistoricalAPYResponse": { "properties": { "data": { "items": { "$ref": "#/components/schemas/V2HistoricalAPYPoint" }, "type": [ "array", "null" ] } }, "type": "object" }, "V2GetOpportunityHistoricalResponse": { "properties": { "baseAsset": { "$ref": "#/components/schemas/SharedTokenResponse", "description": "null when the vault has not yet been indexed in vault_metrics or the underlying token is not registered in supported_tokens" }, "data": { "items": { "$ref": "#/components/schemas/V2HistoricalCombinedPoint" }, "type": [ "array", "null" ] }, "historyTruncated": { "description": "true when backend hit the row cap and oldest APY values may be missing predecessors", "type": "boolean" } }, "type": "object" }, "V2GetOpportunityHistoricalSharePriceResponse": { "properties": { "baseAsset": { "$ref": "#/components/schemas/SharedTokenResponse", "description": "null when the vault has not yet been indexed in vault_metrics or the underlying token is not registered in supported_tokens" }, "data": { "items": { "$ref": "#/components/schemas/V2HistoricalSharePricePoint" }, "type": [ "array", "null" ] } }, "type": "object" }, "V2GetOpportunityHistoricalTVLResponse": { "properties": { "baseAsset": { "$ref": "#/components/schemas/SharedTokenResponse", "description": "null when the vault has not yet been indexed in vault_metrics or the underlying token is not registered in supported_tokens" }, "data": { "items": { "$ref": "#/components/schemas/V2HistoricalTVLPoint" }, "type": [ "array", "null" ] } }, "type": "object" }, "V2HistoricalAPRPoint": { "properties": { "apr": { "$ref": "#/components/schemas/V2APRBreakdown", "description": "Adjacent-pair simple-rate APR against the previous bucket" }, "blockNumber": { "description": "On-chain block number of the snapshot chosen as the bucket representative", "minimum": 0, "type": "integer" }, "timestamp": { "description": "Bucket representative time (unix seconds)", "type": "integer" } }, "type": "object" }, "V2HistoricalAPYPoint": { "properties": { "apy": { "$ref": "#/components/schemas/V2APYBreakdown", "description": "Adjacent-pair compound APY against the previous bucket" }, "blockNumber": { "description": "On-chain block number of the snapshot chosen as the bucket representative", "minimum": 0, "type": "integer" }, "timestamp": { "description": "Bucket representative time (unix seconds)", "type": "integer" } }, "type": "object" }, "V2HistoricalCombinedPoint": { "properties": { "apy": { "$ref": "#/components/schemas/V2APYBreakdown", "description": "Trailing-window APY at this bucket; null when no predecessor exists" }, "blockNumber": { "description": "On-chain block number of the snapshot chosen as the bucket representative", "minimum": 0, "type": "integer" }, "sharePrice": { "$ref": "#/components/schemas/V2NativeUSDValue" }, "timestamp": { "description": "Bucket representative time (unix seconds)", "type": "integer" }, "tvl": { "$ref": "#/components/schemas/V2NativeUSDValue" } }, "type": "object" }, "V2HistoricalSharePricePoint": { "properties": { "blockNumber": { "description": "On-chain block number of the snapshot chosen as the bucket representative", "minimum": 0, "type": "integer" }, "sharePrice": { "$ref": "#/components/schemas/V2NativeUSDValue" }, "timestamp": { "description": "Bucket representative time (unix seconds)", "type": "integer" } }, "type": "object" }, "V2HistoricalTVLPoint": { "properties": { "blockNumber": { "description": "On-chain block number of the snapshot chosen as the bucket representative", "minimum": 0, "type": "integer" }, "timestamp": { "description": "Bucket representative time (unix seconds)", "type": "integer" }, "tvl": { "$ref": "#/components/schemas/V2NativeUSDValue" } }, "type": "object" }, "V2NativeUSDValue": { "properties": { "native": { "type": "number" }, "usd": { "description": "null when underlying USD price was not available for this bucket", "type": [ "null", "number" ] } }, "type": "object" }, "V2ProtocolResponse": { "properties": { "logoUrl": { "description": "Protocol logo image URL", "type": "string" }, "name": { "description": "Protocol name", "type": "string" }, "siteUrl": { "description": "Protocol website URL", "type": "string" } }, "type": "object" } } } }