# Nolus ETL API > Public, read-only HTTP API exposing indexed on-chain analytics for the > [Nolus](https://nolus.io) DeFi protocol — leases, liquidity pools, treasury > flows, liquidations, asset prices, and per-wallet PnL. All data is derived > from Cosmos SDK blocks and WebAssembly contract events on the Nolus chain; > the ETL service ingests blocks, normalises them into PostgreSQL, and serves > them as JSON. Base URL: `https://etl.nolus.network` (staging: `https://etl-internal.nolus.network`) All endpoints are under `/api`, return `application/json` by default, require no auth, allow any CORS origin. ## Machine-readable discovery - [OpenAPI 3.1 specification](/openapi.json) — full endpoint contract; parse this first. - [Browsable endpoint index](/) — human-facing HTML browser. - [Sitemap](/sitemap.xml), [robots.txt](/robots.txt). ## What this API is (and is not) **Is:** analytics over historical + current state of the Nolus protocol. **Is not:** a blockchain RPC node, a transaction submission endpoint, or a trading venue. To submit transactions or read unfinalised state, use a Nolus full node (`rpc.nolus.network`). To read smart-contract state directly, use the Cosmos gRPC endpoint (`grpc.nolus.network`). The service is strictly read-only. The only non-GET route is `POST /api/subscribe`, which registers a browser Web Push subscription for liquidation alerts — it writes to a subscription table, not to the chain. ## Endpoint categories Routes are grouped by the question they answer. Each bullet lists the category, the path prefix, and the typical question it's for. See `/openapi.json` for the full parameter list and response schema of each. ### Configuration & discovery - `/api/protocols`, `/api/protocols/active`, `/api/protocols/{name}` — active and deprecated protocols (per DEX × LPN-currency combination); each carries its set of CosmWasm contract addresses (leaser, lpp, oracle, profit, reserve). - `/api/currencies`, `/api/currencies/active`, `/api/currencies/{ticker}` — currency registry with decimal digits, bank and DEX IBC symbols, per-protocol mappings. - `/api/version` — the deployed ETL release. - `/api/blocks` — the highest block height ingested by the service. - `/health`, `/ready` — liveness + DB-readiness probes (not under `/api`). ### Protocol-wide metrics (TVL, revenue, utilisation) - `/api/total-value-locked`, `/api/supplied-funds`, `/api/borrowed`, `/api/open-interest`, `/api/open-position-value` — scalar USD aggregates for the protocol. - `/api/revenue`, `/api/revenue-series`, `/api/distributed`, `/api/incentives-pool`, `/api/buyback`, `/api/buyback-total` — treasury flows. - `/api/total-tx-value` — cumulative transaction volume in USD. - `/api/supplied-borrowed-history`, `/api/monthly-active-wallets` — time series. - `/api/pools` — per-protocol utilisation, borrow APR, earn APR, supplied + borrowed, plus global optimal and deposit-suspension thresholds. Use this instead of fanning out one-call-per-pool. ### Position & lease analytics (aggregate) - `/api/positions` — flat list of all currently-open leveraged positions (loan, down payment, lease value, PnL, current and liquidation prices). Add `?export=true&format=csv` to stream the full dataset as CSV. - `/api/position-buckets` — distribution of open positions across loan-size buckets. - `/api/positions-by-token` (`open-positions-by-token`), `/api/loans-by-token`, `/api/leased-assets` — aggregates grouped by asset symbol. - `/api/leases-monthly`, `/api/daily-positions`, `/api/leases-active-counts` — temporal and per-protocol lease counts. - `/api/realized-pnl-stats`, `/api/unrealized-pnl` — aggregate PnL scalars. ### Historical events (time-windowed) - `/api/liquidations`, `/api/historically-opened`, `/api/historically-repaid`, `/api/historically-liquidated`, `/api/interest-repayments`, `/api/realized-pnl-wallet` — timestamped event streams. All accept `period=3m|6m|12m|all` (default `3m`), `from=` for incremental sync, `format=json|csv`, and `export=true` for a full-dataset CSV stream bypassing `period`/`from`. ### Lending analytics - `/api/current-lenders`, `/api/historical-lenders` — lender positions and deposit/withdrawal history. - `/api/loans-granted`, `/api/lease-value-stats` — per-asset summaries. - `/api/lp-withdraw?tx=` — single LP withdrawal by transaction hash (404 if not found). ### Per-wallet analytics All of these require `?address=`: - `/api/realized-pnl`, `/api/realized-pnl-data`, `/api/unrealized-pnl-by-address`, `/api/pnl-over-time` — PnL views. - `/api/earnings` — total earnings from lending. - `/api/txs` — paginated transaction history (`filter=transfers,earn,staking,positions,positions_ids`; `skip`, `limit` ≤ 100). - `/api/leases-search` — lease IDs owned by the wallet. - `/api/ls-loan-closing` — closed-lease PnL (paginated; `limit` ≤ 10). - `/api/position-debt-value` — current per-asset position and debt. - `/api/history-stats` — win rate, volume, bucket distribution. ### Record lookup - `/api/ls-opening?lease=` — single-lease deep detail including history and fees. - `/api/ls-opening?leases=` — batch basic info. `lease` and `leases` are mutually exclusive. ### Market data - `/api/prices?interval=&key=&protocol=` — historical price series for a ticker under a specific protocol. `interval` capped at 100 days. ### Push notifications (writes) - `GET /api/subscribe?address&auth&active` — check subscription status. - `POST /api/subscribe` — create or toggle Web Push subscription for a wallet (VAPID). ## Conventions an agent should know - **Numeric amounts** are returned as JSON strings (`"12345.67"`) because they originate from `BigDecimal` — parse with an arbitrary-precision decimal library, not `parseFloat`. USD amounts use stablecoin-reference units; token amounts are in the asset's native decimals (see `/api/currencies` for `decimal_digits`). - **Protocol identifiers** look like `OSMOSIS-OSMOSIS-USDC_NOBLE` (DEX `-` network `-` LPN symbol). Don't invent them — discover from `/api/protocols`. - **Currency tickers** are Nolus-internal (`ATOM`, `USDC_NOBLE`, `NLS`); the chain-level IBC symbols are the `bank_symbol` / `dex_symbol` fields. - **`period`** accepts `3m`, `6m`, `12m`, `all`. Default is `3m`. Applies to every time-series endpoint that doesn't take `interval`. - **`from=`** is an exclusive lower bound for incremental sync; combines with `period` (which then acts as a safety upper window). - **`format=csv`** converts a response to CSV. `export=true` additionally streams the full dataset ignoring `period` and `from`. CSV exports are capped at 100 000 rows. - **Pagination:** `skip` + `limit`. Default `limit=10`. Max `limit=100` for most endpoints, `10` for `/api/ls-loan-closing`. - **Caching:** every response is served through an in-process Moka cache with a 5-minute tier (real-time aggregates) and a 1-hour tier (heavy joins and historical aggregates). A background refresher repopulates entries at 80 % of TTL, so a cold cache is rare in practice but possible on process restart. Don't assume micro-second freshness — data lags by at most one block for real-time reads and at most one hour for heavy aggregates. - **Freshness ceiling:** ingestion is driven by a WebSocket subscription to Tendermint events plus a gap-fill sync task, so the tail of the data is at most a few seconds behind the chain tip. Endpoints that rely on the hourly aggregation snapshot (TVL, open-interest, supplied/borrowed history, active-lenders, pools) update on the hour boundary. - **404 semantics:** endpoints that look up a single record (`/api/protocols/{name}`, `/api/currencies/{ticker}`, `/api/lp-withdraw?tx=...`) return 404 for an unknown key, not an empty object. - **Error responses** are JSON `{ "error": "" }` with a 4xx/5xx status. Validation failures return 400; internal errors return 500 with a generic message (never a database row). - **Rate limits:** none enforced at the application layer. Upstream (Cloudflare) may rate-limit bursts; back off on 429 + `Retry-After`. ## Gotchas LLM agents get wrong - **Don't hit one endpoint per protocol** when `/api/pools` (or `/api/protocols`) returns the same data in one round-trip. - **Don't assume `active` means the protocol still appears in dashboards** — deprecated protocols still hold historical leases; the per-protocol lease count is in `/api/leases-active-counts`. - **PnL numbers are signed.** Negative values mean losses; don't strip the minus when reformatting. - **`history-stats.pnl` is a number, `realized-pnl-stats.amount` is a string.** Legacy shape preserved for consumer compatibility. - **Don't use `/api/txs?filter=positions_ids`** without setting `to=` to the contract IDs of interest — it's a filter parameter, not a discovery one. - **`/api/ls-opening`** takes either `lease` (singular, rich detail) or `leases` (batch, basic); sending both is an error. - **`/api/prices.interval` is in days, `/api/pnl-over-time.interval` is in days too but capped at 30.** Different caps per endpoint; check `/openapi.json`. - **Blocks counter is a high-water mark, not a height.** `/api/blocks` returns the total number of blocks the ETL has processed, not the chain's current height. ## Related resources - Nolus protocol docs: https://docs.nolus.io - Nolus webapp: https://app.nolus.io - Nolus source code: https://github.com/nolus-protocol - Nolus full node (RPC): https://rpc.nolus.network - Nolus gRPC: https://grpc.nolus.network ## Contact For questions about this API or to report incorrect data, open an issue at https://github.com/nolus-protocol/extract-transform-load.