> ## Documentation Index
> Fetch the complete documentation index at: https://xoxno.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrator API

> Read position arrays and asset capacities with prices, token metadata, and explicit missing-data states.

The v1 API combines indexed lending state, token metadata, and lending prices
into arrays your application can display. Use the
[wallet guide](/docs/stellar-lending/dev/wallet-integration) for the integration flow.

| Network | API root |
| - | - |
| Mainnet | `https://api.xoxno.com` |
| Testnet | `https://testnet-api.xoxno.com` |

Both networks serve the routes below. Keep the API network aligned with the
selected RPC, contracts, token addresses, and wallet signing passphrase.

## Routes and types

| Route | Response |
| - | - |
| `GET /stellar-lending/v1/assets` | `LendingAsset[]`; assets listed as collateral on at least one spoke. |
| `GET /stellar-lending/v1/assets?usage=borrow` | `LendingAsset[]`; assets listed for borrowing on at least one spoke. |
| `GET /stellar-lending/v1/users/{owner}/positions` | `LendingPosition[]`; one item per indexed owned position NFT. |

`owner` must be a valid Stellar `G...` account or `C...` contract address.
URL-encode it when constructing a path. These reads require no API key.
Invalid owners, page sizes, cursors, and `usage` values return HTTP 400.

Listing membership does not mean an action is currently available. Read the
spoke flags and capacities, then simulate the selected transaction.

Public types and OpenAPI schemas belong to the SDK:

```ts theme={"system"}
import {
  type LendingAsset,
  type LendingPosition,
  type PositionAsset,
  type Capacity,
  lendingAssetsSchema,
  lendingPositionsSchema,
} from '@xoxno/sdk-js/stellar-lending/read'
```

The schemas describe array bodies, not an object with a `positions` key.
The lightweight client checks HTTP status, array bodies, and safe pagination.
It does not validate every response field against a schema at runtime.

## Shared token fields

Every asset and position leg contains:

| Field | Meaning |
| - | - |
| `sac` | Token contract address, including Stellar Asset Contracts. Use it as the token identifier. |
| `symbol`, `name` | Display labels. They do not identify the token uniquely. |
| `decimals` | Token decimal places, or `null` when unavailable. |
| `logoUrl` | Token image URL, or `null`. Handle failed requests and supported image formats. |
| `hubId`, `hubName` | Liquidity hub. Identify a market with both `hubId` and `sac`. |

The API reads names and logos from token metadata. Listed asset information
can supply a fallback name or symbol. Prices come from lending oracle market
data. You do not need a separate price feed or token-catalog join to display
these responses.

## Position fields

| Field | Meaning |
| - | - |
| `accountId` | Decimal account id string. It identifies the position NFT within `nftContract` and `network`. |
| `nftContract`, `network` | NFT collection and Stellar network. |
| `nftImage` | Dynamic SVG URL on the network's XOXNO API. The path is `/user/lending/image/{accountId}?isStatic=true&chain=STELLAR`. |
| `spokeId`, `spokeName` | Account's risk spoke, or `null`. |
| `supplied` | Supplied token legs. |
| `borrow` | Debt token legs. The JSON key is `borrow`. |
| `hasDebt` | Boolean, or `null` when account rows are unavailable. |
| `healthFactor` | Threshold-weighted collateral divided by debt. Below `1` can permit liquidation. `null` means no debt or unavailable data; inspect `hasDebt`. |
| `borrowLimitUsd` | Estimated borrowing limit using stored account LTV weights, clamped to liquidation thresholds. |
| `availableBorrowUsd` | Account headroom after debt and the minimum-borrow-collateral floor. Market and action constraints still apply. |
| `netApy` | Annual supply income minus debt cost, divided by positive net equity. `null` when inputs or positive equity are unavailable. |
| `dataStatus` | `ready`, `stale`, or `incomplete`. |

Each `PositionAsset` in `supplied` or `borrow` also contains:

| Field | Meaning |
| - | - |
| `amountRaw` | Integer token base-unit string. Supply rounds down; debt rounds up. `null` means the balance could not be computed. |
| `amount` | Decimal whole-token string derived from the raw amount and decimals. |
| `apy` | Supply yield or borrowing cost as a fraction. `0.05` means 5%. |
| `valueUsd`, `priceUsd` | Estimated leg value and price per whole token, in USD; nullable. |
| `priceStatus` | Price validity, staleness, deviation, and timestamp fields. |
| `indexRay` | Applied interest index as an integer RAY string, or `null`. |
| `indexedAt`, `indexedLedger` | Position row's indexed timestamp and ledger. |

