openapi: 3.0.3
info:
  title: pigi.finance Vault Intelligence API
  version: "1.0.0"
  description: >
    Programmatic access to pigi.finance DeFi vault data: APR, APY, TVL
    (with 30-day moving averages) across daily and weekly/monthly/quarterly/yearly
    windows, plus holder counts. Authenticate by exchanging your API key for a
    short-lived JWT, then send `Authorization: Bearer <JWT>` on every request.
servers:
  - url: https://pigi.finance/api/v1
tags:
  - name: meta
  - name: auth
  - name: vaults
  - name: account
paths:
  /:
    get:
      tags: [meta]
      summary: API discovery index
      description: Version, docs link, and the list of available endpoints. No auth.
      security: []
      responses:
        "200":
          description: Discovery document
          content:
            application/json:
              schema:
                type: object
                properties:
                  version: { type: string, example: v1 }
                  docs: { type: string, example: /api-docs/openapi.yaml }
                  auth: { type: string }
                  endpoints:
                    type: array
                    items: { type: string }
  /auth/token:
    post:
      tags: [auth]
      summary: Exchange an API key for a short-lived JWT
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [apiKey]
              properties:
                apiKey:
                  type: string
                  example: pigi_live_xxxxxxxxxxxxxxxxxxxxxxxx
      responses:
        "200":
          description: A bearer token
          content:
            application/json:
              schema:
                type: object
                properties:
                  token: { type: string }
                  expiresIn: { type: integer, description: seconds }
                  plan: { type: string }
        "400": { description: missing_api_key }
        "401": { description: invalid_api_key }
  /vaults:
    get:
      tags: [vaults]
      summary: List vaults
      parameters:
        - { name: protocol_name, in: query, schema: { type: string } }
        - { name: chain_id, in: query, schema: { type: string } }
        - { name: strategy_id, in: query, schema: { type: string } }
        - { name: tvl_filter, in: query, schema: { type: string, enum: [gte_1m, gte_2m, gte_5m, gte_10m, non_na, na] } }
        - { name: apr_filter, in: query, schema: { type: string, enum: [lte_10, gt_5, gt_10, gt_15, gt_20, non_na, na] } }
        - { name: age_filter, in: query, schema: { type: string, enum: [new, 3mo, 6mo, 12mo, 18mo, 24mo, non_na, na] } }
        - { name: limit, in: query, schema: { type: integer, default: 100, maximum: 1000 } }
        - { name: offset, in: query, schema: { type: integer, default: 0 } }
      responses:
        "200":
          description: A page of vaults
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items: { $ref: "#/components/schemas/Vault" }
                  pagination:
                    type: object
                    properties:
                      total: { type: integer }
                      limit: { type: integer }
                      offset: { type: integer }
                      hasMore: { type: boolean }
                  availableFilters:
                    type: object
                    properties:
                      protocol_names: { type: array, items: { type: string } }
                      chain_ids: { type: object, additionalProperties: { type: array, items: { type: integer } } }
                      all_chain_ids: { type: array, items: { type: integer } }
        "401": { description: invalid_token }
  /vaults/{id}:
    get:
      tags: [vaults]
      summary: Get a single vault by pool id
      parameters:
        - { name: id, in: path, required: true, schema: { type: integer } }
      responses:
        "200":
          description: The vault
          content:
            application/json:
              schema:
                type: object
                properties:
                  data: { $ref: "#/components/schemas/Vault" }
        "404": { description: not_found }
  /vaults/{id}/history:
    get:
      tags: [vaults]
      summary: Daily time-series for a vault (by strategy id)
      parameters:
        - { name: id, in: path, required: true, schema: { type: integer }, description: strategy id }
        - { name: range, in: query, schema: { type: string, enum: ["7D", "30D", "90D", "180D"], default: "7D" } }
      responses:
        "200":
          description: Time-series + latest values
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        timestamp: { type: string }
                        tvl: { type: number }
                        apr: { type: number }
                        apy: { type: number }
                        ra_apr: { type: number, description: "risk-adjusted APR (apr - risk)" }
                        tvl_30d_ma: { type: number }
                        apr_30d_ma: { type: number }
                  lastTvl: { type: number }
                  lastApr: { type: number }
                  lastApy: { type: number }
                  lastRaApr: { type: number, nullable: true }
                  lastTvl30dMa: { type: number }
                  lastApr30dMa: { type: number }
                  lastRaApr30dMa: { type: number, nullable: true }
  /vaults/{id}/stats:
    get:
      tags: [vaults]
      summary: Windowed stats for a vault (by strategy id)
      parameters:
        - { name: id, in: path, required: true, schema: { type: integer }, description: strategy id }
        - { name: period, in: query, schema: { type: string, enum: [weekly, monthly, quarterly, yearly] } }
      responses:
        "200":
          description: Windowed stats (all windows if period omitted)
          content:
            application/json:
              schema:
                type: object
                properties:
                  weekly: { $ref: "#/components/schemas/PeriodStats" }
                  monthly: { $ref: "#/components/schemas/PeriodStats" }
                  quarterly: { $ref: "#/components/schemas/PeriodStats" }
                  yearly: { $ref: "#/components/schemas/PeriodStats" }
  /usage:
    get:
      tags: [account]
      summary: Your request usage for the current period
      responses:
        "200":
          description: Usage counters
          content:
            application/json:
              schema:
                type: object
                properties:
                  clientId: { type: integer }
                  plan: { type: string }
                  period:
                    type: object
                    properties:
                      start: { type: string }
                      end: { type: string }
                  used: { type: integer }
                  limit: { type: integer, nullable: true }
                  remaining: { type: integer, nullable: true }
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
  schemas:
    Vault:
      type: object
      properties:
        id: { type: integer }
        strategy_id: { type: integer }
        protocol_name: { type: string }
        chain_id: { type: integer }
        pool_name: { type: string }
        pool_address: { type: string }
        asset_address: { type: string, nullable: true }
        type: { type: string }
        tvl_30d_ma: { type: number, nullable: true }
        apr_30d_ma: { type: number, nullable: true }
        holders: { type: integer, nullable: true }
        pool_creation_date: { type: string, nullable: true }
        updated_at: { type: string, nullable: true }
        tvl_flow_1d: { type: number, nullable: true }
        tvl_flow_7d: { type: number, nullable: true }
        apr_trend_1d: { type: number, nullable: true }
    PeriodStats:
      type: object
      properties:
        tvl_low: { type: number }
        tvl_high: { type: number }
        apr: { type: number }
        apy: { type: number }
        period_start: { type: string }
        period_end: { type: string }
security:
  - bearerAuth: []
