philidor-io Stats API

The Stats API from philidor-io — 3 operation(s) for stats.

Operations 3

GET /v1/stats Platform-wide statistics #
GET /v1/stats/history Platform statistics time series #
GET /v1/stats/rating-dynamics Platform rating migration over time #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/philidor-io:philidor-io-stats-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

philidor-io-stats-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Philidor Io Stats API
  version: 1.2.0
  description: 'Operations tagged Stats across 2 of this provider''s published API definitions: philidor-openapi.json, philidor-io-openapi.json. Each path carries the servers of the definition it was published in.'
servers:
- url: https://api.philidor.io
  description: Production
- url: http://localhost:3003
  description: Local
tags:
- name: Stats
paths:
  /v1/stats:
    get:
      tags:
      - Stats
      summary: Platform-wide statistics
      description: 'Returns aggregate stats: TVL, vault count, risk distribution, TVL by protocol and chain.'
      responses:
        '200':
          description: Platform stats
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatsResponse'
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
        '429':
          description: Rate limit exceeded; retry after Retry-After seconds
          headers:
            Retry-After:
              $ref: '#/components/headers/Retry-After'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
      security:
      - {}
      - ApiKeyAuth: []
      operationId: getV1Stats
      parameters:
      - name: X-Request-Id
        in: header
        required: false
        schema:
          type: string
          pattern: ^[A-Za-z0-9_-]{1,64}$
        description: Optional correlation id, echoed unchanged when valid; otherwise a UUID is generated.
    servers:
    - url: https://api.philidor.io
      description: Production
    - url: http://localhost:3003
      description: Local
  /v1/stats/history:
    get:
      tags:
      - Stats
      summary: Platform statistics time series
      description: 'Daily platform aggregates for charting: total TVL, TVL by protocol and by chain, risk mix, active loans and utilization. One point per UTC day, oldest first. Same public read model as GET /v1/stats.


        Each point carries a `source`: `observed` points were captured live that day; `derived` points were reconstructed after the fact and have a null `riskDistribution`. The additive `reconstructed` flag further marks derived days that also include vaults Philidor was not yet observing, recovered from protocol-native history or archive on-chain reads — those answer "what was today''s covered book worth then", not "what Philidor covered then". Check both before presenting a point as a point-in-time record.'
      parameters:
      - schema:
          type: string
          enum:
          - 7d
          - 30d
          - 90d
          - 1y
          description: Preset window. Ignored when `days` is supplied.
          example: 30d
        required: false
        name: range
        in: query
      - schema:
          type: integer
          minimum: 1
          maximum: 420
          description: Explicit window in days (1–420). Takes precedence over `range`. The ceiling matches vault_snapshots retention (migration 129) — nothing older is recoverable.
        required: false
        name: days
        in: query
      - name: X-Request-Id
        in: header
        required: false
        schema:
          type: string
          pattern: ^[A-Za-z0-9_-]{1,64}$
        description: Optional correlation id, echoed unchanged when valid; otherwise a UUID is generated.
      responses:
        '200':
          description: Platform stats history
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatsHistoryResponse'
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
        '401':
          description: No credential, or an invalid one
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '403':
          description: The credential does not carry the required plan or role
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: Rate limit exceeded; retry after Retry-After seconds
          headers:
            Retry-After:
              $ref: '#/components/headers/Retry-After'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
      security:
      - ApiKeyAuth: []
      operationId: getV1StatsHistory
    servers:
    - url: https://api.philidor.io
      description: Production
    - url: http://localhost:3003
      description: Local
  /v1/stats/rating-dynamics:
    get:
      tags:
      - Stats
      summary: Platform rating migration over time
      description: 'Vault tier migration aggregated from the append-only rating-history ledger: upgrades, downgrades, net, and the transitions behind them.


        Three exclusions are load-bearing and reported as their own fields rather than folded into the headline. `methodologyReclassifications` are moves caused by a methodology version change — the ruler changed, not the risk. `newlyCovered` are first ratings, which have no prior tier to have moved from. `scoreOnlyChanges` are moves that stayed inside a tier.


        Counts are vaults, never TVL. See `meta.weighting`.'
      parameters:
      - schema:
          type: string
          enum:
          - 7d
          - 30d
          - 90d
          - 1y
          description: Preset window. Ignored when `days` is supplied.
          example: 30d
        required: false
        name: range
        in: query
      - schema:
          type: integer
          minimum: 1
          maximum: 420
          description: Explicit window in days (1–420). Takes precedence over `range`.
        required: false
        name: days
        in: query
      - schema:
          type: string
          enum:
          - day
          - week
          description: Bucket size. Daily counts are noisy on a book this size; `week` is the readable default for long ranges.
        required: false
        name: grain
        in: query
      - name: X-Request-Id
        in: header
        required: false
        schema:
          type: string
          pattern: ^[A-Za-z0-9_-]{1,64}$
        description: Optional correlation id, echoed unchanged when valid; otherwise a UUID is generated.
      responses:
        '200':
          description: Platform rating dynamics
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RatingDynamicsResponse'
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
        '401':
          description: No credential, or an invalid one
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '403':
          description: The credential does not carry the required plan or role
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: Rate limit exceeded; retry after Retry-After seconds
          headers:
            Retry-After:
              $ref: '#/components/headers/Retry-After'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
      security:
      - ApiKeyAuth: []
      operationId: getV1StatsRatingDynamics
    servers:
    - url: https://api.philidor.io
      description: Production
    - url: http://localhost:3003
      description: Local
