How to query Iris Core data with the API?
You can query Iris Core data with the GraphQL API. Queries run against the GraphQL Playground. A few conventions carry through every example:- Examples read from the Ethereum mainnet staging fork (VNet,
chainId: 9991); an integration moves to another network by changing thechainId. - By default the API returns only the first 50 results; pass
limit(up to 1000) and page with cursors for more. TheloanPositionsview pages byoffsetinstead. - Addresses are lowercase hex, and filters are exact-match.
BigIntvalues are returned as strings; rates and LLTVs are WAD (1e18), amounts are in the token’s own decimals.- Plural query names are generated from table names:
blmParamss,marketDatas, andwhitelistEntrysare not typos.
Discovery and Listing
Loans List
A loan is identified by its pod, the isolated clone address holding that borrower’s position.(chainId, pod) is the primary key everywhere in this API.
- All Loans
- By Borrower
- By Solver
- Specific Loan
position.
Loan and position in one filter
where cannot traverse a relation, so a condition spanning both sides (a solver’s loans that still carry a bond requirement, say) needed two queries and a client-side join.
loanPositions is a read-only view over loan joined to position on (chainId, pod). Every column of both tables sits flat on one row, so a single where can filter across both.
- Plural only. There is no single-row
loanPosition(chainId:, pod:)lookup; filter onpodinstead. - No relations.
collateralTokenanddebtTokenare raw addresses here, not token objects, so{ symbol decimals }does not resolve. Read metadata fromtokensin the same request. - Offset paging, not cursors.
afterandbeforeare not arguments on this query, andpageInfocarrieshasNextPageandhasPreviousPagewithout cursors. Page withlimitandoffset. orderByis required to page safely. A view has no primary key to break ties on and no default order, so a paginated read must order on an effectively unique column (pod, withchainIdfiltered), or pages can skip and repeat rows.
AND and OR, a default page of 50 rows, and a totalCount over the whole filtered set.
Position Metrics
Collateral, Debt & Bond
position is one-to-one with loan on (chainId, pod) and holds everything mutable.
- All Positions
- Specific Position
bond and bondRequirement are in the debt token’s decimals, collateral in the collateral token’s; a closed loan keeps its row with debt: "0".
Fixed vs Floating Legs
Legs are as of
lastUpdate, not as of now.
Bond Health
bond < bondRequirement, or when ceil((floatingLeg - fixedLeg) × 1e18 / bond) exceeds bondLltv. Both legs are as of lastUpdate, so a ratio computed from them understates a position that has not been touched in a while. For that comparison computed against live venue indices, read positionHealths. See Bond Mechanics.
Liquidatability estimates
positionHealths carries one row per open loan. bondHealthFactor is refreshed by a poll that reads each market’s venue indices onchain and accrues the legs to the poll block, and venueLiquidated follows the venues’ liquidation events. The entity exists so a keeper can filter and sort liquidatability server-side instead of pulling every position and recomputing it client-side.
Five things to know before filtering on it:
bondHealthFactoris an estimate,liquidatableAtis exact. The factor is accurate as ofupdatedAtand drifts until the next poll, so filter with a margin above1and re-verify onchain before sending a transaction.liquidatableAtcomes from the loan’s own terms and does not move.nullmeans no drawdown, not “unknown”: the floating leg is not above the fixed leg. Becausenullnever satisfies a comparison, anybondHealthFactor_*filter drops those rows, which is what a keeper scan wants.- It does not cover the whole bond check.
bondHealthFactoronly compares drawdown tobondLltv. A bond is also unhealthy whenbond < bondRequirement, which is a filter onloanPositions. venueLiquidatedis over-inclusive. It turnstruewhen Morpho Blue emitsLiquidateor Aave V3 emitsLiquidationCallfor an open loan’s pod, and back tofalseat the next IRIS action that accrues or rebases the position. It can staytruefor a position with nothing left to recognize, so filter onvenueLiquidated: trueto find positions awaiting arebaseand check onchain before sending one.- Rows exist only while the loan is open. A row is created in the block the loan opens, with
bondHealthFactornulluntil the first poll, and is deleted by the first poll after the loan closes. There are no relations on this entity, so read the loan and position fields in a second query keyed bypod.
bondHealthFactor is the solver’s bond against its drawdown. It is unrelated to the borrower’s venue health factor, which IRIS does not index.
Loan Status
Status is not a column: it is derived at read time fromdebt, maturity, and overduePeriod.
now in unix seconds:
Of these,
closed is a filter on debt, and the liquidatable set is positionHealths(where: { liquidatableAt_lte: now }), whose rows are open by construction. For the rest, fetch the live set with positions(where: { debt_gt: "0" }) and classify client-side, comparing now against the indexed block timestamp from _meta { status }.
Position Tracking
Borrower All Loans Position
Everything a borrower needs on one screen: terms, live balances, and both USD legs.Borrower Account Overview
Loans, claimable balances, and delegated managers in one request.Solver Book
A solver’s whole exposure: loans underwritten, bond posted against bond required, and unclaimed earnings. To narrow the book by aposition field as well as a loan field, filter the loanPositions view instead.
Bond
BLMs List
A bond lock module (BLM) sets how much bond a solver must post.WhitelistBlm; one with none is a plain Blm.
Bond Curve Parameters
Curves are keyed per debt token, so a single BLM prices USDC and USDT loans independently.- All BLMs
- Specific BLM
position.bondRequirement is computed once at loan open as debt × (slope × duration / 86400 + intercept) / 1e18; see Bond Mechanics.
Solver Whitelist
isWhitelisted: false after a removal, so always filter on the flag.
Enabled Bond LLTVs
The set of bond LLTVs governance permits a quote to use.Venue & Settlement
Venue Adapters
Every position sits in exactly one venue, addressed byvenueId and served by an adapter contract.
loan.venueBitmap is the set of venues the loan may move within (bit n set = venue n allowed); position.venueId is where it is right now.
Enabled Market Data
data is keccak256 of a venue-market blob; hash the blob you hold to check whether it is enabled.
Refinance & Rebase State
Refinancing moves a position between venues, re-snapshotting the venue indices and the market blob.position.data is the raw blob for the current venue (0x when the venue takes no parameters), the pre-image whose hash appears in marketDatas.
Protocol Configuration
Owner, Fee & Fee Recipient
One singleton row per chain.config.fee is the live protocol fee; loan.fee is the value snapshotted when that loan was opened.
Authorization
Borrowers can authorize a manager to act on their positions.isAuthorized: false after revocation, so filter on the flag.
Claimable Balances
Credited earnings (solver interest, protocol fees, collateral surplus) that have not yet been claimed.(chainId, token, account); claims decrement rather than delete, so a zero amount means fully claimed.
Token Metadata
Token metadata is resolved off-chain for every token the protocol references. USD prices are sourced from DefiLlama.Token List
UNKNOWN placeholders rather than omitted.
Prices
priceUsd is refreshed every 5 minutes, is nullable, and is a Float; parse it as a number, not a BigInt.
Token Relations
Any token address field expands in place, which removes the second round trip.{ address } if you need the hex.
Historical Data
The API serves current state only: every row reflects the latest indexed block, with no event log, snapshot table, or timeseries. For now, read the contract event logs directly, or index them yourself; historical timeseries data will be added to the API in a future release.Paging, Ordering & Filtering
Every plural query accepts the same arguments:where, orderBy, orderDirection, limit, and cursor paging via after / before with pageInfo. The one exception is the loanPositions view, which takes offset in place of the cursor arguments; see Loan and position in one filter.
AND and OR take lists of filters and nest:
limit above the 1000 cap fails with a masked INTERNAL_SERVER_ERROR (“Unexpected error.”); where cannot traverse relations, so cross-entity conditions are a second query plus a client-side join, except for loan and position, which the loanPositions view already joins; prefer cursors over offset for full scans, since offset can skip or repeat rows if a write lands mid-scan.
