{
  "openapi": "3.1.0",
  "info": {
    "title": "Loopscale API",
    "version": "0.1.0"
  },
  "servers": [
    {
      "url": "https://tars.loopscale.com/v1",
      "description": "Loopscale Production Server"
    }
  ],
  "paths": {
    "/markets/strategy/infos": {
      "post": {
        "tags": [
          "strategy_data"
        ],
        "summary": "Get Loopscale Strategies",
        "operationId": "route_get_strategy_info",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LendingStrategyFilter"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "List of strategies that match filter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiStrategyInfoResponse"
                }
              }
            }
          },
          "400": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "description": "Returns a list of strategy data matching the filters."
      }
    }
  },
  "components": {
    "schemas": {
      "ApiStrategyInfoResponse": {
        "type": "object",
        "required": [
          "items",
          "pageInfo",
          "aggregate",
          "snapshotTs"
        ],
        "properties": {
          "aggregate": {
            "$ref": "#/components/schemas/StrategiesAggregate"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StrategyDetail"
            }
          },
          "pageInfo": {
            "$ref": "#/components/schemas/PageInfo"
          },
          "snapshotTs": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "AssetTerms": {
        "type": "object",
        "required": [
          "durationAndApys",
          "allocationInfo"
        ],
        "properties": {
          "allocationInfo": {
            "$ref": "#/components/schemas/ParsedCollateralCaps"
          },
          "durationAndApys": {
            "type": "array",
            "items": {},
            "description": "Positional `[duration, apy]` pairs — a heterogeneous 2-tuple array, so it's\ntyped as an array of JSON values rather than a named element type."
          }
        }
      },
      "ErrorDetails": {
        "type": "object",
        "description": "Inner detail of the [`ErrorResponse`] envelope.",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "format": "int32",
            "description": "HTTP status code, mirrored in the response status line",
            "example": 400,
            "minimum": 0
          },
          "message": {
            "type": "string",
            "description": "human-readable, client-safe message (sensitive data redacted)",
            "example": "Request could not be processed."
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "description": "Canonical error envelope for every endpoint. The `x-request-id` response\nheader carries the correlation id for the failing request.",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorDetails",
            "description": "error detail"
          }
        }
      },
      "ExternalYieldInfo": {
        "type": "object",
        "required": [
          "externalYieldSource",
          "balance",
          "apy",
          "yieldAccount",
          "lastUpdateTime"
        ],
        "properties": {
          "apy": {
            "type": "string"
          },
          "balance": {
            "type": "string"
          },
          "externalYieldSource": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "lastUpdateTime": {
            "type": "integer",
            "format": "int64"
          },
          "yieldAccount": {
            "type": "string"
          }
        }
      },
      "LendingStrategyFilter": {
        "type": "object",
        "description": "lending strategy filter",
        "properties": {
          "addresses": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "collateralTermsAssetFilter": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "When non-empty on the summary endpoint, run a secondary query to fetch\n`terms.asset_terms` only for these collateral mints. Empty (default) =\n`terms.asset_terms` stays empty, no secondary query is run. Ignored by\nthe full `/strategy/infos` endpoint."
          },
          "overridePageSize": {
            "type": "boolean"
          },
          "page": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "pageSize": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "principalMints": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "showArchived": {
            "type": "boolean"
          },
          "sortDirection": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "sortType": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "userAddress": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "PageInfo": {
        "type": "object",
        "description": "Pagination envelope shared across paginated listing endpoints\n(`/loans/info`, `/strategy/infos`, `/loop/info/v2`, `/lending_vaults/user/v2`).\n`totalItems` / `totalPages` are filter-scoped, not page-scoped.",
        "required": [
          "page",
          "pageSize",
          "totalItems",
          "totalPages"
        ],
        "properties": {
          "page": {
            "type": "integer",
            "format": "int64",
            "description": "0-indexed page number echoed back from the request.",
            "minimum": 0
          },
          "pageSize": {
            "type": "integer",
            "format": "int64",
            "description": "Maximum item count per page applied by the server (may differ from\nthe request's `pageSize` if the request was 0 or above the cap).",
            "minimum": 0
          },
          "totalItems": {
            "type": "integer",
            "format": "int64",
            "description": "Total item count across the *filter* scope (not just this page).\nWhat \"item\" counts as depends on the endpoint — for grouped\nendpoints this is the count of distinct groups, not loans/rows.",
            "minimum": 0
          },
          "totalPages": {
            "type": "integer",
            "format": "int64",
            "description": "`ceil(totalItems / pageSize)`.",
            "minimum": 0
          }
        }
      },
      "ParsedCapMonitor": {
        "type": "object",
        "required": [
          "startTime1hr",
          "startTime24hr",
          "principal1hr",
          "principal24hr"
        ],
        "properties": {
          "principal1hr": {
            "type": "string"
          },
          "principal24hr": {
            "type": "string"
          },
          "startTime1hr": {
            "type": "string"
          },
          "startTime24hr": {
            "type": "string"
          }
        }
      },
      "ParsedCollateralCaps": {
        "type": "object",
        "required": [
          "maxAllocationPct",
          "currentAllocationAmount"
        ],
        "properties": {
          "currentAllocationAmount": {
            "type": "string"
          },
          "maxAllocationPct": {
            "type": "string"
          }
        }
      },
      "ParsedPrincipalCaps": {
        "type": "object",
        "description": "Parsed principal supply/borrow/withdraw caps: rolling 1h and 24h ceilings plus\nthe max concurrent outstanding, all in the principal mint's native units.",
        "required": [
          "max1hr",
          "max24hr",
          "maxOutstanding"
        ],
        "properties": {
          "max1hr": {
            "type": "string"
          },
          "max24hr": {
            "type": "string"
          },
          "maxOutstanding": {
            "type": "string"
          }
        }
      },
      "StrategiesAggregate": {
        "type": "object",
        "description": "Filter-scoped aggregate over the full matched strategy set. USD fields use\nthe request's pinned oracle snapshot. APYs are fractional (0.085 = 8.5%).\n\n`wAvgApy` and `expected24hInterestUsd` are **blended**: they include both\ndeployed-side interest (from `ledgers.apy`) and external-yield-side yield\n(from `external_yield_vaults.apy`). Idle principal sitting in the strategy's\ntoken account contributes to `strategyBalanceUsd` and drags the weighted\naverage with an implicit 0% APY, matching realized-yield semantics.\n\nStrategies are lender-side only — no role ambiguity; `expected24hInterestUsd`\nalways represents accrual to the lender.",
        "required": [
          "count",
          "principalDeployedUsd",
          "strategyBalanceUsd",
          "totalSupplyUsd",
          "interestAccruedUsd",
          "interestEarnedAllTimeUsd",
          "wAvgApy",
          "expected24hInterestUsd"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "format": "int64",
            "description": "Number of strategies folded into this aggregate.",
            "minimum": 0
          },
          "expected24hInterestUsd": {
            "type": "number",
            "format": "double",
            "description": "Projected 24h interest in USD — computed off the unrounded weighted\nAPY numerator, so it reconciles with the displayed `wAvgApy` within a\nfraction of a bp. Lender-side accrual."
          },
          "interestAccruedUsd": {
            "type": "number",
            "format": "double",
            "description": "Currently-outstanding deployed interest accrued by ledgers, in USD."
          },
          "interestEarnedAllTimeUsd": {
            "type": "number",
            "format": "double",
            "description": "Lifetime interest earned by the lender, read directly from on-chain\n`strategy.cumulative_interest_accrued` summed across the group and\npriced at the snapshot. Independent of `interestAccruedUsd` (which is\nonly the *currently outstanding* leg)."
          },
          "principalDeployedUsd": {
            "type": "number",
            "format": "double",
            "description": "Deployed-side principal in USD — `SUM(principal_due − principal_repaid)`\nacross active ledgers, priced at the snapshot."
          },
          "strategyBalanceUsd": {
            "type": "number",
            "format": "double",
            "description": "Idle-side principal in USD — strategy token-account balance plus\nexternal-yield-vault balance, priced at the snapshot."
          },
          "totalSupplyUsd": {
            "type": "number",
            "format": "double",
            "description": "`principalDeployedUsd + strategyBalanceUsd` — total lender supply."
          },
          "wAvgApy": {
            "type": "number",
            "format": "double",
            "description": "Blended USD-weighted APY: deployed-side (from `ledgers.apy`) plus\nexternal-yield-side (from `external_yield_vaults.apy`). Idle in the\ntoken account contributes at an implicit 0%. Weighting key is\n`totalSupplyUsd`."
          }
        }
      },
      "Strategy": {
        "type": "object",
        "required": [
          "address",
          "version",
          "nonce",
          "bump",
          "principalMint",
          "tokenBalance",
          "lender",
          "originationsEnabled",
          "externalYieldSource",
          "interestPerSecond",
          "lastAccruedTimestamp",
          "liquidityBuffer",
          "interestFee",
          "principalFee",
          "originationFee",
          "originationCap",
          "externalYieldAmount",
          "currentDeployedAmount",
          "outstandingInterestAmount",
          "feeClaimable",
          "cumulativePrincipalOriginated",
          "cumulativeInterestAccrued",
          "cumulativeLoanCount",
          "activeLoanCount",
          "marketInformation",
          "closed",
          "lastInteractedTime",
          "lastInteractedTxn",
          "createdAt",
          "writeVersion",
          "supplyCap1hrPeriodStart",
          "supplyCap24hrPeriodStart",
          "supplyCap1hrAmount",
          "supplyCap24hrAmount",
          "borrowCap1hrPeriodStart",
          "borrowCap24hrPeriodStart",
          "borrowCap1hrAmount",
          "borrowCap24hrAmount",
          "withdrawCap1hrPeriodStart",
          "withdrawCap24hrPeriodStart",
          "withdrawCap1hrAmount",
          "withdrawCap24hrAmount"
        ],
        "properties": {
          "activeLoanCount": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "borrowCap1hrAmount": {
            "type": "string"
          },
          "borrowCap1hrPeriodStart": {
            "type": "string"
          },
          "borrowCap24hrAmount": {
            "type": "string"
          },
          "borrowCap24hrPeriodStart": {
            "type": "string"
          },
          "bump": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "closed": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string"
          },
          "cumulativeInterestAccrued": {
            "type": "string"
          },
          "cumulativeLoanCount": {
            "type": "string"
          },
          "cumulativePrincipalOriginated": {
            "type": "string"
          },
          "currentDeployedAmount": {
            "type": "string"
          },
          "externalYieldAmount": {
            "type": "string"
          },
          "externalYieldSource": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "feeClaimable": {
            "type": "string"
          },
          "id": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "interestFee": {
            "type": "string"
          },
          "interestPerSecond": {
            "type": "number",
            "format": "double"
          },
          "lastAccruedTimestamp": {
            "type": "string"
          },
          "lastInteractedTime": {
            "type": "string"
          },
          "lastInteractedTxn": {
            "type": "string"
          },
          "lender": {
            "type": "string"
          },
          "liquidityBuffer": {
            "type": "string"
          },
          "marketInformation": {
            "type": "string"
          },
          "nonce": {
            "type": "string"
          },
          "originationCap": {
            "type": "string"
          },
          "originationFee": {
            "type": "string"
          },
          "originationsEnabled": {
            "type": "boolean"
          },
          "outstandingInterestAmount": {
            "type": "string"
          },
          "principalFee": {
            "type": "string"
          },
          "principalMint": {
            "type": "string"
          },
          "supplyCap1hrAmount": {
            "type": "string"
          },
          "supplyCap1hrPeriodStart": {
            "type": "string"
          },
          "supplyCap24hrAmount": {
            "type": "string"
          },
          "supplyCap24hrPeriodStart": {
            "type": "string"
          },
          "tokenBalance": {
            "type": "string"
          },
          "version": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "withdrawCap1hrAmount": {
            "type": "string"
          },
          "withdrawCap1hrPeriodStart": {
            "type": "string"
          },
          "withdrawCap24hrAmount": {
            "type": "string"
          },
          "withdrawCap24hrPeriodStart": {
            "type": "string"
          },
          "writeVersion": {
            "type": "string"
          }
        }
      },
      "StrategyDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/StrategyInfo"
          },
          {
            "type": "object",
            "required": [
              "principalDeployedUsd",
              "strategyBalanceUsd",
              "totalSupplyUsd",
              "interestAccruedUsd",
              "interestEarnedAllTimeUsd",
              "wAvgApy",
              "expected24hInterestUsd"
            ],
            "properties": {
              "expected24hInterestUsd": {
                "type": "number",
                "format": "double"
              },
              "interestAccruedUsd": {
                "type": "number",
                "format": "double"
              },
              "interestEarnedAllTimeUsd": {
                "type": "number",
                "format": "double"
              },
              "principalDeployedUsd": {
                "type": "number",
                "format": "double"
              },
              "strategyBalanceUsd": {
                "type": "number",
                "format": "double"
              },
              "totalSupplyUsd": {
                "type": "number",
                "format": "double"
              },
              "wAvgApy": {
                "type": "number",
                "format": "double"
              }
            }
          }
        ]
      },
      "StrategyInfo": {
        "type": "object",
        "required": [
          "strategy",
          "terms",
          "borrowCapMonitor",
          "supplyCapMonitor",
          "withdrawCapMonitor"
        ],
        "properties": {
          "borrowCapMonitor": {
            "$ref": "#/components/schemas/ParsedCapMonitor"
          },
          "externalYieldInfo": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ExternalYieldInfo"
              }
            ]
          },
          "strategy": {
            "$ref": "#/components/schemas/Strategy",
            "description": "Strategy account state (DB projection of the on-chain strategy)."
          },
          "supplyCapMonitor": {
            "$ref": "#/components/schemas/ParsedCapMonitor"
          },
          "terms": {
            "$ref": "#/components/schemas/StrategyTerms"
          },
          "withdrawCapMonitor": {
            "$ref": "#/components/schemas/ParsedCapMonitor"
          }
        }
      },
      "StrategyTerms": {
        "type": "object",
        "required": [
          "assetTerms",
          "supplyCaps",
          "borrowCaps",
          "withdrawCaps"
        ],
        "properties": {
          "assetTerms": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/AssetTerms"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "borrowCaps": {
            "$ref": "#/components/schemas/ParsedPrincipalCaps",
            "description": "Principal borrow caps (rolling 1h/24h + max outstanding)."
          },
          "supplyCaps": {
            "$ref": "#/components/schemas/ParsedPrincipalCaps",
            "description": "Principal supply caps (rolling 1h/24h + max outstanding)."
          },
          "withdrawCaps": {
            "$ref": "#/components/schemas/ParsedPrincipalCaps",
            "description": "Principal withdraw caps (rolling 1h/24h + max outstanding)."
          }
        }
      }
    }
  }
}
