{
  "service": "XRPL Ledger Object Service (LOS)",
  "description": "Public API for querying indexed XRP Ledger data including tokens, AMM pools, DEX trades, transactions, and single-asset vaults with lending protocol support.",
  "version": "2.0",
  "endpoints": [
    {
      "method": "GET",
      "path": "/tokens/{token_id}",
      "summary": "Get token details by ID",
      "description": "Returns metadata, pricing, supply, and market data for a single token. Checks the trusted-tokens table first, then falls back to the general tokens table.",
      "path_parameters": {
        "token_id": {
          "type": "string",
          "required": true,
          "format": "CURRENCY.ISSUER",
          "description": "Token identifier. CURRENCY is the currency code (e.g. \"USD\", or 40-char hex for non-standard codes). ISSUER is the r-address of the issuing account.",
          "example": "USD.rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
        }
      },
      "query_parameters": {},
      "response": {
        "200": {
          "description": "Token found",
          "body": {
            "asset_class": {
              "type": "string",
              "description": "Asset classification (e.g. \"currency\")"
            },
            "asset_subclass": {
              "type": "string",
              "description": "Asset sub-classification (e.g. \"stablecoin\")"
            },
            "issuer_account": {
              "type": "string",
              "description": "Issuer r-address"
            },
            "issuer_name": {
              "type": "string",
              "description": "Human-readable issuer name"
            },
            "issuer_domain": {
              "type": "string",
              "description": "Issuer domain from the account's Domain field"
            },
            "token_name": {
              "type": "string",
              "description": "Human-readable token name"
            },
            "currency": {
              "type": "string",
              "description": "Currency code"
            },
            "price": {
              "type": "number",
              "description": "Current price in XRP",
              "unit": "XRP"
            },
            "price_usd": {
              "type": "number",
              "description": "Current price in USD",
              "unit": "USD"
            },
            "price_change": {
              "type": "number",
              "description": "24-hour price change",
              "unit": "percentage"
            },
            "trust_level": {
              "type": "string",
              "description": "Trust level assigned to this token"
            },
            "supply": {
              "type": "number",
              "description": "Total token supply",
              "unit": "token native units"
            },
            "market_cap": {
              "type": "number",
              "description": "Market capitalization in XRP",
              "unit": "XRP"
            },
            "market_cap_usd": {
              "type": "number",
              "description": "Market capitalization in USD",
              "unit": "USD"
            },
            "circ_supply": {
              "type": "number",
              "description": "Circulating supply",
              "unit": "token native units"
            },
            "daily_volume": {
              "type": "number",
              "description": "24-hour trading volume in XRP",
              "unit": "XRP"
            },
            "daily_volume_usd": {
              "type": "number",
              "description": "24-hour trading volume in USD",
              "unit": "USD"
            },
            "number_of_holders": {
              "type": "number",
              "description": "Number of accounts holding this token"
            },
            "number_of_trustlines": {
              "type": "number",
              "description": "Number of trust lines set for this token"
            },
            "number_of_trades": {
              "type": "number",
              "description": "Number of trades in the last 24 hours"
            },
            "social_links": {
              "type": "object",
              "description": "Social media and website links"
            },
            "icon": {
              "type": "string",
              "description": "URL to the token icon image"
            },
            "tvl_xrp": {
              "type": "number",
              "description": "Total value locked in AMM pools in XRP",
              "unit": "XRP"
            },
            "tvl_usd": {
              "type": "number",
              "description": "Total value locked in AMM pools in USD",
              "unit": "USD"
            },
            "transfer_fee": {
              "type": "number",
              "description": "Transfer fee set by the issuer (fetched live from XRPL)",
              "unit": "percentage"
            },
            "ttl": {
              "type": "number",
              "description": "Time-to-live for this cache entry",
              "unit": "seconds"
            }
          }
        },
        "400": {
          "description": "Missing or invalid token_id format"
        },
        "404": {
          "description": "Token not found in either trusted-tokens or tokens database"
        },
        "500": {
          "description": "Internal server error"
        }
      }
    },
    {
      "method": "POST",
      "path": "/tokens/batch-get",
      "summary": "Get multiple tokens in a single request",
      "description": "Batch retrieval of token data. Returns results for all requested token IDs, including error entries for tokens not found.",
      "path_parameters": {},
      "query_parameters": {},
      "request_body": {
        "content_type": "application/json",
        "fields": {
          "tokenIds": {
            "type": "array of strings",
            "required": true,
            "description": "Array of token IDs in CURRENCY.ISSUER format. Maximum 100 per request.",
            "example": [
              "USD.rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
              "EUR.rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq"
            ]
          }
        }
      },
      "response": {
        "200": {
          "description": "Batch results returned",
          "body": {
            "tokens": {
              "type": "array",
              "description": "Array of token objects (same shape as GET /tokens/{token_id}) or { tokenId, error: \"Token Not Found\" } for missing tokens"
            },
            "summary": {
              "type": "object",
              "description": "Summary counts",
              "fields": {
                "requested": {
                  "type": "number",
                  "description": "Number of tokens requested"
                },
                "found": {
                  "type": "number",
                  "description": "Number of tokens found"
                },
                "notFound": {
                  "type": "number",
                  "description": "Number of tokens not found"
                }
              }
            }
          }
        },
        "400": {
          "description": "Invalid request body, empty array, exceeds 100-token limit, or malformed token IDs"
        },
        "500": {
          "description": "Internal server error"
        }
      }
    },
    {
      "method": "GET",
      "path": "/trusted-tokens",
      "summary": "List all trusted tokens",
      "description": "Returns the full set of tokens in the curated trusted-tokens table. These tokens have been reviewed and assigned trust levels.",
      "path_parameters": {},
      "query_parameters": {},
      "response": {
        "200": {
          "description": "Trusted tokens list",
          "body": {
            "count": {
              "type": "number",
              "description": "Number of trusted tokens returned"
            },
            "tokens": {
              "type": "array",
              "description": "Array of trusted token objects (same fields as GET /tokens/{token_id})"
            }
          }
        },
        "500": {
          "description": "Internal server error"
        }
      }
    },
    {
      "method": "GET",
      "path": "/v2/transactions",
      "summary": "Query indexed transactions (v2)",
      "description": "Returns validated transactions with flexible filtering by account, token, type, and boolean flags. Uses cursor-based pagination. This is the recommended transactions endpoint for new integrations.",
      "path_parameters": {},
      "query_parameters": {
        "account": {
          "type": "string",
          "required": false,
          "description": "Filter by XRPL account r-address. Matches any account involved in the transaction.",
          "example": "rN7n3473SaZBCG4dFL83w7p1W9cgZw6ao3"
        },
        "token": {
          "type": "string",
          "required": false,
          "description": "Filter by token involved in the transaction. Format: CURRENCY.ISSUER.",
          "example": "USD.rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
        },
        "type": {
          "type": "string",
          "required": false,
          "description": "Filter by XRPL transaction type. Supports comma-separated list for multiple types.",
          "example": "Payment,OfferCreate"
        },
        "has_dex_trade": {
          "type": "string (boolean)",
          "required": false,
          "description": "Filter to transactions that include a DEX trade.",
          "allowed_values": [
            "true",
            "false"
          ]
        },
        "is_transfer": {
          "type": "string (boolean)",
          "required": false,
          "description": "Filter to transactions classified as transfers.",
          "allowed_values": [
            "true",
            "false"
          ]
        },
        "size": {
          "type": "number",
          "required": false,
          "description": "Number of results per page.",
          "default": 10,
          "min": 1,
          "max": 200
        },
        "sort_order": {
          "type": "string",
          "required": false,
          "description": "Sort direction by timestamp.",
          "default": "desc",
          "allowed_values": [
            "asc",
            "desc"
          ]
        },
        "search_after": {
          "type": "string (JSON array)",
          "required": false,
          "description": "Cursor for pagination. Pass the next_cursor or prev_cursor value from a previous response.",
          "example": "[1710100000000,\"AABBCC...\"]"
        },
        "direction": {
          "type": "string",
          "required": false,
          "description": "Pagination direction when using search_after.",
          "allowed_values": [
            "next",
            "prev"
          ]
        }
      },
      "response": {
        "200": {
          "description": "Paginated transaction results",
          "body": {
            "size": {
              "type": "number",
              "description": "Requested page size"
            },
            "sort_field": {
              "type": "string",
              "description": "Always \"timestamp\""
            },
            "sort_order": {
              "type": "string",
              "description": "\"asc\" or \"desc\""
            },
            "results": {
              "type": "array",
              "description": "Array of transaction documents"
            },
            "next_cursor": {
              "type": "array or null",
              "description": "Cursor for the next page"
            },
            "prev_cursor": {
              "type": "array or null",
              "description": "Cursor for the previous page"
            },
            "pagination_method": {
              "type": "string",
              "description": "Always \"cursor\""
            },
            "search_after": {
              "type": "array or null",
              "description": "Echo of the search_after value used"
            },
            "direction": {
              "type": "string",
              "description": "\"first_page\", \"next\", or \"prev\""
            }
          }
        },
        "400": {
          "description": "Invalid cursor format"
        },
        "500": {
          "description": "Internal server error"
        }
      }
    },
    {
      "method": "GET",
      "path": "/dex-trades",
      "summary": "Query DEX trades",
      "description": "Returns DEX trade events extracted from XRPL transactions, including both AMM swaps and order book fills. Uses cursor-based pagination.",
      "path_parameters": {},
      "query_parameters": {
        "account": {
          "type": "string",
          "required": false,
          "description": "Filter by XRPL account involved in the trade (includes AMM pool accounts).",
          "example": "rN7n3473SaZBCG4dFL83w7p1W9cgZw6ao3"
        },
        "token": {
          "type": "string",
          "required": false,
          "description": "Filter by token involved in the trade.",
          "example": "USD.rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
        },
        "type": {
          "type": "string",
          "required": false,
          "description": "Filter by DEX trade type.",
          "allowed_values": [
            "amm",
            "orderBook"
          ]
        },
        "size": {
          "type": "number",
          "required": false,
          "description": "Number of results per page.",
          "default": 10,
          "min": 1,
          "max": 200
        },
        "sort_order": {
          "type": "string",
          "required": false,
          "description": "Sort direction by timestamp.",
          "default": "desc",
          "allowed_values": [
            "asc",
            "desc"
          ]
        },
        "search_after": {
          "type": "string (JSON array)",
          "required": false,
          "description": "Cursor for pagination. Must be a JSON-encoded array.",
          "example": "[1710100000000,\"AABBCC...\"]"
        },
        "direction": {
          "type": "string",
          "required": false,
          "description": "Pagination direction when using search_after.",
          "allowed_values": [
            "next",
            "prev"
          ]
        }
      },
      "response": {
        "200": {
          "description": "Paginated DEX trade results",
          "body": {
            "size": {
              "type": "number",
              "description": "Requested page size"
            },
            "sort_field": {
              "type": "string",
              "description": "Always \"timestamp\""
            },
            "sort_order": {
              "type": "string",
              "description": "\"asc\" or \"desc\""
            },
            "results": {
              "type": "array",
              "description": "Array of DEX trade documents"
            },
            "next_cursor": {
              "type": "array or null",
              "description": "Cursor for the next page"
            },
            "prev_cursor": {
              "type": "array or null",
              "description": "Cursor for the previous page"
            },
            "pagination_method": {
              "type": "string",
              "description": "Always \"cursor\""
            },
            "search_after": {
              "type": "array or null",
              "description": "Echo of the search_after value used"
            },
            "direction": {
              "type": "string",
              "description": "\"first_page\", \"next\", or \"prev\""
            }
          }
        },
        "400": {
          "description": "Invalid DEX trade type or cursor format"
        },
        "500": {
          "description": "Internal server error"
        }
      }
    },
    {
      "method": "GET",
      "path": "/amms",
      "summary": "List AMM pools",
      "description": "Returns a ranked list of AMM (Automated Market Maker) pools on the XRPL, sorted by the specified metric. Excludes the aggregated summary record.",
      "path_parameters": {},
      "query_parameters": {
        "sort_field": {
          "type": "string",
          "required": false,
          "description": "Field to sort results by.",
          "default": "tvl_usd",
          "allowed_values": [
            "tvl_xrp",
            "tvl_usd",
            "trading_volume_xrp",
            "trading_volume_usd",
            "fees_collected_xrp",
            "fees_collected_usd",
            "annual_percentage_return",
            "liquidity_provider_count",
            "amm_created_timestamp"
          ]
        },
        "sort_order": {
          "type": "string",
          "required": false,
          "description": "Sort direction.",
          "default": "desc",
          "allowed_values": [
            "asc",
            "desc"
          ]
        },
        "size": {
          "type": "number",
          "required": false,
          "description": "Number of AMM pools to return.",
          "default": 1000,
          "min": 1,
          "max": 1000
        }
      },
      "response": {
        "200": {
          "description": "Sorted list of AMM pools",
          "body": {
            "size": {
              "type": "number",
              "description": "Requested result count"
            },
            "sort_field": {
              "type": "string",
              "description": "Field results are sorted by"
            },
            "sort_order": {
              "type": "string",
              "description": "\"asc\" or \"desc\""
            },
            "count": {
              "type": "number",
              "description": "Actual number of results returned"
            },
            "results": {
              "type": "array",
              "description": "Array of AMM pool objects",
              "item_fields": {
                "amm_account_id": {
                  "type": "string",
                  "description": "AMM pool account r-address"
                },
                "tvl_xrp": {
                  "type": "number",
                  "description": "Total value locked",
                  "unit": "XRP"
                },
                "tvl_usd": {
                  "type": "number",
                  "description": "Total value locked",
                  "unit": "USD"
                },
                "trading_volume_xrp": {
                  "type": "number",
                  "description": "24-hour trading volume",
                  "unit": "XRP"
                },
                "trading_volume_usd": {
                  "type": "number",
                  "description": "24-hour trading volume",
                  "unit": "USD"
                },
                "fees_collected_xrp": {
                  "type": "number",
                  "description": "Total fees collected",
                  "unit": "XRP"
                },
                "fees_collected_usd": {
                  "type": "number",
                  "description": "Total fees collected",
                  "unit": "USD"
                },
                "annual_percentage_return": {
                  "type": "number",
                  "description": "Annualized percentage return for LPs",
                  "unit": "percentage"
                },
                "liquidity_provider_count": {
                  "type": "number",
                  "description": "Number of liquidity provider accounts"
                },
                "amm_created_timestamp": {
                  "type": "string",
                  "description": "ISO 8601 timestamp when the AMM pool was created"
                }
              }
            }
          }
        },
        "500": {
          "description": "Internal server error"
        }
      }
    },
    {
      "method": "GET",
      "path": "/amms/{id}",
      "summary": "Get a single AMM pool or aggregated metrics",
      "description": "Returns details for a specific AMM pool by account ID. Use id=\"aggregated\" to get the latest aggregated metrics across all AMM pools.",
      "path_parameters": {
        "id": {
          "type": "string",
          "required": true,
          "description": "AMM pool account r-address, or the special value \"aggregated\" for protocol-wide AMM metrics.",
          "example": "rN7n3473SaZBCG4dFL83w7p1W9cgZw6ao3"
        }
      },
      "query_parameters": {},
      "response": {
        "200": {
          "description": "AMM pool object (same fields as /amms results), or aggregated metrics when id=\"aggregated\""
        },
        "404": {
          "description": "AMM pool or aggregated metrics not found"
        },
        "500": {
          "description": "Internal server error"
        }
      }
    },
    {
      "method": "GET",
      "path": "/amms/historical-trends",
      "summary": "Get AMM historical trend data",
      "description": "Returns daily time-series data for an AMM pool or the aggregated protocol metrics. Data includes TVL and trading volume per day. Date range is anchored to yesterday (UTC) since today's data may be incomplete. Some dates within the range may have no data; the caller should detect gaps using expected_data_points vs total_data_points. Maximum 5 years (1825 data points).",
      "path_parameters": {},
      "query_parameters": {
        "amm_account_id": {
          "type": "string",
          "required": false,
          "description": "AMM pool account r-address. Defaults to \"aggregated\" for protocol-wide metrics.",
          "default": "aggregated"
        },
        "time_range": {
          "type": "string",
          "required": true,
          "description": "Time range for the data points. Date range is anchored to yesterday (UTC).",
          "allowed_values": [
            "1W",
            "1M",
            "6M",
            "1Y",
            "5Y"
          ],
          "value_descriptions": {
            "1W": "Last 7 days",
            "1M": "Last 30 days",
            "6M": "Last 180 days",
            "1Y": "Last 365 days",
            "5Y": "Last 1825 days"
          }
        }
      },
      "response": {
        "200": {
          "description": "Time-series data",
          "body": {
            "amm_account_id": {
              "type": "string",
              "description": "AMM account ID or \"aggregated\""
            },
            "time_range": {
              "type": "string",
              "description": "Time range filter applied"
            },
            "start_date": {
              "type": "string",
              "description": "Start date of the range (YYYY-MM-DD)"
            },
            "end_date": {
              "type": "string",
              "description": "End date of the range (YYYY-MM-DD, yesterday in UTC)"
            },
            "expected_data_points": {
              "type": "number",
              "description": "Expected number of data points for the requested time range (e.g. 7 for 1W). Compare with total_data_points to detect missing dates."
            },
            "total_data_points": {
              "type": "number",
              "description": "Number of data points returned"
            },
            "data_points": {
              "type": "array",
              "description": "Array of daily data points, sorted ascending by date",
              "item_fields": {
                "date": {
                  "type": "string",
                  "description": "Date in YYYY-MM-DD format"
                },
                "tvl_xrp": {
                  "type": "number",
                  "description": "Total value locked on this date",
                  "unit": "XRP"
                },
                "tvl_usd": {
                  "type": "number",
                  "description": "Total value locked on this date",
                  "unit": "USD"
                },
                "trading_volume_xrp": {
                  "type": "number",
                  "description": "Trading volume on this date",
                  "unit": "XRP"
                },
                "trading_volume_usd": {
                  "type": "number",
                  "description": "Trading volume on this date",
                  "unit": "USD"
                }
              }
            }
          }
        },
        "400": [
          {
            "description": "Missing required parameter: time_range"
          },
          {
            "description": "Invalid time_range value"
          }
        ],
        "500": {
          "description": "Internal server error"
        }
      }
    },
    {
      "method": "GET",
      "path": "/vaults",
      "summary": "List vaults with sorting, filtering, and search",
      "description": "Returns a paginated list of XLS-65 single-asset vaults. Supports sorting, filtering by asset type, and free-text search across vault fields. Only vaults holding XRP or whitelisted stablecoins are indexed.",
      "path_parameters": {},
      "query_parameters": {
        "page": {
          "type": "number",
          "required": false,
          "description": "Page number (1-indexed).",
          "default": 1,
          "min": 1
        },
        "size": {
          "type": "number",
          "required": false,
          "description": "Results per page.",
          "default": 20,
          "min": 1,
          "max": 100
        },
        "sort_by": {
          "type": "string",
          "required": false,
          "description": "Field to sort results by.",
          "default": "assets_total",
          "allowed_values": [
            "assets_total",
            "outstanding_loans",
            "average_interest_rate",
            "utilization_ratio"
          ]
        },
        "sort_order": {
          "type": "string",
          "required": false,
          "description": "Sort direction.",
          "default": "desc",
          "allowed_values": [
            "asc",
            "desc"
          ]
        },
        "asset_type": {
          "type": "string",
          "required": false,
          "description": "Filter vaults by asset category.",
          "default": "all",
          "allowed_values": [
            "all",
            "stablecoins",
            "xrp"
          ],
          "value_descriptions": {
            "all": "All indexed vaults (XRP + whitelisted stablecoins)",
            "stablecoins": "Only vaults holding whitelisted stablecoins (RLUSD, USD, EUR, USDC, USDT, GBP, USDf, sUSDf)",
            "xrp": "Only vaults holding XRP"
          }
        },
        "name_like": {
          "type": "string",
          "required": false,
          "description": "Free-text search query. Searches across vault name, website (fuzzy match), and vault_id, account, owner, asset_currency, asset_issuer (substring match).",
          "example": "Ripple"
        }
      },
      "response": {
        "200": {
          "description": "Paginated vault results",
          "body": {
            "total": {
              "type": "number",
              "description": "Total number of matching vaults"
            },
            "page": {
              "type": "number",
              "description": "Current page number"
            },
            "size": {
              "type": "number",
              "description": "Results per page"
            },
            "total_pages": {
              "type": "number",
              "description": "Total number of pages"
            },
            "sort_by": {
              "type": "string",
              "description": "Field results are sorted by"
            },
            "sort_order": {
              "type": "string",
              "description": "\"asc\" or \"desc\""
            },
            "asset_type": {
              "type": "string",
              "description": "Asset type filter applied"
            },
            "results": {
              "type": "array",
              "description": "Array of vault objects",
              "item_fields": {
                "vault_id": {
                  "type": "string",
                  "description": "64-character hex vault identifier (XRPL ledger object hash)"
                },
                "account": {
                  "type": "string",
                  "description": "Vault pseudo-account r-address (holds the vault's assets)"
                },
                "name": {
                  "type": "string or null",
                  "description": "Vault name, extracted from the on-chain Data field (JSON key \"n\")"
                },
                "website": {
                  "type": "string or null",
                  "description": "Vault website, extracted from the on-chain Data field (JSON key \"w\")"
                },
                "metadata": {
                  "type": "string or null",
                  "description": "Raw on-chain Data field value (hex-encoded or JSON string)"
                },
                "asset_currency": {
                  "type": "string",
                  "description": "Vault asset currency code (e.g. \"XRP\", \"USD\", or 40-char hex)"
                },
                "asset_issuer": {
                  "type": "string or null",
                  "description": "Vault asset issuer r-address (null for XRP)"
                },
                "assets_total": {
                  "type": "number",
                  "description": "Total assets in the vault, including amounts lent out",
                  "unit": "asset native units (XRP for XRP vaults, token units for IOU vaults)"
                },
                "assets_available": {
                  "type": "number",
                  "description": "Assets currently available for withdrawal (assets_total minus lent-out amounts)",
                  "unit": "asset native units"
                },
                "outstanding_loans": {
                  "type": "number",
                  "description": "Total value outstanding across all active loans from this vault (computed every 5 minutes)",
                  "unit": "asset native units"
                },
                "average_interest_rate": {
                  "type": "number or null",
                  "description": "Weighted average interest rate across active loans, weighted by total_value_outstanding (computed every 5 minutes). Null if no active loans.",
                  "unit": "percentage (e.g. 5.0 = 5%)"
                },
                "utilization_ratio": {
                  "type": "number",
                  "description": "Fraction of vault assets currently lent out: outstanding_loans / assets_total. 0 if assets_total is 0.",
                  "unit": "ratio (0 to 1)"
                },
                "owner": {
                  "type": "string",
                  "description": "Vault owner account r-address"
                },
                "withdrawal_policy": {
                  "type": "string or null",
                  "description": "Withdrawal strategy type identifier"
                },
                "share_mpt_id": {
                  "type": "string or null",
                  "description": "MPTokenIssuanceID for the vault's share tokens (48-char hex)"
                },
                "loss_unrealized": {
                  "type": "number",
                  "description": "Unrealized loss from impaired loans (paper loss, not yet written down)",
                  "unit": "asset native units"
                },
                "created_at": {
                  "type": "string",
                  "description": "ISO 8601 timestamp when the vault was created on-ledger"
                },
                "ledger_index": {
                  "type": "number",
                  "description": "Ledger index of the most recent transaction that modified this vault"
                },
                "last_updated": {
                  "type": "string",
                  "description": "ISO 8601 timestamp of the most recent transaction that modified this vault"
                }
              }
            }
          }
        },
        "400": {
          "description": "Invalid sort_by field or asset_type value"
        },
        "500": {
          "description": "Internal server error"
        }
      }
    },
    {
      "method": "GET",
      "path": "/vaults/{vault_id}",
      "summary": "Get a single vault by ID",
      "description": "Returns the full details of a specific vault by its ledger object hash.",
      "path_parameters": {
        "vault_id": {
          "type": "string",
          "required": true,
          "format": "64-character hexadecimal string",
          "description": "XRPL vault ledger object hash.",
          "example": "A1B2C3D4E5F6...64 hex chars"
        }
      },
      "query_parameters": {},
      "response": {
        "200": {
          "description": "Vault object (same fields as /vaults results)"
        },
        "400": {
          "description": "Invalid vault_id format (must be 64-character hex)"
        },
        "404": {
          "description": "Vault not found"
        },
        "500": {
          "description": "Internal server error"
        }
      }
    },
    {
      "method": "GET",
      "path": "/vaults/aggregate-statistics",
      "summary": "Get aggregate vault and lending statistics",
      "description": "Returns protocol-wide aggregate statistics across all indexed vaults. Values are denominated in XRP (converted from each vault's native asset using market rates). Statistics are recomputed every 10 minutes.",
      "path_parameters": {},
      "query_parameters": {},
      "response": {
        "200": {
          "description": "Aggregate statistics",
          "body": {
            "active_vaults": {
              "type": "number",
              "description": "Total number of indexed vaults",
              "unit": "count"
            },
            "tvl_total": {
              "type": "number",
              "description": "Total value locked across all vaults (sum of assets_total, converted to XRP)",
              "unit": "XRP"
            },
            "debt_total": {
              "type": "number",
              "description": "Total outstanding debt across all vaults (sum of outstanding_loans, converted to XRP)",
              "unit": "XRP"
            },
            "loans_originated": {
              "type": "number",
              "description": "Total value of all loans ever originated (sum of original loan obligations, converted to XRP)",
              "unit": "XRP"
            },
            "avg_interest_rate": {
              "type": "number",
              "description": "Weighted average interest rate across all vaults with active loans, weighted by assets_total",
              "unit": "percentage (e.g. 5.0 = 5%)"
            },
            "utilization_ratio": {
              "type": "number",
              "description": "Protocol-wide utilization: debt_total / tvl_total. 0 if tvl_total is 0.",
              "unit": "ratio (0 to 1)"
            },
            "last_updated": {
              "type": "string",
              "description": "ISO 8601 timestamp of the last statistics recomputation"
            }
          }
        },
        "500": {
          "description": "Internal server error"
        }
      }
    }
  ],
  "notes": {
    "pagination": "Transaction, DEX trade, and v1 transaction endpoints use cursor-based pagination via search_after. The vault list endpoint uses offset-based pagination via page/size. Cursor values should be treated as opaque — pass them exactly as received from next_cursor or prev_cursor.",
    "units": "All XRP amounts are in XRP (not drops). IOU/stablecoin amounts are in their native token units. Percentages are expressed as numbers where 5.0 means 5%. Ratios are 0-to-1 decimals.",
    "rate_limits": "API requests are throttled. Default limits: 10 requests/second sustained, 20 requests/second burst.",
    "data_freshness": "Transaction data is indexed in near-real-time (within ~1 minute of ledger close). Vault aggregate statistics are recomputed every 10 minutes. Per-vault loan statistics are recomputed every 5 minutes.",
    "indexed_vaults": "Only vaults holding XRP or whitelisted stablecoins (RLUSD, USD, EUR, USDC, USDT, GBP, USDf, sUSDf) are indexed."
  }
}