{"openapi":"3.0.0","info":{"title":"Spectra SDK API","version":"1.0.0","description":"Public API documentation for Spectra Protocol SDK"},"servers":[{"url":"https://api.spectra.finance","description":"Production"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Enter your bearer token"}},"schemas":{"TransactionDescribeInput":{"type":"object","additionalProperties":false,"required":["requestId","chainId","to","data","operation","value"],"properties":{"requestId":{"type":"string","minLength":1,"maxLength":128},"chainId":{"type":"integer","enum":[1,10,14,56,143,146,999,1329,8453,42161,43111,43114,747474]},"to":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"data":{"type":"string","pattern":"^0x(?:[0-9a-fA-F]{2})*$","description":"At most 262144 decoded bytes per transaction."},"operation":{"type":"integer","enum":[0,1]},"value":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"},"safeAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","description":"Context only; never part of canonical decode identity."}}},"TransactionDescribeBatchRequest":{"type":"object","additionalProperties":false,"required":["transactions"],"properties":{"transactions":{"type":"array","minItems":1,"maxItems":50,"description":"Ordered batch; total decoded calldata is limited to 1048576 bytes.","items":{"$ref":"#/components/schemas/TransactionDescribeInput"}}}},"TransactionDescribeRaw":{"type":"object","required":["chainId","target","calldata","operation","value"],"properties":{"chainId":{"type":"integer"},"target":{"type":"string","nullable":true},"calldata":{"type":"string"},"operation":{"type":"integer","enum":[0,1],"nullable":true},"value":{"type":"string","nullable":true}}},"TransactionDescribeNode":{"type":"object","required":["status","raw","targetVerified","provenance","cacheHit","observedAt","freshness","implementationEvidence","warnings"],"properties":{"status":{"type":"string","enum":["decoded","partial","unknown","malformed"]},"raw":{"$ref":"#/components/schemas/TransactionDescribeRaw"},"function":{"type":"object","additionalProperties":true},"children":{"type":"array","items":{"$ref":"#/components/schemas/TransactionDescribeNode"}},"targetVerified":{"type":"boolean"},"provenance":{"type":"string","enum":["repository-selector","repository-abi","unknown"]},"cacheHit":{"type":"boolean"},"observedAt":{"type":"string","format":"date-time"},"freshness":{"type":"object","additionalProperties":true},"implementationEvidence":{"nullable":true},"warnings":{"type":"array","items":{"type":"string"}}}},"TransactionDescribeBatchResponse":{"type":"object","required":["decoderVersion","results"],"properties":{"decoderVersion":{"type":"string"},"results":{"type":"array","description":"One isolated result per input, in input order.","items":{"allOf":[{"$ref":"#/components/schemas/TransactionDescribeNode"},{"type":"object","required":["requestId"],"properties":{"requestId":{"type":"string"},"context":{"type":"object","additionalProperties":true}}}]}}}},"AddressCatalogManagedSafeRole":{"type":"string","enum":["dao","metavault","accountant","poolManager"]},"AddressCatalogManagedSafeProvenance":{"type":"object","required":["kind"],"additionalProperties":false,"properties":{"kind":{"type":"string","enum":["daoConfig","metavaultDeployment","metavaultRegistry","accountantConfig","poolManagerConfig"]}}},"AddressCatalogManagedSafeContext":{"type":"object","required":["kind","isProduction","projectId","projectName","type"],"additionalProperties":false,"properties":{"kind":{"type":"string","enum":["metavault"]},"isProduction":{"type":"boolean"},"name":{"type":"string"},"projectId":{"type":"string","description":"Stable MetaVault cluster identifier shared by the main and every remote."},"projectName":{"type":"string","description":"Canonical project display name inherited from the MetaVault main."},"type":{"type":"string"}}},"AddressCatalogManagedSafe":{"type":"object","required":["address","chainId","roles","provenance","contexts","resolvedAt"],"additionalProperties":false,"properties":{"address":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"chainId":{"type":"integer","minimum":1},"roles":{"type":"array","minItems":1,"uniqueItems":true,"items":{"$ref":"#/components/schemas/AddressCatalogManagedSafeRole"}},"provenance":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/AddressCatalogManagedSafeProvenance"}},"contexts":{"type":"array","items":{"$ref":"#/components/schemas/AddressCatalogManagedSafeContext"}},"resolvedAt":{"type":"integer","minimum":1,"description":"Timestamp at which the dynamic RegistryV2/subgraph catalog was projected."}}},"AddressCatalogManagedSafeResponse":{"type":"object","required":["safes","count","complete","degradedChains"],"additionalProperties":false,"properties":{"safes":{"type":"array","items":{"$ref":"#/components/schemas/AddressCatalogManagedSafe"}},"count":{"type":"integer","minimum":0},"complete":{"type":"boolean","description":"False when one or more chain catalogs could not be refreshed; available chains remain present."},"degradedChains":{"type":"array","items":{"type":"integer","minimum":1}}}},"AddressCatalogRecord":{"type":"object","required":["key","address","chainId","source","resolvedAt"],"properties":{"key":{"type":"string","description":"Canonical dot-notation catalog key.","example":"core.registryV2.8453"},"address":{"type":"string","nullable":true,"description":"Checksummed EVM address, or null for a value-bearing record.","pattern":"^0x[0-9a-fA-F]{40}$"},"value":{"type":"string","description":"Non-address value. Present only on value-bearing records."},"valueType":{"type":"string","enum":["address","string","uint256","bytes32","bool","bytes"],"description":"Canonical Registry V2 semantic type. Present only on registry records."},"poolIdentity":{"type":"object","description":"Canonical pool-domain identity. Present only on pool-oracle records.","required":["poolAddress","ptAddress","ibtAddress"],"additionalProperties":false,"properties":{"poolAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"ptAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"ibtAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}}},"chainId":{"type":"integer","minimum":1,"example":8453},"source":{"type":"string","enum":["static","rpc","subgraph"]},"resolvedAt":{"type":"integer","format":"int64","minimum":1,"description":"Unix time in milliseconds assigned when resolution starts. Static records use module evaluation time. This is not a live provider freshness guarantee."}}},"AddressCatalogResolverError":{"type":"object","description":"Closed, free-text-free description of one failed resolver leg.","required":["resolver","chainId","code"],"additionalProperties":false,"properties":{"resolver":{"type":"string","enum":["coreV2","metavaultsGlobals","poolOracles","vaultAddresses"]},"chainId":{"type":"integer","minimum":1},"code":{"type":"string","enum":["RPC_DOWN","SUBGRAPH_DEGRADED"]}}},"AddressCatalogPoolRelationship":{"type":"object","required":["poolAddress","ptAddress","ibtAddress","rateOracle"],"properties":{"poolAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"ptAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"ibtAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"rateOracle":{"oneOf":[{"type":"object","required":["status","address"],"properties":{"status":{"type":"string","enum":["resolved"]},"address":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}}},{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["absent","unavailable"]}}}]}}},"AddressCatalogPoolRelationshipResponse":{"type":"object","required":["pools","count"],"properties":{"pools":{"type":"array","items":{"$ref":"#/components/schemas/AddressCatalogPoolRelationship"}},"count":{"type":"integer","minimum":0},"errors":{"type":"array","items":{"$ref":"#/components/schemas/AddressCatalogResolverError"}}}},"AddressCatalogTypedRegistryRelationship":{"type":"object","required":["name","domain","description","optional","source","resolvedAt","value"],"additionalProperties":false,"properties":{"name":{"type":"string"},"domain":{"type":"string","enum":["core","metadata","pipeline","remote","settlement","fees"]},"description":{"type":"string"},"optional":{"type":"boolean"},"source":{"type":"string","enum":["static","rpc","subgraph"]},"resolvedAt":{"type":"integer","format":"int64"},"value":{"oneOf":[{"type":"object","required":["valueType","address"],"additionalProperties":false,"properties":{"valueType":{"type":"string","enum":["address"]},"address":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}}},{"type":"object","required":["valueType","value"],"additionalProperties":false,"properties":{"valueType":{"type":"string","enum":["string","uint256","bytes32","bool","bytes"]},"value":{"type":"string"}}}]}}},"AddressCatalogStaticContractRelationship":{"type":"object","required":["contractName","exportName","address","source","resolvedAt"],"additionalProperties":false,"properties":{"contractName":{"type":"string"},"exportName":{"type":"string"},"address":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"},"source":{"type":"string","enum":["static"]},"resolvedAt":{"type":"integer","format":"int64"}}},"AddressCatalogMetaVaultGlobalEntity":{"type":"object","required":["kind","identity","registryV2","relationships"],"additionalProperties":false,"properties":{"kind":{"type":"string","enum":["metavault-global"]},"identity":{"type":"object","required":["chainId"],"additionalProperties":false,"properties":{"chainId":{"type":"integer","minimum":1}}},"registryV2":{"oneOf":[{"type":"object","required":["status","address"],"additionalProperties":false,"properties":{"status":{"type":"string","enum":["resolved"]},"address":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}}},{"type":"object","required":["status"],"additionalProperties":false,"properties":{"status":{"type":"string","enum":["absent"]}}}]},"relationships":{"type":"object","required":["registry","staticContracts"],"additionalProperties":false,"properties":{"registry":{"type":"array","items":{"$ref":"#/components/schemas/AddressCatalogTypedRegistryRelationship"}},"staticContracts":{"type":"array","items":{"$ref":"#/components/schemas/AddressCatalogStaticContractRelationship"}}}}}},"AddressCatalogEntity":{"oneOf":[{"type":"object","required":["kind","identity","relationships"],"additionalProperties":false,"properties":{"kind":{"type":"string","enum":["pool"]},"identity":{"type":"object","required":["chainId","poolAddress"],"additionalProperties":false,"properties":{"chainId":{"type":"integer","minimum":1},"poolAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}}},"relationships":{"type":"object","required":["pt","ibt","rateOracle"],"additionalProperties":false,"properties":{"pt":{"type":"object","required":["address"],"additionalProperties":false,"properties":{"address":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}}},"ibt":{"type":"object","required":["address"],"additionalProperties":false,"properties":{"address":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}}},"rateOracle":{"oneOf":[{"type":"object","required":["status","address"],"additionalProperties":false,"properties":{"status":{"type":"string","enum":["resolved"]},"address":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}}},{"type":"object","required":["status"],"additionalProperties":false,"properties":{"status":{"type":"string","enum":["absent","unavailable"]}}}]}}}}},{"$ref":"#/components/schemas/AddressCatalogMetaVaultGlobalEntity"},{"type":"object","required":["kind","identity","relationships"],"additionalProperties":false,"properties":{"kind":{"type":"string","enum":["metavault-vault"]},"identity":{"type":"object","required":["chainId","safeAddress"],"additionalProperties":false,"properties":{"chainId":{"type":"integer","minimum":1},"safeAddress":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}}},"relationships":{"type":"object","required":["registry","global"],"additionalProperties":false,"properties":{"registry":{"type":"array","items":{"$ref":"#/components/schemas/AddressCatalogTypedRegistryRelationship"}},"global":{"$ref":"#/components/schemas/AddressCatalogMetaVaultGlobalEntity"}}}}}]},"AddressCatalogEntityResponse":{"oneOf":[{"type":"object","required":["entities","count","cardinality","completeness"],"additionalProperties":false,"properties":{"entities":{"type":"array","maxItems":0},"count":{"type":"integer","enum":[0]},"cardinality":{"type":"string","enum":["none"]},"completeness":{"type":"string","enum":["complete"]}}},{"type":"object","required":["entities","count","cardinality","completeness"],"additionalProperties":false,"properties":{"entities":{"type":"array","minItems":1,"maxItems":1,"items":{"$ref":"#/components/schemas/AddressCatalogEntity"}},"count":{"type":"integer","enum":[1]},"cardinality":{"type":"string","enum":["one"]},"completeness":{"type":"string","enum":["complete"]}}},{"type":"object","required":["entities","count","cardinality","completeness"],"additionalProperties":false,"properties":{"entities":{"type":"array","minItems":2,"items":{"$ref":"#/components/schemas/AddressCatalogEntity"}},"count":{"type":"integer","minimum":2},"cardinality":{"type":"string","enum":["many"]},"completeness":{"type":"string","enum":["complete"]}}},{"type":"object","required":["entities","count","cardinality","completeness","errors"],"additionalProperties":false,"properties":{"entities":{"type":"array","minItems":1,"maxItems":1,"items":{"$ref":"#/components/schemas/AddressCatalogEntity"}},"count":{"type":"integer","enum":[1]},"cardinality":{"type":"string","enum":["one"]},"completeness":{"type":"string","enum":["degraded"]},"errors":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/AddressCatalogResolverError"}}}},{"type":"object","required":["entities","count","cardinality","completeness","errors"],"additionalProperties":false,"properties":{"entities":{"type":"array","minItems":2,"items":{"$ref":"#/components/schemas/AddressCatalogEntity"}},"count":{"type":"integer","minimum":2},"cardinality":{"type":"string","enum":["many"]},"completeness":{"type":"string","enum":["degraded"]},"errors":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/AddressCatalogResolverError"}}}},{"type":"object","required":["entities","count","cardinality","completeness","errors"],"additionalProperties":false,"properties":{"entities":{"type":"array","maxItems":0},"count":{"type":"integer","enum":[0]},"cardinality":{"type":"string","enum":["unknown"]},"completeness":{"type":"string","enum":["degraded"]},"errors":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/AddressCatalogResolverError"}}}}]},"AddressCatalogListResponse":{"type":"object","required":["addresses","count"],"properties":{"addresses":{"type":"array","items":{"$ref":"#/components/schemas/AddressCatalogRecord"}},"count":{"type":"integer","minimum":0},"errors":{"type":"array","description":"Omitted when every resolver leg answered. Presence means the result is partial.","items":{"$ref":"#/components/schemas/AddressCatalogResolverError"}}}},"AddressCatalogExactResponse":{"type":"object","required":["address"],"properties":{"address":{"type":"object","nullable":true,"allOf":[{"$ref":"#/components/schemas/AddressCatalogRecord"}],"description":"Full catalog record, or null when the well-formed key does not exist."}}},"AddressCatalogChainsResponse":{"type":"object","required":["chains"],"properties":{"chains":{"type":"array","description":"Chain IDs with at least one Spectra deployment; not every namespace is available on every chain.","items":{"type":"integer","minimum":1}}}},"AddressCatalogApiError":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","retryable"],"properties":{"code":{"type":"string","enum":["INVALID_REQUEST","INTERNAL_ERROR"]},"message":{"type":"string"},"retryable":{"type":"boolean"},"details":{"type":"object","additionalProperties":true}}}}}}},"security":[{"bearerAuth":[]}],"paths":{"/api-docs":{"get":{"summary":"Get OpenAPI specification","description":"Returns the OpenAPI specification for the API. Internal routes are only shown when authenticated.","tags":["Documentation"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"header","name":"Authorization","required":false,"schema":{"type":"string"},"description":"Bearer token for accessing internal routes (optional)","example":"Bearer your_token_here"}],"responses":{"200":{"description":"OpenAPI specification","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/health":{"get":{"summary":"Liveness check","description":"Confirms the API process is up. Touches no database or cache.\nFor data freshness use `/v2/status`.\n","tags":["Health"],"responses":{"200":{"description":"Service is up","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"healthy"},"service":{"type":"string","example":"spectra-sdk"},"version":{"type":"string","description":"Short git commit of the deployed API","example":"abc1234"},"timestamp":{"type":"string","format":"date-time"},"uptime":{"type":"number","example":12345.67}}}}}}}}},"/v1/{network}/limit-orders/cancel/advance-nonce":{"post":{"summary":"Build a cancel-all transaction","description":"Returns calldata advancing the sender's order epoch on series 0 (increaseEpoch / advanceEpoch), which cancels every order they signed under an older epoch. The maker must sign and send it.\n","tags":["Limit Orders"],"parameters":[{"name":"network","in":"path","required":true,"schema":{"type":"string","example":"base"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"integer","minimum":1,"maximum":255,"default":1,"description":"How many epochs to advance"}}}}}},"responses":{"200":{"description":"Transaction to send from the maker (to, data, value)"},"400":{"description":"Invalid request or chain without a deployment"},"500":{"description":"Server error"}}}},"/v1/{network}/limit-orders/cancel/batch":{"post":{"summary":"Build a cancel transaction for several orders","description":"Returns calldata for the settlement's cancelOrders(makerTraits[], orderHashes[]). The maker must sign and send it; every order must belong to that maker.\n","tags":["Limit Orders"],"parameters":[{"name":"network","in":"path","required":true,"schema":{"type":"string","example":"base"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orders"],"properties":{"orders":{"type":"array","maxItems":20,"items":{"type":"object","description":"A signed order as served by GET /orders or /generate-order-data"}}}}}}},"responses":{"200":{"description":"Transaction to send from the maker (to, data, value)"},"400":{"description":"Invalid request or chain without a deployment"},"500":{"description":"Server error"}}}},"/v1/{network}/limit-orders/cancel/single":{"post":{"summary":"Build a cancel transaction for one order","description":"Returns calldata for the settlement's cancelOrder(makerTraits, orderHash). The maker must sign and send it; only the maker can cancel their order.\n","tags":["Limit Orders"],"parameters":[{"name":"network","in":"path","required":true,"schema":{"type":"string","example":"base"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["order"],"properties":{"order":{"type":"object","description":"The signed order as served by GET /orders or /generate-order-data"}}}}}},"responses":{"200":{"description":"Transaction to send from the maker (to, data, value)"},"400":{"description":"Invalid request or chain without a deployment"},"500":{"description":"Server error"}}}},"/v1/{network}/limit-orders/create":{"post":{"summary":"Create a new limit order","description":"Validates a signed 1inch limit order (or a Safe order pre-signed through ERC-1271) and stores it in the book","tags":["Limit Orders"],"parameters":[{"name":"network","in":"path","required":true,"description":"The network to create the order on (ethereum, base, arbitrum, etc.)","schema":{"type":"string","example":"base"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["order"],"properties":{"order":{"type":"object","description":"The order exactly as returned by POST /generate-order-data: the signed 1inch fields (salt, maker, receiver, makerAsset, takerAsset, makingAmount, takingAmount, makerTraits), its extension, and the indexed terms (orderType, makerTokenType, pt, impliedRate, expiry, nonce). Uints are decimal strings. The terms must match the signed bytes.\n"},"signature":{"type":"string","description":"EIP-712 signature of the order. Omit (or send \"0x\") for a pre-signed order — a MetaVault Safe that approved the order hash through ERC-1271 (SpectraLimitOrderSigner). The approval is then verified on-chain instead.\n","example":"0x1234567890abcdef...1b"},"curvePoolAddress":{"type":"string","description":"Optional Curve pool of the order's market. Enables the AMM half of the marketable-order guard (the book half always runs).\n"},"allowCrossing":{"type":"boolean","description":"Rest the order even when it would immediately match resting liquidity (it will be arbitraged). Default false — a marketable order is rejected with 409 ORDER_WOULD_IMMEDIATELY_MATCH and the bestOpposingRate it crossed.\n"}}}}}},"responses":{"200":{"description":"Order created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"orderHash":{"type":"string","description":"The unique hash of the created order","example":"0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd"}}}}}},"400":{"description":"Invalid request or validation failed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"order.makingAmount: Must be an integer string"}}}}}},"409":{"description":"The order would immediately match resting liquidity (marketable). Body carries code ORDER_WOULD_IMMEDIATELY_MATCH and bestOpposingRate (WAD) — fill instead, or resubmit with allowCrossing true to rest anyway.\n"},"500":{"description":"Server error"}}}},"/v1/{network}/limit-orders/generate-order-data":{"post":{"summary":"Generate order data ready for EIP-712 signing","description":"Builds the 1inch limit order a maker signs: the maker's current epoch as nonce, a random salt bound to the fee-order extension, the APY as an 18-decimal WAD, and the rate getter's live taking amount as the signed baseline. Sign `orderData.order` with EIP-712 under `orderData.domain` (\"1inch Limit Order Protocol\" v4) and submit it to POST /create.\n","tags":["Limit Orders"],"parameters":[{"name":"network","in":"path","required":true,"description":"Chain ID or network name (e.g. \"8453\" for Base)","schema":{"type":"string","example":"8453"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pt","maker","orderType","makingAmount","impliedApy","expiry"],"properties":{"pt":{"type":"string","description":"Principal Token address","example":"0x1234567890123456789012345678901234567890"},"maker":{"type":"string","description":"Maker wallet address","example":"0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"},"makerTokenType":{"type":"number","description":"Quote token: 0=IBT (default), 1=VAULT_SHARE, 2=UNDERLYING. VAULT_SHARE needs a wrapped IBT market, otherwise 400 UNSUPPORTED_MAKER_TOKEN.","enum":[0,1,2]},"orderType":{"type":"number","description":"Order type: 1=IBT_FOR_PT, 2=PT_FOR_IBT, 3=IBT_FOR_YT, 4=YT_FOR_IBT","enum":[1,2,3,4],"example":1},"makingAmount":{"type":"string","description":"Amount the maker is offering (in token wei)","example":"1000000000000000000"},"impliedApy":{"type":"number","description":"Target implied APY as a decimal (e.g. 0.05 for 5%, 0.10 for 10%)","example":0.05},"expiry":{"type":"string","description":"Order expiration as a Unix timestamp (seconds)","example":"1735689600"}}},"examples":{"buyPT":{"summary":"Buy PT with IBT at 5% implied APY","value":{"pt":"0x1234567890123456789012345678901234567890","maker":"0xabcdefabcdefabcdefabcdefabcdefabcdefabcd","orderType":1,"makingAmount":"1000000000000000000","impliedApy":0.05,"expiry":"1735689600"}}}}}},"responses":{"200":{"description":"Order data ready for EIP-712 signing","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"orderData":{"type":"object","properties":{"order":{"type":"object","description":"Signed 1inch fields (salt, maker, receiver, makerAsset, takerAsset, makingAmount, takingAmount, makerTraits) plus extension and the indexed terms (orderType, makerTokenType, pt, impliedRate, expiry, nonce). Uints are decimal strings. Pass it to POST /create.\n"},"orderHash":{"type":"string","description":"EIP-712 hash, equal to the settlement's hashOrder(order)"},"domain":{"type":"object","description":"EIP-712 domain to sign under"}}}}}}}},"400":{"description":"Invalid request, or a vault-share quote on a market without a wrapper"},"500":{"description":"Server error"}}}},"/v1/{network}/limit-orders/orders":{"get":{"summary":"Get limit orders","description":"Retrieve limit orders with filtering and pagination options. Supports cross-market queries.","tags":["Limit Orders"],"parameters":[{"name":"network","in":"path","required":true,"description":"The network to query orders from","schema":{"type":"string","example":"base"}},{"name":"market","in":"query","required":false,"description":"Filter by PT address (optional, omit for cross-market queries)","schema":{"type":"string","example":"0x1234567890123456789012345678901234567890"}},{"name":"makerAddress","in":"query","description":"Filter by maker address","schema":{"type":"string","example":"0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"}},{"name":"orderTypes","in":"query","description":"Filter by order types (comma-separated, 1=IBT_FOR_PT, 2=PT_FOR_IBT, 3=IBT_FOR_YT, 4=YT_FOR_IBT)","schema":{"type":"string","example":"1,2"}},{"name":"orderStatus","in":"query","description":"Filter by order statuses (comma-separated, open, cancelled, filled, partially_filled, expired)","schema":{"type":"string","example":"open,partially_filled"}},{"name":"limit","in":"query","description":"Maximum number of orders to return","schema":{"type":"integer","default":100,"maximum":1000}},{"name":"offset","in":"query","description":"Number of orders to skip (for pagination)","schema":{"type":"integer","default":0,"maximum":9000}}],"responses":{"200":{"description":"Orders retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"orders":{"type":"array","items":{"type":"object","properties":{"orderHash":{"type":"string"},"chainId":{"type":"number"},"ptAddress":{"type":"string"},"makerAddress":{"type":"string"},"receiverAddress":{"type":"string"},"orderType":{"type":"number"},"orderStatus":{"type":"string"},"makingAmount":{"type":"string"},"filledAmount":{"type":"string"},"impliedRate":{"type":"string"},"nonce":{"type":"string"},"makerBalance":{"type":"string","nullable":true,"description":"Validator-observed spendable balance (min(balance, allowance)); null if never read"},"orderBookBalance":{"type":"string","description":"Greedy allocation of the maker's spendable balance across their live orders (duplicates show once)"},"invalidReason":{"type":"string","nullable":true,"description":"Why the row is flagged invalid; populated for maker-scoped reads only"}}}}}}}}},"400":{"description":"Invalid request parameters"},"500":{"description":"Server error"}}}},"/v1/{network}/limit-orders/quote":{"post":{"summary":"Quote optimal trade routing","description":"Computes the optimal split of a trade between the Curve AMM and the on-chain limit-order book to maximise execution price.  Returns the AMM/book allocation, weighted-average implied rate, and an ordered fill plan that can be passed directly to the LimitOrderEngine contract.\n","tags":["Limit Orders"],"parameters":[{"name":"network","in":"path","required":true,"description":"Chain ID or network name (e.g. \"8453\" for Base)","schema":{"type":"string","example":"8453"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pt","orderType","inputAmount"],"properties":{"pt":{"type":"string","description":"Principal token of the market","example":"0x1234567890123456789012345678901234567890"},"curvePoolAddress":{"type":"string","description":"Optional Curve StableSwap pool of the market (PT is coins[1]). Without it, or when the market's pool is switched off or empty, the quote is book-only.\n","example":"0x1234567890123456789012345678901234567890"},"orderType":{"type":"integer","description":"Order type: 1 = IBT_FOR_PT (buy PT with IBT), 2 = PT_FOR_IBT (sell PT for IBT), 3 = IBT_FOR_YT (buy YT with IBT), 4 = YT_FOR_IBT (sell YT for IBT)\n","enum":[1,2,3,4],"example":1},"inputAmount":{"type":"string","description":"Amount of the making token to trade, as a decimal string (wei)","example":"1000000000000000000"},"impliedRateFee":{"type":"string","description":"Optional protocol fee override in 18-decimal WAD (e.g. \"10000000000000000\" for 1%). Defaults to the fee taker's live fee(). Fill recipe — for every fill, deltas of adjacent points give per-order amounts: maxTaking ← Δ cumulativeMakerTakingWithFees (maker taking token, fee + 30s-drift inclusive); taker input / tokeniser input ← Δ cumulativeTakingAmountWithFees (taker input token).\n","example":"10000000000000000"},"optimizationTolerance":{"type":"number","description":"Optional optimizer convergence tolerance","example":0.000001},"maxIterations":{"type":"integer","description":"Optional optimizer iteration cap","example":100},"limitImpliedRate":{"type":"string","description":"Optional marketable-limit bound (18-decimal WAD implied rate). When set, the walk only consumes book orders and AMM depth whose fee-adjusted rate is at-or-better than this limit (equality fills), and the response gains a `limit` block splitting the input into what can execute now and what should rest as a maker order.\n","example":"20000000000000000"},"taker":{"type":"string","description":"Optional taker address. That maker's own resting orders are excluded from the walk (self-trade prevention).\n"},"fillRecipient":{"type":"string","description":"Optional caller of the batch fill (the Spectra router when routed). When set, the response gains `batch`: the book leg as one SpectraLimitOrderBatchFiller.fillMany payload, with commandInput ready for router command FILL_1INCH_LIMIT_ORDERS (0x27). Tokeniser surplus goes to this address.\n"}}}}}},"responses":{"200":{"description":"Quote computed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"routing":{"type":"object","properties":{"alpha":{"type":"string","description":"Fraction of the trade routed through the AMM [0,1]","example":"0.6"},"ammAmount":{"type":"string","description":"Amount routed through the AMM (wei)","example":"600000000000000000"},"bookAmount":{"type":"string","description":"Amount routed through the order book (wei)","example":"400000000000000000"},"totalAmount":{"type":"string","description":"Executable input, fee-free (wei) — ammAmount + bookAmount","example":"1000000000000000000"},"remainderAmount":{"type":"string","description":"Requested input that cannot execute (wei): beyond the limit bound, or beyond the book on a book-only quote. Rest it as a maker order.\n","example":"0"},"bookAmountWithFees":{"type":"string","description":"Book-leg input INCLUDING the protocol fee (sum of every fill group's final cumulativeTakingAmountWithFees). Equals bookAmount when the fee is zero.\n","example":"404000000000000000"},"totalAmountWithFees":{"type":"string","description":"Total input the taker must actually send to avoid an InsufficientFunds revert: ammAmount + bookAmountWithFees. The Curve AMM fee is already inside ammAmount (it reduces output, not input), so only the book-leg fee is added.\n","example":"1004000000000000000"},"expectedOutput":{"type":"string","description":"What the taker receives at the quote price, AMM and book legs (wei). Set ASSERT_MIN_BALANCE from it, less your slippage tolerance.\n","example":"1050000000000000000"}}},"avgExecutionPrice":{"type":"string","description":"Weighted-average implied rate across both venues","example":"0.048"},"ammPrice":{"type":"string","description":"Average implied rate on the AMM leg","example":"0.05"},"bookPrice":{"type":"string","description":"Average implied rate on the book leg","example":"0.045"},"iterations":{"type":"integer","description":"Number of optimizer iterations","example":47},"computeTimeMs":{"type":"number","description":"Total solver computation time in milliseconds","example":12.3},"fillGroups":{"type":"array","description":"Book-leg fill plan, one group per order type (direct first, then cross-market through the tokeniser). Within a group's fills[], the making delta for entry i is fills[i].cumulativeMakingAmount minus the previous entry's; the cumulativeMakerTakingWithFees delta is the fill's maxTaking; the cumulativeTakingAmountWithFees delta is the taker's input. `batch` carries the same plan ready to send.\n","items":{"type":"object","properties":{"orderType":{"type":"integer","description":"Order type shared by every order in this group (1-4)"},"isCrossMarket":{"type":"boolean","description":"false = direct fill, true = cross-market (tokeniser mint/redeem)"},"takerInputToken":{"type":"string","enum":["PT","IBT","YT"],"description":"Token role the taker funds for this group"},"fills":{"type":"array","items":{"type":"object","properties":{"order":{"type":"object"},"cumulativeMakingAmount":{"type":"string"},"cumulativeTakingAmount":{"type":"string"},"cumulativeTakingAmountWithFees":{"type":"string","description":"Cumulative taker-input funding budget, including fees"},"cumulativeMakerTakingWithFees":{"type":"string","description":"Cumulative maker-taking-token cap (the fills' maxTaking)"},"cumulativeAverageImpliedRate":{"type":"string"}}}}}}},"batch":{"type":"object","description":"Present iff fillRecipient was set and the book leg is not empty: fills (signed order, signature, contractMaker, amount, takerTraits, extension, interaction), budgets (strictly ascending tokens), minMakingFilled, skipReverts, and commandInput — the ABI-encoded input of router command 0x27. preSteps and postSteps ({ command, input }) are the router steps to run right before and after 0x27: the taker's IBT redeemed (0x07) or unwrapped (0x11) into the token a direct sell is paid in, then direct-buy proceeds deposited (0x04) or wrapped (0x10) back into IBT and kept by the router, or leftovers returned to the caller (0x02). The AMM leg is routed separately. IMPORTANT: the taker's output is not bounded by the batch (tokenised fills use minOut 0, post-step deposits have no minimum); end the router script with ASSERT_MIN_BALANCE (0x0f) on the output token, after postSteps and before the sweep, set from the quote minus your slippage tolerance.\n"},"limit":{"type":"object","description":"Present iff limitImpliedRate was requested. fillableAmount is the fee-free input executable within the limit (routing.totalAmount equals it; the actual spend stays routing.totalAmountWithFees); remainderAmount is the rest of the requested input, which should rest as a maker order.\n","properties":{"limitImpliedRate":{"type":"string"},"fillableAmount":{"type":"string"},"remainderAmount":{"type":"string"}}},"error":{"type":"string","description":"Error message when success is false"}}}}}},"400":{"description":"Invalid request parameters"},"500":{"description":"Server error"}}}},"/v1/{network}/metavaults/bridge/transactions":{"get":{"description":"Returns all bridge transactions for metavaults on a specific network","tags":["Metavaults","Bridge"],"parameters":[{"name":"network","in":"path","required":true,"description":"The network to fetch bridge transactions for","schema":{"type":"string"}},{"name":"refresh","in":"query","required":false,"description":"Force refresh the cache","schema":{"type":"boolean"}}],"responses":{"200":{"description":"The bridge transactions grouped by metavault address and chainId","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object","properties":{"transactions":{"type":"array","items":{"type":"object"}},"totalBridgedUsdLast30d":{"type":"number"},"totalInFlightUsd":{"type":"number"},"totalPendingUsd":{"type":"number"}}}}}}}}}},"/v1/{network}/metavaults":{"get":{"description":"Returns all metavaults for a specific network","tags":["Metavaults"],"parameters":[{"name":"network","in":"path","required":true,"description":"The network to fetch metavaults for","schema":{"type":"string"}}],"responses":{"200":{"description":"The list of metavaults on the network","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}},"example":[{"address":"0x0169ba21e6b5e0f9bea75acbbd1acaa75d60efe4","vault":"0x3006451e6bccbf1bda5deb09ee29cbfe05a1ac1a","chainId":8453,"name":"Spectra-MetaVault","symbol":"SMV","decimals":6,"curator":{"name":"MEV Capital","addresses":["0x3f2edd2AEaA3aF225D23b225bAf8CCEB900AF7d8"]},"underlying":{"address":"0x833589fcd6edb6e08f4c7c32d4f71b54bda02913","symbol":"USDC","decimals":6,"price":{"usd":0.999858682720936}},"metadata":{"title":"MEV USDC","description":"Get the best risk adjusted USDC yield"},"positions":[{"address":"0x63948fb5d91f8863f7ea30ce3ba7e281983b7f03","symbol":"PT-sw-smUSDC-1764115208","maturity":1764115208,"tvl":{"underlying":6336.955418,"usd":6336.05989670278},"pools":[{"address":"0x6a8f70e13cdbb1603c5b8c6f414ac7da4096a185","ptApy":6.8515481963273,"lpApy":{"total":6.39118960728796}}]}],"epochs":[{"timestamp":1760009459,"rate":"1000000","assets":"1000010"}],"tvl":{"underlying":10.9718245932344,"usd":10.9702740848365},"liveApy":{"total":6.23493039693365},"exchangeRate":"1000000","price":{"underlying":1,"usd":0.999858682720936}}]}}}}}},"/v1/{network}/metavaults/timelock/transactions":{"get":{"description":"Returns all timelocked transactions for metavaults on a specific network","tags":["Metavaults","Timelock"],"parameters":[{"name":"network","in":"path","required":true,"description":"The network to fetch timelocked transactions for","schema":{"type":"string"}},{"name":"days","in":"query","required":false,"description":"Number of days to look back for timelocked transactions (default: 30)","schema":{"type":"integer","default":30}},{"name":"includeDisabled","in":"query","required":false,"description":"Include transactions from disabled modules (default: false)","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"The timelocked transactions grouped by metavault address","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object","properties":{"chainId":{"type":"number","description":"The chain ID"},"transactions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"operator":{"type":"string"},"queueNonce":{"type":"string"},"timelockedTransactionHash":{"type":"string"},"timestamp":{"type":"string"},"blockNumber":{"type":"string"},"to":{"type":"string"},"value":{"type":"string"},"data":{"type":"string"},"operation":{"type":"number"},"nonce":{"type":"string"},"transactionHash":{"type":"string"},"logIndex":{"type":"string"},"delayModule":{"type":"string"},"metavault":{"type":"object","properties":{"address":{"type":"string"}}},"chainId":{"type":"number"},"status":{"type":"string","enum":["EXECUTED_OR_SKIPPED","QUEUED","READY","EXPIRED","MODULE_NOT_ENABLED"]},"executionMaxTimestamp":{"type":"string","nullable":true,"description":"Maximum timestamp when transaction can be executed (timestamp + txExpiration)"},"cooldownEndTimestamp":{"type":"string","nullable":true,"description":"Timestamp when cooldown period ends (timestamp + txCooldown)"}}}}}}}}}}}}},"/v1/{network}/otc/create":{"post":{"summary":"Publish a signed OTC rate order","description":"Validates a signed Spectra OTC RATE-order envelope (EIP-712 hash and signature, canonical rate-getter extension, salt binding, on-chain settlement hash / market pairing / invalidator state) and stores it in the order book. The signed makerTraits choose the fill policy: all-or-nothing (NO_PARTIAL_FILLS) or partial fills across several transactions (ALLOW_MULTIPLE_FILLS); no other combination is accepted. The API never signs or rewrites orders; fills and cancels happen directly against the settlement contract.\n","tags":["OTC"],"parameters":[{"name":"network","in":"path","required":true,"schema":{"type":"string","example":"flare"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["envelope"],"properties":{"envelope":{"type":"object","description":"SpectraOtcOrderEnvelopeV1 (spectra-otc SDK_INTERACTION_SPEC §10)"}}}}}},"responses":{"200":{"description":"Order accepted"},"400":{"description":"Malformed request"},"422":{"description":"Envelope failed validation"},"503":{"description":"OTC orders not enabled on this deployment"}}}},"/v1/{network}/otc/orders":{"get":{"summary":"List OTC rate orders","description":"Listed Spectra OTC RATE orders as canonical signed envelopes: not delisted, not expired, and neither filled, cancelled nor unfillable (maker balance or allowance below what the order still offers, ERC-1271 rejection, rate getter refusal) at the last per-minute revalidation, whose verdict is in metadata.invalidated, metadata.unfillableReason and metadata.checkedAt. Orders signed with partial fills (metadata.allowsPartialFills) fill across several transactions and stay listed until nothing is left: metadata.remainingMakingAmount is the making amount left at the last check (an all-or-nothing order offers its whole amount until it closes). A closed order's metadata.outcome says how it ended, FILLED or CANCELLED, once read from the settlement's OrderFilled logs: null until then, about a minute after a fill and ten after a cancel. A cancelled partial order keeps what earlier fills took; metadata.remainingMakingAmount is then what the cancel withdrew. Clients must re-decode signed terms from the extension and refresh amounts/invalidator state on-chain — the stored takingAmount is only a creation-time baseline.\n","tags":["OTC"],"parameters":[{"name":"network","in":"path","required":true,"schema":{"type":"string","example":"flare"}},{"name":"market","in":"query","description":"Filter by the signed PT (market) address","schema":{"type":"string"}},{"name":"makerAddress","in":"query","schema":{"type":"string"}},{"name":"derivativeKind","in":"query","description":"0 = PT, 1 = YT","schema":{"type":"string","enum":["0","1"]}},{"name":"includeInactive","in":"query","description":"Also include expired, delisted, filled/cancelled and currently unfillable rows (maker history views)\n","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"List of signed envelopes"},"503":{"description":"OTC orders not enabled on this deployment"}}}},"/v1/{network}/otc/rfq/cancel":{"post":{"summary":"Cancel a quote request","description":"The requester withdraws their request (EIP-712 CancelQuoteRequest signature verified against the stored requester). Already-published response orders stay live on the book — they are independent signed orders their makers cancel on-chain.\n","tags":["OTC"],"parameters":[{"name":"network","in":"path","required":true,"schema":{"type":"string","example":"flare"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["requestHash","signature"]}}}},"responses":{"200":{"description":"Cancelled"},"400":{"description":"Malformed request"},"422":{"description":"Cancel failed validation"},"503":{"description":"OTC orders not enabled on this deployment"}}}},"/v1/{network}/otc/rfq/create":{"post":{"summary":"Submit a signed OTC quote request","description":"Stores a non-binding, EIP-712-signed request for quotes addressed to a set of curator vaults. The signature is verified against the requester (ERC-1271 aware) and the market fields are cross-checked on-chain; recipients respond by publishing private OTC rate orders through /otc/create and linking them via /otc/rfq/respond.\n","tags":["OTC"],"parameters":[{"name":"network","in":"path","required":true,"schema":{"type":"string","example":"flare"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["envelope"],"properties":{"envelope":{"type":"object","description":"SpectraOtcRfqEnvelopeV1"}}}}}},"responses":{"200":{"description":"Request accepted"},"400":{"description":"Malformed request"},"422":{"description":"Request failed validation"},"503":{"description":"OTC orders not enabled on this deployment"}}}},"/v1/{network}/otc/rfq/decline":{"post":{"summary":"Decline a quote request for one vault","description":"A curator discards a quote request for THEIR vault only. The EIP-712 DeclineQuoteRequest signature is verified against the signer, and the signer's authority over the vault (curator/configurator role member or Safe owner) is verified against a chain-reconciled vault snapshot — fail-closed when that state cannot be read.\n","tags":["OTC"],"parameters":[{"name":"network","in":"path","required":true,"schema":{"type":"string","example":"flare"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["requestHash","vault","signer","signature"]}}}},"responses":{"200":{"description":"Declined"},"400":{"description":"Malformed request"},"422":{"description":"Decline failed validation"},"503":{"description":"OTC disabled, or vault authority state unavailable"}}}},"/v1/{network}/otc/rfq/requests":{"get":{"summary":"List OTC quote requests","description":"Two views. `?requester=` returns the requester's own requests with every recipient's state plus the full envelopes of linked response orders (ready to fill). `?vault=` returns the vault's inbox — its own recipient rows on still-open requests; PENDING rows are the actionable ones, other recipients' identities are not exposed.\n","tags":["OTC"],"parameters":[{"name":"network","in":"path","required":true,"schema":{"type":"string","example":"flare"}},{"name":"requester","in":"query","schema":{"type":"string"}},{"name":"vault","in":"query","schema":{"type":"string"}},{"name":"includeClosed","in":"query","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Request list"},"400":{"description":"Malformed request"},"503":{"description":"OTC orders not enabled on this deployment"}}}},"/v1/{network}/otc/rfq/respond":{"post":{"summary":"Link a vault's response order to a quote request","description":"Deliberately signature-free — the linked order (published through /otc/create) is itself maker-signed by the vault and must be private to the requester, so a matching stored order already proves intent. The pairing is enforced: maker == the recipient vault, opposite side, matching derivative/quote kinds, matching market (on-chain (ibt, maturity) check for new-market requests), allowlist ∋ requester.\n","tags":["OTC"],"parameters":[{"name":"network","in":"path","required":true,"schema":{"type":"string","example":"flare"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["requestHash","vault","orderHash"]}}}},"responses":{"200":{"description":"Response linked"},"400":{"description":"Malformed request"},"422":{"description":"The order does not pair with the request"},"503":{"description":"OTC orders not enabled on this deployment"}}}},"/v1/{network}/pools/{curvePoolAddress}/activity":{"get":{"description":"Returns historical trading activity for a specific pool with USD values","tags":["Pools"],"parameters":[{"name":"network","in":"path","required":true,"description":"The network to fetch pool activity for","schema":{"type":"string"}},{"name":"curvePoolAddress","in":"path","required":true,"description":"The curve pool contract address","schema":{"type":"string"}}],"responses":{"200":{"description":"List of historical pool transactions with USD values","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"hash":{"type":"string","description":"Transaction hash"},"timestamp":{"type":"number","description":"Transaction timestamp (Unix timestamp)"},"valueUsd":{"type":"number","description":"USD value of the transaction at the time it occurred"},"type":{"type":"string","description":"Type of transaction","enum":["BUY_PT","SELL_PT","DEPOSIT","WITHDRAW","REDEEM"]}}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["Invalid chain ID or underlying asset address"]}}}}}}}}},"/v1/{network}/pools/{curvePoolAddress}/stats":{"get":{"description":"AMM trading volume for complete UTC days (1/7/30, previous 30, lifetime). Every window includes explicit coverage. Current partial UTC day is excluded. No OTC volume.","tags":["Pools"],"parameters":[{"name":"network","in":"path","required":true,"schema":{"type":"string"}},{"name":"curvePoolAddress","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Available statistics, which may have partial or stale status. Display totals as complete only when that window's complete flag is true.","content":{"application/json":{"schema":{"type":"object","required":["pool","chainId","updatedAt","asOf","status","source","windows"],"properties":{"pool":{"type":"string"},"chainId":{"type":"integer"},"updatedAt":{"type":"string","format":"date-time"},"asOf":{"type":"string","format":"date-time","description":"Exclusive end of the last complete indexed UTC day"},"status":{"type":"string","enum":["fresh","stale","partial"]},"source":{"type":"object","properties":{"blockNumber":{"type":"integer"},"indexedAt":{"type":"string","format":"date-time"},"historyComplete":{"type":"boolean"},"hasIndexingErrors":{"type":"boolean"},"pages":{"type":"integer"},"records":{"type":"integer"}}},"windows":{"type":"object","required":["d1","d7","d30","prev30","lifetime"],"additionalProperties":{"type":"object","required":["from","to","complete","reasons","underlying","usd","missingPriceDays"],"properties":{"from":{"type":"integer","description":"Inclusive Unix timestamp"},"to":{"type":"integer","description":"Exclusive Unix timestamp"},"complete":{"type":"boolean"},"reasons":{"type":"array","items":{"type":"string","enum":["pool-too-young","history-incomplete","indexing-errors","missing-usd-prices","invalid-data"]}},"underlying":{"type":"string","description":"Available volume in underlying token units"},"usd":{"type":"number","nullable":true,"description":"Null when any nonzero volume day is unpriced"},"missingPriceDays":{"type":"integer"}}}}}}}}},"400":{"description":"Invalid network or pool address"},"404":{"description":"Pool not found"},"503":{"description":"Pool statistics temporarily unavailable"}}}},"/v1/{network}/pools/{curvePoolAddress}/volume":{"get":{"description":"Returns historical trading volume data for a specific pool with buy/sell volumes in USD","tags":["Pools"],"parameters":[{"name":"network","in":"path","required":true,"description":"The network to fetch pool volume data for","schema":{"type":"string"}},{"name":"curvePoolAddress","in":"path","required":true,"description":"The curve pool contract address","schema":{"type":"string"}}],"responses":{"200":{"description":"Historical trading volume data with buy/sell volumes in USD","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"timestamp":{"type":"number","description":"Unix timestamp for the volume data point"},"buyUsd":{"type":"number","description":"Buy volume in USD for this time period"},"sellUsd":{"type":"number","description":"Sell volume in USD for this time period"}}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["Invalid chain ID or underlying asset address"]}}}}}}}}},"/v1/{network}/pools":{"get":{"description":"Returns all pools with their associated PT/YT/LP for a specific network","tags":["Pools"],"parameters":[{"name":"network","in":"path","required":true,"description":"The network to fetch pools for","schema":{"type":"string"}},{"name":"quality","in":"query","required":false,"description":"ok returns only pools whose quality.status is ok (no implausible APY, impaired PT rate or IBT-depleted pool); markets left without pools are dropped. Applied by default for source=defillama.","schema":{"type":"string","enum":["ok"]}},{"name":"source","in":"query","required":false,"description":"Integrator identifier. defillama implies quality=ok.","schema":{"type":"string"}}],"responses":{"200":{"description":"Available pools. Check catalog headers before presenting data as current or complete.","headers":{"X-Spectra-Catalog-Status":{"schema":{"type":"string","enum":["fresh","stale","partial"]},"description":"Fresh snapshot, retained snapshot served because its refresh failed, or current result with markets omitted or a shared source unavailable."},"X-Spectra-Catalog-As-Of":{"schema":{"type":"string","format":"date-time"},"description":"Original compilation time, preserved when serving retained data."},"X-Spectra-Catalog-Omitted":{"schema":{"type":"integer"},"description":"PT markets omitted from this response."},"X-Spectra-Quality-Omitted":{"schema":{"type":"integer"},"description":"Pools removed by the quality filter (only with quality=ok or source=defillama)."}},"content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"pt":{"type":"object","description":"PT information"},"address":{"type":"string","description":"Pool contract address"},"chainId":{"type":"number","description":"Blockchain network chain ID"},"lpt":{"type":"object","description":"Liquidity pool token information with supply and price","properties":{"supply":{"type":"string","description":"Total supply of LP tokens"},"price":{"type":"object","description":"Price information"}}},"liquidity":{"type":"object","description":"Total liquidity in the pool"},"ibtToPt":{"type":"string","nullable":true,"description":"Exchange rate from IBT to PT"},"ptToIbt":{"type":"string","nullable":true,"description":"Exchange rate from PT to IBT"},"ptPrice":{"type":"object","description":"Principal Token price"},"ytPrice":{"type":"object","description":"Yield Token price"},"impliedApy":{"type":"number","description":"Implied Annual Percentage Yield"},"ptApy":{"type":"number","description":"Principal Token APY"},"quality":{"type":"object","description":"Whether the quoted rates are safe to present. Anomalous pools keep their raw figures but should not be listed as opportunities.","properties":{"status":{"type":"string","enum":["ok","anomalous"]},"reasons":{"type":"array","items":{"type":"string","enum":["implausible_apy","pt_rate_impaired","ibt_depleted_pool"]},"description":"implausible_apy: fixed or implied APY above 500% or LP APY above 1000%; pt_rate_impaired: PT rate below 99% of par (losses absorbed); ibt_depleted_pool: under 1% of pool liquidity is IBT."}}},"ytLeverage":{"type":"number","nullable":true,"description":"Yield Token leverage multiplier"},"lpApy":{"type":"object","description":"Liquidity Provider APY breakdown","properties":{"total":{"type":"number","description":"Total APY for LP"},"boostedTotal":{"type":"number","description":"Boosted total APY (optional)"},"details":{"type":"object","description":"Detailed APY breakdown","properties":{"fees":{"type":"number","description":"APY from trading fees"},"pt":{"type":"number","description":"APY from PT component"},"ibt":{"type":"number","description":"APY from IBT component"},"rewards":{"type":"object","description":"APY from reward tokens"},"boostedRewards":{"type":"object","description":"Boosted reward APY ranges"}}}}},"ibtAmount":{"type":"string","description":"Amount of IBT in the pool"},"ptAmount":{"type":"string","description":"Amount of PT in the pool"},"feeRate":{"type":"string","description":"Pool fee rate"},"outFee":{"type":"string","description":"Output fee"},"midFee":{"type":"string","description":"Mid-price fee"},"spotPrice":{"type":"string","nullable":true,"description":"Current spot price"},"lastPrices":{"type":"string","description":"Last recorded prices"},"type":{"type":"string","enum":["CURVE","CURVE_SNG"],"description":"Pool type (AMM curve type)"}}}}}}},"503":{"description":"No usable catalog. No-store response with X-Spectra-Catalog-Status unavailable."}}}},"/v1/{network}/portfolio/{address}":{"get":{"description":"Returns the portfolio (positions) for a specific address on a specific network","tags":["Portfolio"],"parameters":[{"name":"network","in":"path","required":true,"description":"The network to fetch portfolio for","schema":{"type":"string"}},{"name":"address","in":"path","required":true,"description":"The wallet address to fetch portfolio for","schema":{"type":"string"}}],"responses":{"200":{"description":"The user's portfolio containing their positions across different PTs/YTs and their associated pools","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string","description":"Future contract address"},"name":{"type":"string","description":"Future token name"},"symbol":{"type":"string","description":"Future token symbol"},"decimals":{"type":"number","description":"Token decimals"},"chainId":{"type":"number","description":"Blockchain network chain ID"},"rate":{"type":"string","description":"Current exchange rate"},"addressStatus":{"type":"string","enum":["safe","role-unsafe","unsafe","blocked"],"description":"Contract address registry status of this market (denylist, then its own entry, then its factory's when the factory passes its status on, otherwise unsafe)"},"exitOnly":{"type":"boolean","description":"True when the address gate hides this market from discovery. The position is kept, only exit actions (withdraw, redeem, remove liquidity) should be offered"},"balance":{"type":"string","nullable":true,"description":"PT balance of the user"},"yt":{"type":"object","description":"Yield Token information","properties":{"address":{"type":"string","description":"YT contract address"},"decimals":{"type":"number","description":"YT decimals"},"chainId":{"type":"number","description":"Chain ID"},"balance":{"type":"string","nullable":true,"description":"YT balance of the user"},"yield":{"type":"object","nullable":true,"description":"Yield information","properties":{"claimable":{"type":"string","nullable":true,"description":"Claimable yield amount"},"claimed":{"type":"string","nullable":true,"description":"Already claimed yield amount"}}}}},"ibt":{"type":"object","description":"Interest Bearing Token information","properties":{"address":{"type":"string","description":"IBT contract address"},"name":{"type":"string","description":"IBT name"},"symbol":{"type":"string","description":"IBT symbol"},"decimals":{"type":"number","description":"IBT decimals"},"chainId":{"type":"number","description":"Chain ID"},"rate":{"type":"string","description":"IBT rate"},"apr":{"type":"object","description":"APR information","properties":{"total":{"type":"number","description":"Total APR"},"details":{"type":"object","properties":{"base":{"type":"number","description":"Base APR"},"rewards":{"type":"object","description":"Rewards breakdown"}}}}},"price":{"type":"object","description":"IBT price information","properties":{"underlying":{"type":"number","description":"Price in underlying terms"},"usd":{"type":"number","nullable":true,"description":"Price in USD"}}},"protocol":{"type":"string","nullable":true,"description":"Protocol name"},"balance":{"type":"string","nullable":true,"description":"IBT balance of the user"}}},"underlying":{"type":"object","description":"Underlying token information","properties":{"address":{"type":"string","description":"Underlying token address"},"name":{"type":"string","description":"Underlying token name"},"symbol":{"type":"string","description":"Underlying token symbol"},"decimals":{"type":"number","description":"Underlying token decimals"},"chainId":{"type":"number","description":"Chain ID"},"price":{"type":"object","description":"Underlying token price","properties":{"usd":{"type":"number","nullable":true,"description":"Price in USD"}}},"balance":{"type":"string","nullable":true,"description":"Underlying balance of the user"}}},"maturity":{"type":"number","description":"Future maturity timestamp"},"maturityValue":{"type":"object","nullable":true,"description":"Value at maturity","properties":{"underlying":{"type":"number","description":"Value in underlying terms"},"usd":{"type":"number","nullable":true,"description":"Value in USD"}}},"createdAt":{"type":"number","description":"Creation timestamp","items":{"type":"object","properties":{"amount":{"type":"number","nullable":true,"description":"Multiplier amount"},"name":{"type":"string","description":"Multiplier name"}}}},"pools":{"type":"array","description":"Associated pools where user has LP positions","items":{"type":"object","properties":{"address":{"type":"string","description":"Pool contract address"},"chainId":{"type":"number","description":"Chain ID"},"lpt":{"type":"object","description":"LP token information","properties":{"address":{"type":"string","description":"LP token address"},"decimals":{"type":"number","description":"LP token decimals"},"chainId":{"type":"number","description":"Chain ID"},"supply":{"type":"string","description":"Total LP token supply"},"price":{"type":"object","description":"LP token price"},"balance":{"type":"string","nullable":true,"description":"User's LP token balance"}}},"liquidity":{"type":"object","description":"Pool liquidity information"},"ibtToPt":{"type":"string","nullable":true,"description":"Exchange rate from IBT to PT"},"ptToIbt":{"type":"string","nullable":true,"description":"Exchange rate from PT to IBT"},"ptPrice":{"type":"object","description":"PT price in the pool"},"ytPrice":{"type":"object","description":"YT price in the pool"},"impliedApy":{"type":"number","description":"Implied APY from the pool"},"ptApy":{"type":"number","description":"PT APY"},"ytLeverage":{"type":"number","nullable":true,"description":"YT leverage multiplier"},"lpApy":{"type":"object","description":"LP APY breakdown","properties":{"total":{"type":"number","description":"Total LP APY"},"boostedTotal":{"type":"number","nullable":true,"description":"Boosted total APY"},"details":{"type":"object","description":"APY breakdown details"}}},"ibtAmount":{"type":"string","description":"IBT amount in pool"},"ptAmount":{"type":"string","description":"PT amount in pool"},"feeRate":{"type":"string","description":"Pool fee rate"},"outFee":{"type":"string","description":"Output fee"},"midFee":{"type":"string","description":"Mid-price fee"},"spotPrice":{"type":"string","nullable":true,"description":"Current spot price"},"lastPrices":{"type":"string","description":"Last recorded prices"},"type":{"type":"string","enum":["CURVE","CURVE_SNG"],"description":"Pool AMM type"}}}}}}}}}}}}},"/v1/watch-tower/{network}/transactions":{"get":{"description":"Returns all watch tower transactions (conditional orders) for a specific network","tags":["Watch Tower"],"parameters":[{"name":"network","in":"path","required":true,"description":"The network to fetch watch tower transactions for","schema":{"type":"string"}},{"name":"owner","in":"query","required":false,"description":"Optional owner address to filter transactions by","schema":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"}}],"responses":{"200":{"description":"The watch tower transactions","content":{"application/json":{"schema":{"type":"object","properties":{"network":{"type":"string"},"totalTransactions":{"type":"number"},"transactions":{"type":"array","items":{"type":"object","properties":{"owner":{"type":"string"},"conditionalOrder":{"type":"object","properties":{"id":{"type":"string"},"tx":{"type":"string"},"params":{"type":"object"},"proof":{"type":"object"},"composableCow":{"type":"string"},"orders":{"type":"array","items":{"type":"object","properties":{"orderUid":{"type":"string"},"status":{"type":"string","enum":["SUBMITTED","FILLED","UNKNOWN"]}}}},"pollResult":{"type":"object","nullable":true,"properties":{"lastExecutionTimestamp":{"type":"number"},"blockNumber":{"type":"number"},"result":{"type":"object"}}}}}}}}}}}}}}}},"/v1/addresses/chains":{"get":{"summary":"List chains represented in the address catalog","description":"Returns the union of chains with any core or MetaVault deployment. Inclusion does not imply that every address namespace is available on that chain.","tags":["Address Catalog"],"security":[],"responses":{"200":{"description":"Numeric chain IDs in ascending order.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogChainsResponse"},"example":{"chains":[1,10,14,56,143,146,999,1329,8453,42161,43111,43114,747474]}}}}}}},"/v1/addresses/entities":{"get":{"summary":"Resolve a typed address-catalog entity and its relationships","description":"Resolves a pool, MetaVault global deployment, or MetaVault vault without requiring callers to parse catalog keys. Pool lookup accepts exactly one pool or PT address; PT lookup may validly return many pools. Cardinality and completeness are independent, so provider degradation never masquerades as not-found.","tags":["Address Catalog"],"security":[],"parameters":[{"name":"kind","in":"query","required":true,"schema":{"type":"string","enum":["pool","metavault-global","metavault-vault"]}},{"name":"chain","in":"query","required":true,"schema":{"type":"integer","minimum":1}},{"name":"pool","in":"query","schema":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}},{"name":"pt","in":"query","schema":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}},{"name":"vault","in":"query","schema":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}}],"responses":{"200":{"description":"A constrained typed entity result. Healthy responses omit errors.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogEntityResponse"}}}},"400":{"description":"Missing, malformed, conflicting, or kind-inapplicable selector.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogApiError"}}}},"500":{"description":"Unexpected registry failure with a constant, credential-free body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogApiError"}}}}}}},"/v1/addresses/managed-safes":{"get":{"summary":"List Safes intentionally managed by Spectra","description":"Returns operational Safes from reviewed configuration plus MetaVault Safes discovered from the same RegistryV2/subgraph catalog used by Curator. It never discovers Safes from owners, wallets, or a Safe Transaction Service.","tags":["Address Catalog"],"security":[],"parameters":[{"name":"chain","in":"query","required":false,"description":"Positive decimal chain ID. A valid unrepresented chain returns an empty list.","schema":{"type":"integer","minimum":1}},{"name":"role","in":"query","required":false,"schema":{"$ref":"#/components/schemas/AddressCatalogManagedSafeRole"}}],"responses":{"200":{"description":"Managed Safes in stable chain/address order after applying all supplied filters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogManagedSafeResponse"}}}},"400":{"description":"A supplied chain or role filter is malformed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogApiError"}}}},"500":{"description":"Unexpected local catalog failure with a constant, credential-free body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogApiError"}}}}}}},"/v1/addresses/metavaults/{chainId}/{vaultSafe}":{"get":{"summary":"List one MetaVault's typed registry records","description":"Returns vault-scoped `metavaults.vault.{chainId}.{vaultSafe}.registry.*` records with canonical Registry V2 value types. The Safe accepts any hexadecimal casing and record keys emit it lowercase. An undeployed namespace or a confirmed absent vault is a healthy empty response; provider failure is reported in `errors`.","tags":["Address Catalog"],"security":[],"parameters":[{"name":"chainId","in":"path","required":true,"description":"Positive decimal chain ID.","schema":{"type":"integer","minimum":1}},{"name":"vaultSafe","in":"path","required":true,"description":"20-byte hexadecimal Safe address, accepted case-insensitively.","schema":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}}],"responses":{"200":{"description":"Vault-scoped records, possibly with a partial-result error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogListResponse"},"examples":{"healthy":{"value":{"addresses":[{"key":"metavaults.vault.8453.0x2222222222222222222222222222222222222222.registry.core.safe","address":"0x2222222222222222222222222222222222222222","valueType":"address","chainId":8453,"source":"subgraph","resolvedAt":1710000000000}],"count":1}},"structurallyAbsent":{"value":{"addresses":[],"count":0}},"degraded":{"value":{"addresses":[],"count":0,"errors":[{"resolver":"vaultAddresses","chainId":8453,"code":"SUBGRAPH_DEGRADED"}]}}}}}},"400":{"description":"The chainId or vaultSafe path segment is malformed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogApiError"}}}},"500":{"description":"Unexpected registry failure with a constant, credential-free body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogApiError"}}}}}}},"/v1/addresses/metavaults/{chainId}":{"get":{"summary":"List MetaVault global registry addresses","description":"Returns only chain-global MetaVault registry entries. It does not enumerate vaults or return vault-scoped entries. A structurally absent namespace is an empty healthy response; a provider failure is reported in `errors`.","tags":["Address Catalog"],"security":[],"parameters":[{"name":"chainId","in":"path","required":true,"description":"Positive decimal chain ID.","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"MetaVault global records, possibly with a partial-result error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogListResponse"},"examples":{"healthy":{"value":{"addresses":[{"key":"metavaults.global.8453.registry.core.factory","address":"0x1111111111111111111111111111111111111111","chainId":8453,"source":"subgraph","resolvedAt":1710000000000}],"count":1}},"structurallyAbsent":{"value":{"addresses":[],"count":0}},"degraded":{"value":{"addresses":[],"count":0,"errors":[{"resolver":"metavaultsGlobals","chainId":8453,"code":"SUBGRAPH_DEGRADED"}]}}}}}},"400":{"description":"The chainId path segment is malformed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogApiError"}}}},"500":{"description":"Unexpected registry failure with a constant, credential-free body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogApiError"}}}}}}},"/v1/addresses/pools/{chainId}":{"get":{"summary":"List pool oracles or query pool relationships","description":"With no selector, returns pool-keyed oracle records and follows every subgraph page with a strictly increasing Pool id cursor, deduplicates PTs, and performs RPC reads in bounded chunks. With exactly one `pool` or `pt` selector, returns typed pool, PT, IBT and rate-oracle relationships. PT reverse lookup is completely cursor-paginated. Validated identities survive an absent or unavailable oracle.","tags":["Address Catalog"],"security":[],"parameters":[{"name":"chainId","in":"path","required":true,"description":"Positive decimal chain ID.","schema":{"type":"integer","minimum":1}},{"name":"pool","in":"query","required":false,"description":"Exact Spectra pool address. Mutually exclusive with `pt`.","schema":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}},{"name":"pt","in":"query","required":false,"description":"Principal token reverse lookup returning every matching pool. Mutually exclusive with `pool`.","schema":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$"}}],"responses":{"200":{"description":"Pool-keyed oracle records in list mode, or typed pool relationships in selector mode, possibly with a partial-result error.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/AddressCatalogListResponse"},{"$ref":"#/components/schemas/AddressCatalogPoolRelationshipResponse"}]},"examples":{"healthy":{"value":{"addresses":[{"key":"pools.oracle.8453.0x2222222222222222222222222222222222222222","address":"0x3333333333333333333333333333333333333333","chainId":8453,"source":"rpc","resolvedAt":1710000000000}],"count":1}},"structurallyAbsent":{"value":{"addresses":[],"count":0}},"degraded":{"value":{"addresses":[],"count":0,"errors":[{"resolver":"poolOracles","chainId":8453,"code":"SUBGRAPH_DEGRADED"}]}}}}}},"400":{"description":"The chainId path segment is malformed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogApiError"}}}},"500":{"description":"Unexpected registry failure with a constant, credential-free body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogApiError"}}}}}}},"/v1/addresses":{"get":{"summary":"Query the Spectra address catalog","description":"Returns the static catalog by default, a chain-scoped list with `chain`,\nor one full catalog record with `key`. `category` filters list responses\nat a dot-segment boundary. A syntactically valid undeployed chain is an\nhonest empty result, not a request error. A list may contain both useful\naddresses and `errors` when one resolver leg is degraded.\n","tags":["Address Catalog"],"security":[],"parameters":[{"name":"chain","in":"query","required":false,"description":"Positive decimal chain ID. With `key`, constrains the record to the same chain.","schema":{"type":"integer","minimum":1}},{"name":"key","in":"query","required":false,"description":"Exact canonical dot-notation key. Takes precedence over list mode.","schema":{"type":"string","minLength":1},"example":"core.registryV2.8453"},{"name":"category","in":"query","required":false,"description":"Dot-namespace prefix for list modes, for example `core` or `metavaults.global`.","schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"Catalog list or exact-key result. The shape depends on whether `key` was supplied.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/AddressCatalogListResponse"},{"$ref":"#/components/schemas/AddressCatalogExactResponse"}]},"examples":{"exactKey":{"summary":"Exact-key response contains the whole record under `address`","value":{"address":{"key":"core.registryV2.8453","address":"0x1111111111111111111111111111111111111111","chainId":8453,"source":"static","resolvedAt":1710000000000}}},"unknownKey":{"summary":"A well-formed key that does not exist remains a 200","value":{"address":null}},"structurallyAbsent":{"summary":"No address namespace is deployed on the requested chain","value":{"addresses":[],"count":0}},"degradedPartialResult":{"summary":"Static records survive a failed dynamic resolver leg","value":{"addresses":[{"key":"core.registryV2.8453","address":"0x1111111111111111111111111111111111111111","chainId":8453,"source":"static","resolvedAt":1710000000000}],"count":1,"errors":[{"resolver":"metavaultsGlobals","chainId":8453,"code":"SUBGRAPH_DEGRADED"}]}}}}}},"400":{"description":"A supplied query parameter is malformed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogApiError"},"example":{"error":{"code":"INVALID_REQUEST","message":"Invalid chain","retryable":false,"details":{"field":"chain","received":"abc"}}}}}},"500":{"description":"Exact lookup or unexpected registry failure. The response never contains provider error text.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressCatalogApiError"},"example":{"error":{"code":"INTERNAL_ERROR","message":"Address registry error","retryable":true}}}}}}}},"/v1/prices/{network}":{"get":{"summary":"Get latest USD prices for tokens on a given network","description":"Returns the latest DefiLlama USD price for each requested token on the given network, as a `{ [tokenAddress]: usdPrice }` map. Used to value holdings whose price isn't in a vault snapshot (e.g. a whitelisted-but- unheld ERC-4626 vault priced via its underlying).\n","tags":["Prices"],"parameters":[{"in":"path","name":"network","required":true,"schema":{"type":"string"},"description":"The network (e.g. mainnet, base)"},{"in":"query","name":"tokens","required":true,"schema":{"type":"string"},"description":"Comma-separated token addresses to price"}],"responses":{"200":{"description":"USD price per token","content":{"application/json":{"schema":{"type":"object"},"example":{"0x833589fcd6edb6e08f4c7c32d4f71b54bda02913":0.9998}}}},"400":{"description":"Invalid network or missing tokens"},"500":{"description":"Server error"}}}},"/v1/spectra/circulating-supply":{"get":{"description":"Returns the circulating supply of SPECTRA tokens","tags":["Spectra Token"],"responses":{"200":{"description":"The circulating supply of SPECTRA tokens","content":{"application/json":{"schema":{"type":"string"}}}}}}},"/v1/spectra/total-supply":{"get":{"description":"Returns the total supply of SPECTRA tokens","tags":["Spectra Token"],"responses":{"200":{"description":"The total supply of SPECTRA tokens","content":{"application/json":{"schema":{"type":"string"}}}}}}},"/v1/stellar/activity":{"get":{"tags":["Stellar"],"summary":"Market activity / account history feed","description":"Indexed on-chain activity for Stellar PT markets. Market mode (`pt` only) serves the public feed — order fills, tokenize, redeem. Account mode (`account`, optionally scoped by `pt`) serves every event the account participated in, either side. Rows carry kinds, raw string amounts and token addresses — the app maps labels and formats values against its market catalog. Keyset-paginate with `before` = the last row's eventId.\n","parameters":[{"in":"query","name":"pt","schema":{"type":"string"}},{"in":"query","name":"account","schema":{"type":"string"}},{"in":"query","name":"before","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"type":"integer","maximum":100}}],"responses":{"200":{"description":"{ success, rows, meta: { syncedToLedger, syncedAt, coverageStartLedger, gapCount } }"},"400":{"description":"Invalid parameters."}}}},"/v1/stellar/limit-orders/create":{"post":{"tags":["Stellar Limit Orders"],"summary":"Admit a signed or already registered maker order","description":"Submit the complete Order fields as decimal strings (no nonce). registrationMode defaults to auth_entry: authEntry must contain the maker-signed register_orders_batch authorization, as base64 XDR. For onchain mode, omit authEntry after register_order confirms. The API recomputes the order hash and requires an open registration on the configured engine. It never registers or submits transactions. validateOnly runs every admission check without persisting; in onchain mode call it BEFORE the register transaction, since it is the only step that can still reject a crossing order.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["order"],"properties":{"order":{"type":"object","description":"Complete Stellar Order fields"},"registrationMode":{"type":"string","enum":["auth_entry","onchain"],"default":"auth_entry"},"authEntry":{"type":"string","nullable":true,"description":"Required only in auth_entry mode"},"allowCrossing":{"type":"boolean","default":false},"validateOnly":{"type":"boolean","default":false,"description":"Run all admission checks and persist nothing"}}}}}},"responses":{"200":{"description":"{ success: true, orderHash }"},"400":{"description":"{ success: false, error } — validation failure"},"409":{"description":"Order would immediately match resting liquidity"},"500":{"description":"{ success: false, error }"}}}},"/v1/stellar/limit-orders/generate-order-data":{"post":{"tags":["Stellar Limit Orders"],"summary":"Server-filled order fields for maker signing","description":"Body { pt, maker, receiver?, orderType, makingAmount, impliedApy, expiry, makerTokenType? }. Fills salt, impliedRate (APY→WAD), failSafeRate and the recommended auth-entry expiration ledger (the entry must outlive the order; network ceiling ≈ +3M ledgers).\n"}},"/v1/stellar/limit-orders/orders":{"get":{"tags":["Stellar Limit Orders"],"summary":"List orders (DB + live on-chain status join)","description":"Query params mirror the EVM book: market, makerAddress, orderTypes, orderStatus, limit, offset. DTO shares the EVM field names plus the Stellar extras authEntry + registered (no nonce).\n"}},"/v1/stellar/limit-orders/quote":{"post":{"tags":["Stellar Limit Orders"],"summary":"Book-walk quote → fill plan (register+fill legs for the app)","description":"Body { pt, orderType, amount }. `orderType` is the TAKER'S trade (EVM-solver vocabulary; buy PT = 1/IbtForPt) — the walk consumes the opposing maker book. Returns the best-first fill plan with per-order authEntry + registered flags and the EXACT taker input (the engine consumes taker_input_amount in full — quotes size it precisely, drift-padded like maxTaking).\n"}},"/v1/stellar/pools":{"get":{"tags":["Stellar"],"summary":"List Stellar PT markets","description":"All PT markets registered on the Stellar core registry, in the same Future shape as the EVM {network}/pools endpoint. Markets whose PT wasm predates pricing_data are flagged tradable=false — orders on them cannot settle on-chain. Stellar has no AMM: pools is always empty and market pricing comes from the limit-order book. tvl.sourceAsOf is the oldest USD TVL input timestamp (the exact total_assets simulation ledger close time and underlying USD quote timestamp), never request/cache time. tvl.quality is fresh, stale, missing or unverified; fresh requires both inputs within 15 minutes. Cached responses preserve sourceAsOf, so consumers must also check its age at use time. This provenance describes USD TVL only. tvl.observedAt is the latest actual input timestamp; observationId identifies the network, ledger and quote evidence, surviving cached reads without dropping new balances priced with the same older quote. tvl.network distinguishes stellar:pubnet from stellar:testnet using an RPC-verified simulation passphrase. Mismatch or unavailable verification leaves network null and quality unverified. All source checks allow 60 seconds of forward clock skew; larger future timestamps are unverified. Missing means USD cannot be valued, not that underlying TVL is unavailable. Low-confidence prices remain displayable but unverified. EURC quotes may exceed the 15-minute window between provider updates and appear stale. Missing or unverified observations have null observedAt and observationId. ibt.rate and spotRate are live wrapper redemption/conversion quotes in raw underlying units per whole IBT, with ibt.rateObservation carrying the ledger and sourceAsOf. When the wrapper cannot be quoted they fall back to the PT's stored IbtRate and rateObservation is null. ibt.apr values are APY percentage points; observation identifies provider, method, windowSeconds, sourceAsOf and expiresAt. Blend uses current supply rates; Upshift uses seven-day realized share-price returns; Centrifuge uses seven-day reported issuer NAV returns, not Stellar oracle-price history. Missing or expired yield is null; genuine zero and negative yields are preserved. Every cached read reapplies the yield's expiresAt.\n","responses":{"200":{"description":"Array of Stellar markets (Future shape + tradable)."},"500":{"description":"Upstream Soroban RPC or configuration error."},"503":{"description":"Stellar support is not enabled in this deployment."}}}},"/v1/stellar/portfolio/{address}":{"get":{"tags":["Stellar"],"summary":"A holder's Stellar PT/YT positions","description":"USD tvl.sourceAsOf is the oldest exact simulation-ledger/quote timestamp; observedAt is the latest input, and observationId identifies that evidence. network is stellar:pubnet or stellar:testnet only after the RPC network matches the configured simulation passphrase. quality is fresh, stale, missing or unverified. Fresh requires complete evidence within 15 minutes, allowing 60 seconds of forward clock skew; clients must recheck source age. Unverified or missing observations have null observedAt and observationId. Missing means USD cannot be valued, not that underlying TVL is unavailable. Per-read cache aging preserves source times and applies on all Stellar routes. Low-confidence prices remain displayable but unverified. EURC quotes may exceed the 15-minute window between provider updates and appear stale. IBT rates and base APY follow /v1/stellar/pools: live wrapper quotes (checkpoint fallback) and provider APY that is null once expired.\n","parameters":[{"name":"address","in":"path","required":true,"description":"Stellar account (G…) or contract (C…) strkey.","schema":{"type":"string"}}],"responses":{"200":{"description":"Markets where the holder has PT or YT balance."},"400":{"description":"Not a valid Stellar address."},"500":{"description":"Upstream Soroban RPC or configuration error."},"503":{"description":"Stellar support is not enabled in this deployment."}}}},"/v1/stellar/pt/{address}":{"get":{"tags":["Stellar"],"summary":"Get one Stellar PT market by contract address","description":"USD tvl.sourceAsOf is the oldest exact simulation-ledger/quote timestamp; observedAt is the latest input, and observationId identifies that evidence. network is stellar:pubnet or stellar:testnet only after the RPC network matches the configured simulation passphrase. quality is fresh, stale, missing or unverified. Fresh requires complete evidence within 15 minutes, allowing 60 seconds of forward clock skew; clients must recheck source age. Unverified or missing observations have null observedAt and observationId. Missing means USD cannot be valued, not that underlying TVL is unavailable. Per-read cache aging preserves source times and applies on all Stellar routes. Low-confidence prices remain displayable but unverified. EURC quotes may exceed the 15-minute window between provider updates and appear stale.\n","parameters":[{"name":"address","in":"path","required":true,"description":"PT contract id (C… strkey).","schema":{"type":"string"}}],"responses":{"200":{"description":"The market in the Future shape (+ tradable flag)."},"400":{"description":"Not a valid Stellar contract/account address."},"404":{"description":"No registered market at this address."},"500":{"description":"Upstream Soroban RPC or configuration error."},"503":{"description":"Stellar support is not enabled in this deployment."}}}},"/v1/vision/{network}":{"get":{"summary":"Get latest APRs for a given network","description":"Returns the latest APRs for a given network","tags":["Vision"],"parameters":[{"in":"path","name":"network","required":true,"schema":{"type":"string"},"description":"The network to get APRs for (e.g. mainnet, base)"},{"in":"query","name":"tokens","required":true,"schema":{"type":"string"},"description":"Comma-separated list of token addresses to get APRs for"}],"responses":{"200":{"description":"Latest APRs","content":{"application/json":{"schema":{"type":"object","properties":{"apr":{"type":"object","properties":{"[ tokenAddress ]":{"type":"string","description":"The latest APR for the given token"},"timestamp":{"type":"string","description":"The timestamp of the latest APR"}}}},"example":{"0xad55aebc9b8c03fc43cd9f62260391c13c23e7c0":"3.796"}}}}},"400":{"description":"Invalid network or missing tokens","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/v2/bridge-paths/dictionary":{"get":{"summary":"Protocol-level bridge-path decoder dictionary (info-only)","description":"Returns every `(srcChainId → dstChainId)` route the protocol\nsupports for the CCTP+USDC scope (V2.1.0), along with the\n`keccak256(bridgeInterface, tokenIn, dstChainId, tokenOut)` key\neach row would have on ANY vault's registry. Independent of any\nspecific vault — purely a decoder dictionary used to translate\nopaque registry-row hashes back into a human-readable shape.\n\nWrapper addresses per chain are resolved at request time from\neach chain's `core.bridge.cctp` global registry entry. Chains\nmissing that entry are dropped from the result.\n","tags":["Permissions"],"parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1}},{"name":"pageSize","in":"query","required":false,"schema":{"type":"integer","default":50}}],"responses":{"200":{"description":"Paginated dictionary entries."}}}},"/v2/capabilities/schema":{"get":{"summary":"Capability kind schemas","description":"Machine-readable description of every supported capability kind so\nfrontend developers can auto-generate input forms instead of\nhand-authoring one per kind.\n\nEach entry carries `{ kind, description, fields[] }` where every\nfield has `{ name, type, required, description? }`. Lightweight on\npurpose — no JSON-Schema runtime, just a stable shape that tracks\nthe `Capability` discriminator in the SDK.\n\nBuild-time-static — cached for 1 hour via `Cache-Control`.\n","tags":["Capabilities"],"responses":{"200":{"description":"List of capability kinds"}}}},"/v2/capability":{"post":{"summary":"Plan routes for a vault capability or function-call intent","description":"Capability- and intent-driven routing entry point. The caller submits\nexactly one of:\n\n  - `capability` — single high-level capability (configurator,\n    template.apply, role.assign, vault.settle, etc.).\n  - `capabilities` — list of capabilities planned as\n    all-or-nothing bundled route alternatives when the list has\n    multiple items.\n  - `intent` — single function-call intent `{ target, selector,\n    calldata, value?, operation? }`. Shorthand for a one-element\n    `intents` list.\n  - `intents` — list of function-call intents. Each intent is routed\n    independently, then multi-item lists are submitted only through\n    a bundle that carries the whole list.\n  - `multiSend` — pre-encoded Safe `multiSend(bytes)` calldata\n    blob. The validator unwraps the inner actions into a list of\n    function-call intents before routing. The outer selector must\n    equal `0x8d80ff0a`. Every signable route must carry all inner\n    actions; otherwise `bundled` is `null`, `fullyEligible` is\n    `false`, and no split route is exposed for signing.\n\nRole transport derivation. For Mode A (`intent` / `intents`) and\nMode B (`multiSend`) the planner derives the\n`(rolesModifier, roleKey)` transport from the snapshot's scope\ngraph — the caller never names the role. Mode C\n(`capability: { kind: \"raw\" }`) is the explicit-transport escape\nhatch where the caller specifies `rolesModifier` directly; the\nplanner still validates that the caller's role scopes the call.\n\nAll five modes are mutually exclusive. The response shape is\n`{ routes, unmet, atomicityResult, rationale, evidence }` where\n`routes[].bundle` is `Operation[]`. List-based modes (`capabilities`,\n`intents`, `multiSend`) additionally return a `list` field carrying\nthe bundled / per-item routes. `evidence.status` is `verified-live`,\n`last-known-good`, or `unverified`. Under the default advisory policy,\nunavailable live evidence keeps constructable routes actionable and\nannotated; deterministic on-chain rejection still disables a route.\n","tags":["Permissions"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chainId","vault","caller"],"properties":{"chainId":{"type":"integer"},"vault":{"type":"string","description":"0x-prefixed Safe / vault address."},"caller":{"type":"string","description":"0x-prefixed caller EOA used to derive the CallerContext."},"capability":{"type":"object","description":"A single Capability discriminator. Mutually exclusive with capabilities/intent/intents/multiSend."},"capabilities":{"type":"array","items":{"type":"object"},"description":"List of Capabilities. Mutually exclusive with capability/intent/intents/multiSend."},"intent":{"type":"object","description":"Single FunctionCallIntent — `{ target, selector, calldata, value?, operation? }`. `selector` MUST equal the first 4 bytes of `calldata`. `value` is a decimal string (omit for zero). `operation` is 0 (Call) or 1 (DelegateCall). Mutually exclusive with the other four modes.","properties":{"target":{"type":"string","description":"0x-prefixed 20-byte contract address."},"selector":{"type":"string","description":"0x-prefixed 4-byte function selector. Must equal `calldata.slice(0, 10)`."},"calldata":{"type":"string","description":"0x-prefixed even-length hex string (ABI-encoded calldata)."},"value":{"type":"string","description":"Optional decimal string for ETH value in wei."},"operation":{"type":"integer","enum":[0,1],"description":"Optional — 0 (Call, default) or 1 (DelegateCall)."}}},"intents":{"type":"array","items":{"type":"object"},"description":"List of FunctionCallIntents (same shape as `intent`). Mutually exclusive with the other four modes."},"multiSend":{"type":"object","description":"Pre-encoded Safe `multiSend(bytes)` blob. Mutually exclusive with the other four modes. Multi-item inners are planned as one all-or-nothing bundle.","properties":{"calldata":{"type":"string","description":"0x-prefixed hex calldata starting with the `multiSend(bytes)` selector `0x8d80ff0a`."}}},"atomicity":{"type":"string","enum":["strict","best-effort"],"default":"best-effort","description":"Single-capability atomicity hint."},"guardianFastPath":{"type":"boolean","description":"Opt-in — when true the planner ranks the no-Delay direct path higher than the queued path for guardian capabilities (e.g. `queue.cancel`)."},"preferRole":{"type":"string","description":"Soft ranking hint. Eligible routes whose transport role matches `preferRole` are surfaced first. Does NOT affect eligibility, only the order of `routes[]`. Forwarded by the CLI's `--prefer-role X` flag."},"isSafeProposer":{"type":"boolean","description":"Caller-side flag — true when the caller has Safe Tx Service propose rights but is NOT an on-chain Safe owner. The proposer allowlist lives off-chain in the Safe Tx Service and cannot be derived from the vault snapshot, so the API accepts the flag verbatim from the CLI/UI. When set (and the caller is not a Safe owner) the planner surfaces a `safe-propose`-tagged route in the Safe fallback ladder for callers who would otherwise get no route on rolesMod-unscoped calls."}}}}}},"responses":{"200":{"description":"Routing result (routes + unmet + atomicityResult + rationale + evidence). Each route's `bundle` is `Operation[]`. List modes additionally include a `list` field."},"400":{"description":"Malformed body"},"422":{"description":"A required template registry global is not configured"},"500":{"description":"Snapshot fetch or planning failure"},"503":{"description":"Enforced policy only — snapshot, template registry state, or exact route execution could not be verified"}}}},"/v2/catalog":{"get":{"summary":"Dashboard-ready vault catalog (Phase 5)","description":"Returns the `Catalog` projection of a vault — identity, phase,\npipelines + role memberships, registry K/V, and audit summary\n(mandatory invariants + consistency findings).\n\nTwo modes:\n  - default: one-shot JSON response.\n  - `subscribe=true`: upgrades to Server-Sent Events. The connection\n    emits a `vault-changed` event whenever the data layer's durable\n    change feed (`dl_cache_changes`) records a change for the\n    subscribed vault. Each event carries the freshly-computed Catalog\n    projection.\n","tags":["Permissions"],"parameters":[{"in":"query","name":"chainId","required":true,"schema":{"type":"integer"}},{"in":"query","name":"vault","required":true,"schema":{"type":"string","description":"0x-prefixed Safe / vault address"}},{"in":"query","name":"subscribe","required":false,"schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Catalog JSON or SSE stream"},"400":{"description":"Invalid query"},"500":{"description":"Snapshot fetch failure"}}}},"/v2/metavaults/{chainId}/{address}/activity":{"get":{"description":"Vault Activity surface — currently-queued Delay-module items\n(`pending`) plus executed transaction history across the cluster\n(`history`, fanned across home + remotes via the metavaults\nsubgraph's `MetavaultTransaction` entity). Pending data is also\ncarried on the main detail endpoint; this endpoint pairs it with\nthe history stream so the per-vault Activity page is a single\nfetch.\n","tags":["Metavaults v2"],"parameters":[{"in":"path","name":"chainId","required":true,"schema":{"type":"integer"}},{"in":"path","name":"address","required":true,"schema":{"type":"string","description":"0x-prefixed Safe / vault address"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","default":100,"maximum":1000}},{"in":"query","name":"before","description":"Unix-seconds cursor — return entries older than this.","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Activity payload"},"400":{"description":"Invalid chainId or address"},"404":{"description":"Metavault not found"}}}},"/v2/metavaults/{chainId}/{address}/audit":{"get":{"summary":"Per-vault audit — mandatory invariants + consistency checks","description":"Returns the audit findings for a vault as two independent lists:\n\n  - `mandatoryViolations`: derived from templates flagged\n    `mandatoryFor: true`. Anything in this list is a hard\n    \"vault not healthy\" finding and carries canonical\n    `severity: \"error\"`.\n  - `consistencyFindings`: vault-internal coherence checks with\n    severity error / warning / info. The list may contain\n    `severity: \"warning\"` entries that don't break health.\n\nCanonical pure projection over `VaultSnapshot` plus resolved template\nevidence — the same inputs produce the same audit on every surface.\n","tags":["Permissions"],"parameters":[{"in":"path","name":"chainId","required":true,"schema":{"type":"integer"}},{"in":"path","name":"address","required":true,"schema":{"type":"string","description":"0x-prefixed Safe / vault address"}}],"responses":{"200":{"description":"Audit findings JSON"},"400":{"description":"Invalid params"},"500":{"description":"Snapshot fetch failure"}}}},"/v2/metavaults/{chainId}/{address}/bridges":{"get":{"description":"Full cross-chain bridge transaction history for a MetaVault cluster\n(CCTP transfers, all statuses) plus rolling USD totals. Pending\ntransfers also surface as `allocations` on the detail endpoint; this\nendpoint is the complete ledger, including settled (`completed`)\ntransfers.\n","tags":["Metavaults v2"],"parameters":[{"in":"path","name":"chainId","required":true,"schema":{"type":"integer"}},{"in":"path","name":"address","required":true,"schema":{"type":"string","description":"0x-prefixed Safe / vault address"}}],"responses":{"200":{"description":"Bridge transaction history"},"400":{"description":"Invalid chainId or address"},"404":{"description":"Metavault not found"}}}},"/v2/metavaults/{chainId}/{address}/configuration":{"get":{"description":"Per-network configuration for a MetaVault cluster.","tags":["Metavaults v2"],"responses":{"200":{"description":"Main and trusted remote configuration"},"400":{"description":"Invalid chainId or address"},"503":{"description":"Cluster configuration unavailable"}}}},"/v2/metavaults/{chainId}/{address}/curator-membership/preview":{"post":{"description":"Compare one final curator list with every live network. A versioned deferred review is required before executable routes can be planned.","tags":["Metavaults v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["caller","members","planning"],"properties":{"caller":{"type":"string"},"members":{"type":"array","maxItems":100,"items":{"type":"string"}},"isSafeProposer":{"type":"boolean"},"planning":{"type":"object","properties":{"version":{"type":"integer","enum":[1]},"mode":{"type":"string","enum":["deferred","reviewed"]},"reviewDigest":{"type":"string"},"operationReview":{"type":"object","properties":{"chainId":{"type":"integer"},"vault":{"type":"string"},"digest":{"type":"string"}}}}}}}}}},"responses":{"200":{"description":"Per-network curator reconciliation before planning"},"400":{"description":"Invalid request"},"503":{"description":"Cluster state could not be verified"}}}},"/v2/metavaults/{chainId}/{address}/curator-membership":{"get":{"description":"Live curator roster across the main vault and its trusted remotes.","tags":["Metavaults v2"],"responses":{"200":{"description":"Per-network and cluster-wide curator members"},"400":{"description":"Invalid chainId or address"},"503":{"description":"Cluster state could not be verified"}}}},"/v2/metavaults/{chainId}/{address}/diff":{"get":{"summary":"Event delta between two blocks","description":"Returns the canonical events for a vault between `from` (inclusive)\nand `to` (inclusive). Unlike `/history`, this endpoint is bounded\nby the explicit window and does not paginate — the caller picks a\nnarrow window. Useful for reconstruction and auditing.\n","tags":["MetaVaults Live"],"parameters":[{"name":"chainId","in":"path","required":true,"schema":{"type":"integer"}},{"name":"address","in":"path","required":true,"schema":{"type":"string"}},{"name":"from","in":"query","required":true,"schema":{"type":"integer"}},{"name":"to","in":"query","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Events between `from` and `to`."},"400":{"description":"Invalid params or range too large."}}}},"/v2/metavaults/{chainId}/{address}/guardian-membership/preview":{"post":{"description":"Compare one final guardian list with every live network and plan one strict update per network.","tags":["Metavaults v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["caller","members"],"properties":{"caller":{"type":"string"},"members":{"type":"array","maxItems":100,"items":{"type":"string"}},"isSafeProposer":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Per-network guardian reconciliation and routes"},"400":{"description":"Invalid request"},"503":{"description":"Cluster state could not be verified"}}}},"/v2/metavaults/{chainId}/{address}/guardian-membership":{"get":{"description":"Live guardian roster across the main vault and its trusted remotes.","tags":["Metavaults v2"],"responses":{"200":{"description":"Per-network and cluster-wide guardian members"},"400":{"description":"Invalid chainId or address"},"503":{"description":"Cluster state could not be verified"}}}},"/v2/metavaults/{chainId}/{address}/history":{"get":{"summary":"Paginated event-log query for a vault","description":"Returns the canonical event log for a vault, ordered by\n(block_number, log_index). Supports pagination via `afterId`\ncursor and filtering by event kind, block range, and page size.\n","tags":["MetaVaults Live"],"parameters":[{"name":"chainId","in":"path","required":true,"schema":{"type":"integer"}},{"name":"address","in":"path","required":true,"schema":{"type":"string"}},{"name":"fromBlock","in":"query","schema":{"type":"integer"}},{"name":"toBlock","in":"query","schema":{"type":"integer"}},{"name":"kind","in":"query","schema":{"type":"string"},"description":"Repeatable. Filter to one or more EventKinds."},{"name":"afterId","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer","maximum":500}}],"responses":{"200":{"description":"Page of events."},"400":{"description":"Invalid params."}}}},"/v2/metavaults/{chainId}/{address}/permissions":{"get":{"description":"Installed templates and ungrouped raw ops for a MetaVault and every\nremote Safe it declares. Each Safe's snapshot runs the matcher\npipeline + toPermissionsData projector; `chains` lists the chains\nactually read (a remote that fails is a warning, not a chain).\n`members` is the home Safe's.\n","tags":["Metavaults v2"],"parameters":[{"in":"path","name":"chainId","required":true,"schema":{"type":"integer"}},{"in":"path","name":"address","required":true,"schema":{"type":"string","description":"0x-prefixed Safe / vault address"}}],"responses":{"200":{"description":"Permissions snapshot"},"400":{"description":"Invalid chainId or address"},"404":{"description":"Metavault not found"}}}},"/v2/metavaults/{chainId}/{address}/role-membership/{role}/preview":{"post":{"description":"Compare one final accountant or configurator list with every live network and plan one strict update per network.","tags":["Metavaults v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["caller","members"],"properties":{"caller":{"type":"string"},"members":{"type":"array","maxItems":100,"items":{"type":"string"}},"isSafeProposer":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Per-network role reconciliation and routes"},"400":{"description":"Invalid request"},"503":{"description":"Cluster state could not be verified"}}}},"/v2/metavaults/{chainId}/{address}/role-membership/{role}":{"get":{"description":"Live accountant or configurator roster across the main vault and its trusted remotes.","tags":["Metavaults v2"],"responses":{"200":{"description":"Per-network and cluster-wide role members"},"400":{"description":"Invalid chainId","address":null,"or role":null},"503":{"description":"Cluster state could not be verified"}}}},"/v2/metavaults/{chainId}/{address}":{"get":{"description":"Single MetaVault detail (v2). Identified by (chainId, address).","tags":["Metavaults v2"],"parameters":[{"in":"path","name":"chainId","required":true,"schema":{"type":"integer"}},{"in":"path","name":"address","required":true,"schema":{"type":"string","description":"0x-prefixed Safe / vault address"}}],"responses":{"200":{"description":"MetaVault detail"},"400":{"description":"Invalid chainId or address"},"404":{"description":"MetaVault not found"}}}},"/v2/metavaults/{chainId}/{address}/safe-governance/preview":{"post":{"description":"Compare one final Safe owner list and threshold with every live network and plan one atomic update per network.","tags":["Metavaults v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["caller","owners","threshold"],"properties":{"caller":{"type":"string"},"owners":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string"}},"threshold":{"type":"integer","minimum":1},"isSafeProposer":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Per-network Safe governance reconciliation and routes"},"400":{"description":"Invalid request"},"503":{"description":"Cluster state could not be verified"}}}},"/v2/metavaults/{chainId}/{address}/snapshot":{"get":{"summary":"Vault snapshot at a target block (time-travel)","description":"Returns a {@link VaultSnapshot} reconstructed AS OF the requested\nblock. The substrate loads the latest keyframe ≤ block and replays\nevents forward. It returns 409 rather than substituting current state\nwhen the target cannot be reconstructed exactly. Without `asOf`,\nreturns the latest snapshot through the data layer.\n","tags":["MetaVaults Live"],"parameters":[{"name":"chainId","in":"path","required":true,"schema":{"type":"integer"}},{"name":"address","in":"path","required":true,"schema":{"type":"string"}},{"name":"asOf","in":"query","schema":{"type":"integer"},"description":"Block number for time-travel reconstruction."}],"responses":{"200":{"description":"Snapshot returned."},"400":{"description":"Invalid params."},"409":{"description":"Exact historical snapshot unavailable."}}}},"/v2/metavaults/{chainId}/{address}/swap-config":{"get":{"description":"The vault's live aggregator-swap configuration, read from the\nDECODED on-chain condition trees (not from template detection —\nthe `curator-1inch-swap` switch template is invisible to the\nsignature matcher, and the live tree is the truth regardless of\nhow the grant was applied). One entry per supported aggregator\nprovider; `installed` is fail-closed — true only when the\ngrant pins the output receiver to the Safe and carries a closed\nasset set of at least two tokens.\n\nConsumed by the curator-app Swap module to populate its token\npickers and gate the form.\n","tags":["Metavaults v2"],"parameters":[{"name":"chainId","in":"path","required":true,"schema":{"type":"integer"}},{"name":"address","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Swap provider configuration"},"400":{"description":"Invalid chainId or address"},"500":{"description":"Snapshot read failure"}}}},"/v2/metavaults/audit":{"get":{"summary":"Audit the `scope=global` registry coverage across every supported chain","description":"For every `SUPPORTED_CHAIN_IDS` member, lists which `scope=global`\nregistry keys (e.g. `core.factory`, the Spectra zaps, the\ncanonical implementation addresses) are written on-chain vs.\nmissing. Missing keys are split into:\n\n  - `missingRequired` — load-bearing. A chain with any required\n    key missing cannot host a fresh metavault deploy. Flips\n    `healthy: false`.\n  - `missingOptional` — feature-gated. CCTP / DeBridge / Dutch\n    auction / receiver lock guard. A chain can be considered\n    fully configured even when these are absent — they only need\n    to be written on chains where those features are deployed.\n\nChains whose subgraph endpoint cannot be read surface as `error`.\nThey make the global verdict `unknown` and keep `healthy: false`;\nunavailable evidence is never treated as successful coverage.\n\nImplementation: each chain probe is one batched subgraph query\n(`resolveAllGlobals`). The 13 probes run in parallel; wall time\nis bounded by the slowest subgraph response. Not cached.\n\nConsumers: ops dashboards, the `mv audit` CLI command.\n","tags":["Metavaults v2"],"responses":{"200":{"description":"Coverage matrix returned. Inspect `verdict`; `healthy` is retained for compatibility."}}}},"/v2/metavaults/compile-deploy":{"post":{"description":"Compile a metavault deployment intent into a single broadcast-ready\ntransaction `{ to, data, value }`. The caller signs and submits this\ntransaction with their wallet — the endpoint never touches a chain or\na signer.\n\nWith `kind:\"main\"` or no `kind`, emits a Portofino-shaped pipeline\n(Safe + Vault + Roles + Delay + ZodiacManagement + Metadata). The\noptional `timings` body field overrides per-pipeline cooldown/expiry\nand can skip the default delay (`default.includeDelay:false` →\nroles-default routes straight to the Safe) or the whole management\npipeline (`management.include:false`). Omit `timings` to accept the\ndefaults (both delays use a 72h cooldown and 14d expiry).\n`safe.mode:\"new\"` creates a Safe with the supplied owners and threshold;\n`safe.mode:\"existing\"` omits the Safe step and extends the supplied Safe.\nOmitting `safe` keeps the canonical Spectra DAO signer defaults for\nbackwards compatibility. Other fields fall back to defaults that mirror\nthe reference fixture at\n`packages/spectra-sdk/metavaults/factory/__tests__/compileDeployment.spec.ts`.\n\nWith `kind:\"remote\"`, emits the remote-only factory preset: Safe +\ndefault RolesModifier + default Delay + management pipeline. It does\nnot deploy a vault/wrapper, metadata, or seed transaction.\n","tags":["Metavaults v2"],"responses":{"200":{"description":"Compiled deployment with calldata + decoded summary"},"400":{"description":"Invalid body"}}}},"/v2/metavaults/portfolio/{address}":{"get":{"description":"A user's MetaVault (v2) positions with per-user ERC-7540 request state.\nHybrid, user-first: one `metavaultHolders` query per configured chain\nyields the held HOME rows, which are aggregated + compiled (remotes\nsynthesized from metadata — no remote-row fetch), then an on-chain\nmulticall provides authoritative balances / claimable amounts. Never\ncalls getAllMetavaults (no all-chain fan-out per vault).\nEvery position carries `addressStatus` (contract address registry\nstatus of the vault: denylist, own entry, else its factory's when the\nfactory passes its status on, otherwise unsafe) and `exitOnly` (true\nwhen the address gate hides the vault from public lists; the position\nis kept, exit actions only).\n","tags":["Metavaults v2"],"parameters":[{"in":"path","name":"address","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Portfolio MetaVault positions"},"400":{"description":"Invalid address"}}}},"/v2/metavaults":{"get":{"description":"Cross-chain list of MetaVaults (v2). Permission-derived\nallocations from the registry layer + Spectra/Pendle/Avant adapters.\n\nBy default only returns vaults that are publicly ready: phase\n`production`, at least one curator, and at least one settled epoch\n(i.e. seeded). Pass `status=all` to bypass that filter — used by\nthe curator app's Dashboard to show vaults still in setup that the\nconnected wallet owns.\n\nThe `member` filter matches against `roles[*].addresses` across\nevery role on the vault. A wallet that's only the deploy-time\nconfigurator (still in setup) will be found by the same query.\n","tags":["Metavaults v2"],"parameters":[{"in":"query","name":"network","schema":{"type":"string"},"description":"Comma-separated chain slugs (e.g. \"base,mainnet\"). Omit for all."},{"in":"query","name":"member","schema":{"type":"string"},"description":"Filter to vaults where the address is a member of any role\n(curator, configurator, accountant, guardian, …). Matches the\nlowercase 0x form returned by the API. If role data is degraded\nor incomplete, the vault stays in the response with a warning\ninstead of being treated as a known non-match.\n"},{"in":"query","name":"underlying","schema":{"type":"string"},"description":"Filter by underlying symbol (e.g. \"USDC\")."},{"in":"query","name":"status","schema":{"type":"string","enum":["public","all"]},"description":"`public` (default) returns only production-phase, seeded vaults\nwith a curator. `all` bypasses the readiness filter — use for\nauthenticated dashboards that need to surface in-setup vaults.\n"}],"responses":{"200":{"description":"MetaVaults list"}}}},"/v2/metavaults/seed-compile":{"post":{"deprecated":true,"description":"**Deprecated.** Use `POST /v2/capability` with a `vault.seed`\ncapability instead — that endpoint plans the Safe-owner,\nsafe-propose, AND configurator two-phase paths in one call. This\nhandler is kept temporarily for back-compat while the curator UI\nfinishes migrating; it will be removed in a follow-up release.\n\nCompile a single-step `SEED_VAULT` factory call into broadcast-ready\ncalldata. The caller dispatches the resulting `{to, data, value}`\nthrough their vault Safe (the factory is `OnlySafe`-gated and was\nleft enabled as a Safe module after the original deploy precisely\nfor this kind of follow-up step).\n\nOn-chain effect, executed atomically by the Safe in Phase 3 of the\nfactory's pipeline (see `metavaults-V1/src/factory/deployers/SeedVaultDeployer.sol`):\n  1. underlying.approve(vault, seedAmount)\n  2. vault.deposit(seedAmount, safe)\n  3. vault.close()  — closes the first epoch\n\nThe deployer resolves the vault address via the registry fallback\n(`registry.getAddress(safe, keccak256(\"core.vault\"))`), so this\nworks against any already-deployed vault whose `core.vault` entry\nis registered and whose Safe still owns the vault.\n","tags":["Metavaults v2"],"responses":{"200":{"description":"Compiled seed call calldata"},"400":{"description":"Invalid body"},"502":{"description":"core.factory unresolved on the target chain"}}}},"/v2/permissions/templates/active":{"get":{"summary":"Per-role applied templates + queue-aware OperationDiff","description":"Hybrid response combining three sources:\n  - the `Catalog` snapshot (authoritative for confirmed state),\n  - the LiveLog `vault_events` table (optimistic / pending state),\n  - the per-pipeline Delay queue (computed live by the SDK's\n    `Diff` engine).\n\nEach role entry carries the matcher's confirmed `appliedTemplates`\n(F-04 shape), the LiveLog's pending `template.applied` events\n(status: pending | confirmed | unconfirmed | failed), and an\n`OperationDiff` that surfaces what changes when the queue executes.\n\nUI consumers render this as the \"active templates\" panel — one\nper role, with a colour-coded badge per template instance.\n","tags":["Permissions"],"parameters":[{"in":"query","name":"chainId","required":true,"schema":{"type":"integer"}},{"in":"query","name":"vault","required":true,"schema":{"type":"string","description":"0x-prefixed Safe / vault address"}}],"responses":{"200":{"description":"Active templates response"},"400":{"description":"Invalid query"},"500":{"description":"Snapshot fetch failure"}}}},"/v2/permissions/templates":{"get":{"description":"Catalog of installable permission templates. Each template is the\nunit a curator adds via POST /permissions/compile. Mirrors\nlistTemplates() from the public SDK registry.\n\nThe response carries an `ETag` derived from a 16-char content hash of\nthe body so clients can short-circuit subsequent requests via\n`If-None-Match → 304 Not Modified` (ported from the now-consolidated\nstandalone templates route). Cached via\n`Cache-Control: public, s-maxage=300, stale-while-revalidate=600`.\n","tags":["Metavaults v2"],"parameters":[{"name":"If-None-Match","in":"header","required":false,"schema":{"type":"string"},"description":"Previously-seen ETag — request returns 304 when matched."}],"responses":{"200":{"description":"Template catalog"},"304":{"description":"Not modified — client cache is up to date."}}}},"/v2/registry/{chainId}/{vault}/{key}":{"get":{"summary":"Read a typed registry value for a vault","description":"Returns the typed value stored under `key` for `vault` in the\nMetaVaultsRegistryV2 on `chainId`.\n\nResolution order:\n  1. Look up the value in the latest snapshot's `registry` slice\n     (assembled by the snapshot cache + `fetchVaultSnapshot`). When\n     present, the response is served from cache without an extra\n     RPC round-trip.\n  2. Fall back to a direct viem `readContract` call when the\n     snapshot has no row for the key. Requires\n     `?registryAddress=0x…` so the route can target the right\n     contract.\n\nWrites go through `POST /v2/capability` with\n`kind: \"registry.write\"` — there is no write route here.\n","tags":["MetaVaults Registry"],"parameters":[{"name":"chainId","in":"path","required":true,"schema":{"type":"integer"}},{"name":"vault","in":"path","required":true,"schema":{"type":"string"}},{"name":"key","in":"path","required":true,"schema":{"type":"string"},"description":"Either a 32-byte hex bytes32 (pre-hashed) or the human-readable key name (hashed server-side)."},{"name":"valueType","in":"query","schema":{"type":"string","enum":["STRING","ADDRESS","UINT256","BYTES","BOOL"]}},{"name":"registryAddress","in":"query","schema":{"type":"string"},"description":"Optional registry address; required when the snapshot does not carry the key."}],"responses":{"200":{"description":"Value retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"value":{"type":"string","description":"Typed value (string/address/decimal-uint/hex-bytes/bool string)."},"valueType":{"type":"string"},"isLocked":{"type":"boolean"},"lastUpdatedBlock":{"type":"string","description":"Decimal bigint"},"source":{"type":"string","enum":["snapshot","rpc"]}}}}}},"400":{"description":"Invalid input"},"404":{"description":"Key not set"},"500":{"description":"Read failure"}}}},"/v2/status":{"get":{"summary":"Platform-wide data freshness","description":"Public, unauthenticated indexing status for the metavault data\nlayer: one line per chain (subgraph lag, heartbeat age) plus the\nsnapshot cache. Computed from Postgres only, memoised for 30s in\nprocess and cacheable for 30s at the edge.\n\nStatus levels: `ok`, `degraded` (a chain's subgraph is past the\nwarn lag), `outage` (a chain heartbeat is stale, a subgraph is\npast the critical lag, the snapshot cache is unhealthy, or the\naggregator itself is unreachable). Guardian notification\ndelivery is not part of this signal.\n","tags":["Health"],"responses":{"200":{"description":"Status computed (may still be degraded or outage)","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok","degraded","outage"]},"version":{"type":"string","description":"Short git commit of the deployed API","example":"abc1234"},"generatedAt":{"type":"string","format":"date-time"},"chains":{"type":"array","items":{"type":"object","properties":{"chainId":{"type":"integer","example":14},"name":{"type":"string","example":"Flare"},"status":{"type":"string","enum":["ok","degraded","outage"]},"subgraphLagSeconds":{"type":"integer","nullable":true},"subgraphLagBlocks":{"type":"integer","nullable":true},"heartbeatAgeSeconds":{"type":"integer","nullable":true},"reasons":{"type":"array","items":{"type":"string"}}}}},"snapshots":{"type":"object","properties":{"ok":{"type":"boolean"},"invalidatedRows":{"type":"integer"},"oldestInvalidatedAgeSeconds":{"type":"integer"}}}}}}}},"503":{"description":"Aggregator unreachable or timed out; body is an outage status"}}}},"/v2/webhooks/goldsky/{chain}/{source}":{"post":{"summary":"Goldsky webhook ingress","description":"HMAC-verified ingress for Goldsky subgraph entity webhooks. One\nendpoint per (chain × subgraph family) pair. The handler verifies the\nshared-secret/HMAC, maps the entity row to the same poll change shape\nthe cron backstop uses, applies the targeted cache effect, and returns\n200 in <200 ms.\n","tags":["Webhooks"],"parameters":[{"name":"chain","in":"path","required":true,"schema":{"type":"string"}},{"name":"source","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Entity change accepted, de-duped, or ignored."},"400":{"description":"Malformed payload or unknown chain/source."},"401":{"description":"HMAC verification failed."}}}}},"tags":[]}