Preserve raw strings. Display numbers are not exact transaction-sizing or
contract-admission inputs. The API applies interest indexes; do not apply
legacy RAY balance conversion to v1 `amountRaw`.

## Asset and spoke fields

An asset item describes one `(hubId, sac)` market. One SAC can appear in several
items when it belongs to several hubs.

| Asset field | Meaning |
| - | - |
| `network` | `mainnet` or `testnet`. |
| `supplyApy`, `borrowApy` | Market yield and cost as fractions, or `null`. |
| `priceUsd`, `priceStatus` | Lending price and its status. |
| `spokes` | Listings that match the requested collateral or borrow usage. |
| `dataStatus` | Availability of the inputs checked for this item. |
| `indexedAt`, `indexedLedger` | Hub market's indexed timestamp and ledger. |

Each spoke item contains:

| Field | Meaning |
| - | - |
| `spokeId`, `spokeName` | Risk configuration used by an account. |
| `ltvBps` | Listing LTV clamped to its liquidation threshold. `10,000` means 100%. Existing accounts can have different stored weights. |
| `supplyCapacity`, `borrowCapacity` | Estimated market headroom as `Capacity` objects. |
| `canSupply` | Checked listing flags and computed capacity permit positive supply in this snapshot. |
| `canBeCollateral` | Listing is collateralizable and its checked entry flags permit supply. |
| `canBorrow` | Checked listing flags, capacity, and usable price permit borrowing in this snapshot. |
| `canOpenAccount` | Spoke exists and is not deprecated. Other admission rules still apply. |

`Capacity` contains `amountRaw` as a base-unit string, `amount` as a whole-token
decimal string, and `usd` as a display number. Each can be `null`. Zero means
no estimated headroom. Supply capacity considers spoke cap usage and known
pool backing. Borrow capacity also considers shared liquidity, the cash buffer,
and maximum utilization.

These booleans and capacities do not check every global pause, account rule,
wallet balance, or authorization. A `ready` response does not guarantee that
a transaction will succeed.

## Missing data and freshness

`priceStatus` contains `valid`, `stale`, `deviation`, and `timestamp`. The timestamp
is in Unix seconds; `null` means no market timestamp was available. An
unusable price makes `priceUsd` null. Dependent USD and risk values can become
unavailable while raw balances remain.

* `ready`: the inputs checked by this builder are available.
* `stale`: indexed ownership or market information needs reconciliation.
* `incomplete`: required rows, metadata, prices, or computation inputs are missing.

Inspect individual fields. `incomplete` takes precedence over `stale`; a missing
logo can make an item incomplete. Keep known balances visible. Do not replace
missing data with zero or treat the NFT image as evidence of a current balance.

Assets use `Cache-Control: public, s-maxage=10`. Wallet positions use
`Cache-Control: no-store`. The backend also caches computed asset bodies for
5 seconds, position bodies for 3 seconds, and token metadata for 600 seconds.
It queries indexed NFT ownership on every wallet request before reusing a body.

These intervals do not prove data is only that old. Indexing, state snapshots,
oracle reads, metadata, and HTTP caches have separate freshness limits.
The ownership query reads indexed inventory, not live `owner_of` state.
Use contract views or simulation where current ledger state matters.

Refresh after confirmed success and when the wallet or network changes.
Keep a refreshing state while the indexer catches up. Do not repeat a successful
transaction because the API still shows the previous snapshot.

## Pagination

Positions accept `limit` from 1 to 100; the default is 50. `cursor` is opaque
and scoped to the owner, network, and NFT collection. Do not construct it.

Follow `Link` with `rel="next"` until absent, including after an empty page.
Resolve relative links against the current page URL. Every leg of one NFT stays
on the same page. Order follows indexed NFT identifiers, not numeric account
ids or health factor. Several pages are not an atomic ledger snapshot.

The SDK's `read.positions(owner)` collects pages, rejects redirects and
cross-endpoint links, and detects cycles. Direct implementations need equivalent
URL and cycle checks. Keep HTTP failures distinct from empty results.

## Legacy reads

The unversioned `/stellar-lending/users/{owner}/positions` returns an object
with position legs and RAY quantities. It differs from this v1 array contract.
Advanced readers can still use context, reserve, live-state, and detailed-market
endpoints. Do not apply their balance conversions to v1 raw amounts.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.