components:
  schemas:
    StatsResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            totalVaults:
              type: number
            totalTvl:
              type: number
              description: Sum of indexed position values. Exposures can overlap across positions and protocols; this is not unique capital.
            avgApr:
              type:
              - number
              - 'null'
            activeLoansUsd:
              type: number
              description: 'Active loan size in USD: SUM(utilization × tvl_usd) over investable vaults — the real metric behind headline TVL (TVL actually lent out). Only money-market vaults reporting utilization contribute; MetaMorpho uses pro-rata market attribution (double-count-free across vaults sharing a market). 0 until adapters populate utilization.'
            weightedUtilization:
              type:
              - number
              - 'null'
              description: TVL-weighted mean utilization across vaults that report it (denominator excludes NULL-utilization vaults so non-money-market TVL does not dilute it). Null when no vault reports utilization.
            curatorCount:
              type: number
            protocolCount:
              type: number
            chainCount:
              type: number
            riskDistribution:
              type: array
              items:
                type: object
                properties:
                  risk_tier:
                    type: string
                    enum:
                    - Prime
                    - Core
                    - Edge
                    description: Published tier (hysteresis-stabilized). May briefly differ from a naive derivation from risk_score while a boundary move is dwelling.
                  count:
                    type: number
                  tvl:
                    type: number
                required:
                - risk_tier
                - count
                - tvl
            tvlByProtocol:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: string
                  tvl_semantics:
                    type: string
                    enum:
                    - overlapping_position_value
                    description: Gross value of indexed PT and LP positions. PT supply includes tokens held in LP reserves, so these values overlap and are not unique capital.
                  name:
                    type: string
                  logo_url:
                    type:
                    - string
                    - 'null'
                  vault_count:
                    type: number
                  tvl:
                    type: number
                required:
                - id
                - name
                - logo_url
                - vault_count
                - tvl
            tvlByChain:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: number
                  name:
                    type: string
                  logo_url:
                    type:
                    - string
                    - 'null'
                  vault_count:
                    type: number
                  tvl:
                    type: number
                required:
                - id
                - name
                - logo_url
                - vault_count
                - tvl
            lastSync:
              type:
              - string
              - 'null'
          required:
          - totalVaults
          - totalTvl
          - avgApr
          - activeLoansUsd
          - weightedUtilization
          - curatorCount
          - protocolCount
          - chainCount
          - riskDistribution
          - tvlByProtocol
          - tvlByChain
          - lastSync
      required:
      - data
    StatsHistoryResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              recorded_at:
                type: string
                description: UTC day bucket, ISO-8601.
              source:
                type: string
                enum:
                - observed
                - derived
                description: '''observed'' — captured live from /v1/stats that day, fully point-in-time. ''derived'' — reconstructed after the fact: TVL/APR/utilization are real historical measurements, but protocol/chain labels and the investable-set filter reflect today''s vaults, and riskDistribution is null because the historical published tier is not recoverable. Do not present derived points as an audited point-in-time record. See `reconstructed` for how the day was recovered.'
              reconstructed:
                type: boolean
                description: Additive field. False for a day replayed purely from Philidor's own per-vault snapshot history. True when the day additionally includes vaults Philidor was not yet observing, recovered from protocol-native history (Morpho's API, Uniswap's subgraph) or archive on-chain reads priced with historical USD. A true day answers 'what was today's covered book worth then', NOT 'what Philidor covered then'. Always false when source is 'observed'.
              totalVaults:
                type:
                - number
                - 'null'
              totalTvl:
                type: number
                description: Sum of indexed position values. Exposures can overlap across positions and protocols; this is not unique capital.
              activeLoansUsd:
                type:
                - number
                - 'null'
                description: Null means not measurable that day (per-vault utilization predates migration 230), not zero.
              weightedUtilization:
                type:
                - number
                - 'null'
              avgApr:
                type:
                - number
                - 'null'
              tvlByProtocol:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      anyOf:
                      - type: string
                      - type: number
                    name:
                      type: string
                    tvl:
                      type: number
                    vault_count:
                      type: number
                    tvl_semantics:
                      type: string
                      enum:
                      - overlapping_position_value
                      description: Gross value of indexed PT and LP positions. PT supply includes tokens held in LP reserves, so these values overlap and are not unique capital.
                  required:
                  - id
                  - name
                  - tvl
                  - vault_count
              tvlByChain:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      anyOf:
                      - type: string
                      - type: number
                    name:
                      type: string
                    tvl:
                      type: number
                    vault_count:
                      type: number
                    tvl_semantics:
                      type: string
                      enum:
                      - overlapping_position_value
                      description: Gross value of indexed PT and LP positions. PT supply includes tokens held in LP reserves, so these values overlap and are not unique capital.
                  required:
                  - id
                  - name
                  - tvl
                  - vault_count
              riskDistribution:
                type:
                - array
                - 'null'
                items:
                  type: object
                  properties:
                    risk_tier:
                      type: string
                    count:
                      type: number
                    tvl:
                      type: number
                  required:
                  - risk_tier
                  - count
                  - tvl
                description: Null on derived points — see `source`.
            required:
            - recorded_at
            - source
            - reconstructed
            - totalVaults
            - totalTvl
            - activeLoansUsd
            - weightedUtilization
            - avgApr
            - tvlByProtocol
            - tvlByChain
            - riskDistribution
        meta:
          type: object
          properties:
            days:
              type: number
            points:
              type: number
            observedPoints:
              type: number
            derivedPoints:
              type: number
            reconstructedPoints:
              type: number
          required:
          - days
          - points
          - observedPoints
          - derivedPoints
          - reconstructedPoints
      required:
      - data
      - meta
    ErrorEnvelope:
      description: Error body. `legacy_code` is present for one compatibility release when an older endpoint previously emitted a lowercase route-specific code.
      type: object
      required:
      - error
      properties:
        error:
          type: object
          required:
          - code
          - message
          - request_id
          properties:
            code:
              type: string
              pattern: ^[A-Z][A-Z0-9_]*$
              example: NOT_FOUND
            message:
              type: string
              example: Vault not found
            request_id:
              type: string
              description: Correlation id, also in the X-Request-Id header.
            legacy_code:
              type: string
              description: Previous lowercase code during the one-release migration window.
            pricing_url:
              type: string
              description: Present on a tier gate. Same URL as refusal.upgrade_url.
            refusal:
              description: Present on 401/403 for a gated data family (PHI-312). Same object as one row of GET /v1/access/families. x402_price is null until pay-per-request is live.
              type: object
              required:
              - restricted_fields
              - family
              - required_plan
              - upgrade_url
              - x402_price
              properties:
                restricted_fields:
                  type: array
                  items:
                    type: string
                family:
                  type: string
                required_plan:
                  type:
                  - string
                  - 'null'
                  enum:
                  - Free
                  - Analyst
                  - Pro
                  - Data
                  - Decisioning
                  - Embedded
                  - null
                upgrade_url:
                  type: string
                  example: https://philidor.io/pricing
                x402_price:
                  type: 'null'
          additionalProperties: true
    RatingDynamicsResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              bucketStart:
                type: string
                description: Start of the bucket, UTC, ISO-8601.
              upgrades:
                type: number
                description: Vault tier moves to a better tier (toward Prime). Excludes methodology reclassifications and first ratings.
              downgrades:
                type: number
                description: Vault tier moves to a worse tier (toward Edge). Excludes methodology reclassifications.
              net:
                type: number
                description: upgrades - downgrades.
              newlyCovered:
                type: number
                description: 'Vaults receiving a first rating. Deliberately NOT counted as upgrades: there is no prior tier to have moved from, and counting them would let coverage growth read as improving credit quality.'
              methodologyReclassifications:
                type: number
                description: Moves attributed to a methodology version change, reported separately and excluded from upgrades/downgrades. A methodology bump can move hundreds of vaults without any of them becoming riskier — the ruler changed, not the book.
              scoreOnlyChanges:
                type: number
                description: Score moves that did not cross a tier boundary.
              meanScoreDelta:
                type:
                - number
                - 'null'
                description: Mean (new_score - prev_score) over non-methodology moves carrying both scores. Null when the bucket has none.
              transitions:
                type: array
                items:
                  type: object
                  properties:
                    from:
                      type: string
                      enum:
                      - Prime
                      - Core
                      - Edge
                    to:
                      type: string
                      enum:
                      - Prime
                      - Core
                      - Edge
                    count:
                      type: number
                  required:
                  - from
                  - to
                  - count
            required:
            - bucketStart
            - upgrades
            - downgrades
            - net
            - newlyCovered
            - methodologyReclassifications
            - scoreOnlyChanges
            - meanScoreDelta
            - transitions
        meta:
          type: object
          properties:
            days:
              type: number
            grain:
              type: string
              enum:
              - day
              - week
            buckets:
              type: number
            upgrades:
              type: number
            downgrades:
              type: number
            net:
              type: number
            weighting:
              type: string
              enum:
              - vault_count
              description: Counts of vaults, never TVL-weighted. rating_history stores no TVL, and weighting a historical move by today’s balance would produce a series that silently rewrites itself.
          required:
          - days
          - grain
          - buckets
          - upgrades
          - downgrades
          - net
          - weighting
      required:
      - data
      - meta
  headers:
    X-RateLimit-Limit:
      description: Requests allowed in the active window for this caller.
      schema:
        type: integer
    Retry-After:
      description: Seconds to wait before retrying (429, 503, 504).
      schema:
        type: integer
        minimum: 0
    X-RateLimit-Reset:
      description: Unix timestamp (seconds) when the window resets.
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests remaining in the active window.
      schema:
        type: integer
    X-Request-Id:
      description: Correlation id for the request. A valid inbound X-Request-Id (1-64 word characters or dashes) is echoed; otherwise one is generated. Quote it when reporting a failure.
      schema:
        type: string
  securitySchemes:
    IndexTokenAuth:
      type: http
      scheme: bearer
      description: Separate index preview/client token. Commercial API keys do not unlock private index routes.
    ApiKeyAuth:
      type: http
      scheme: bearer
      description: 'Philidor API key (`Authorization: Bearer pk_live_...`). Optional on public endpoints, where it raises rate limits and unlocks tiered capabilities. The administrative surfaces additionally require operator-set metadata.admin_surface=true; mutations require metadata.admin_role=admin_editor or admin_operator under the same write-role enforcement as admin sessions. A plan tier alone never grants administrative access.'
    AdminCookieAuth:
      type: apiKey
      in: cookie
      name: philidor_admin_session
      description: Administrative session. Additionally IP-allowlisted.
    DashboardCookieAuth:
      type: apiKey
      in: cookie
      name: philidor_dashboard_session
      description: Dashboard session cookie (httpOnly).
x-refined-from:
- philidor-openapi.json
- philidor-io-openapi.json