Every endpoint the API serves, with its parameters, errors and webhooks. Generated from the specification rather than written beside it, so it cannot describe a version of the API that no longer exists.
53 operations across 10 groups, and 2 webhook events. Plans and pricing.
Base URL https://aspern.org/api. Authenticate with X-API-Key, issued from your account page. Ratings and this document need no key.
| Setting | Value | Why it matters |
|---|---|---|
| Base URL | https://aspern.org/api | Every path below already begins with /v1, do not put it here too. |
| Auth header | X-API-Key | Not Authorization. |
| Auth scheme / prefix | none | The key is sent raw. A "Bearer" prefix makes the key unreadable. |
| Spec path | /v1/openapi.json | Relative to the base URL above. |
curl -s https://aspern.org/api/v1/vaults?agentManaged=true&limit=5 \ -H "X-API-Key: $ASPERN_KEY"
Errors carry the reason. A 402 means the call is outside your plan and names what would cover it; 429 means the quota is spent, not that the data is missing. Neither is ever returned as an empty result, an empty list from this API means we looked and found nothing.
Every response states what it cannot see. Coverage, sample size and the mechanism behind a figure travel with the figure, because a number read without them is the failure this platform exists to prevent.
What we think of a strategy. Free, the argument is worth more to us published than sold.
/v1/vaultsThe vault universe, filterable.
A vault absent here is one we do not observe, not one that does not exist. Free.
| Parameter | Type | In | What it does |
|---|---|---|---|
| q | string | optional | Name or address fragment. |
| chain | string | optional | e.g. hyperliquid, drift. |
| platform | string | optional | Platform id. |
| agentManaged | boolean | optional | Restrict to machine-managed. `machineManaged` is accepted as a synonym. |
| minTvl | number | optional | Floor on stated size. |
| closed | boolean | optional | Include vaults we have recorded as shut. Excluded by default. |
| lifecycle | string | optional | live | dead | unlaunched | unknown. `dead` reaches the failures in one call rather than past eleven hundred rows of survivors, and implies closed=true. `unlaunched` is a vault nobody ever deposited into, which is not a failure. |
| format | string | optional | 'csv' returns a spreadsheet rather than JSON. Needs export.bulk, so this otherwise-free route answers 402 for that one value. |
| limit | number | optional | Default 50, capped at 100, or 1000 with export.bulk. |
| offset | number | optional |
/v1/vaults/{slug}One vault: metrics, value series, positions, execution quality, and what evidence exists for it.
The `available` block is free at every tier and states what this platform HOLDS for the vault, fills, positions, funding accrual, liquidation prices, whether or not the key may read it. An absence and a paywall are different facts: a 402 from /v1/funding or /v1/stress means the data exists and the tier does not carry it. `performance.execution` carries turnover, taker share and fee basis points where the vault has traded enough for them to mean anything, and null where it has not. Free.
| Parameter | Type | In | What it does |
|---|---|---|---|
| slug | string | in path | Vault slug. |
/v1/operatorsOperator cohorts, survivors and failures kept in.
Free.
| Parameter | Type | In | What it does |
|---|---|---|---|
| limit | number | optional | Default 50, capped at 200. |
| offset | number | optional |
/v1/operators/{slug}One operator and its whole book.
Free.
| Parameter | Type | In | What it does |
|---|---|---|---|
| slug | string | in path |
/v1/assetsInstruments and who holds them.
Free.
/v1/indexThe machine-managed capital index, with its constituents.
Requires `index.read` — PUBLIC or PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| from | string | optional | ISO date, inclusive. |
| to | string | optional | ISO date, inclusive. |
/v1/benchmark/{symbol}A benchmark series to compare against.
Free.
| Parameter | Type | In | What it does |
|---|---|---|---|
| symbol | string | in path |
/v1/metaCounts, capabilities your key holds, and the standing limitations.
Free.
/v1/assets/denominationsWhat the capital is denominated in, and whether that thing is worth what its name claims.
Only a dollar claim can be checked here: there is no ether or bitcoin reference price, so those are unpriced rather than sound. A dollar-named token priced far from a dollar is a ticker collision rather than a depeg, and its price is refused. Free.
What each vault and operator actually did, read from the chain rather than reported to us.
/v1/vaults/{slug}/waterfallGross to net, and whether it was earned by being right or by being paid to wait.
Measured over the window funding can be measured over, not the vault’s lifetime. Requires `waterfall.read` — PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| slug | string | in path |
/v1/vaults/{slug}/executionTaker share, fee rate and how it gets filled.
Requires `fills.read` — ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| slug | string | in path |
/v1/vaults/{slug}/tradesHit rate, payoff and holding period, rebuilt from the venue’s own open and close labels.
A high win rate beside a payoff below one is the signature of selling optionality. Requires `trades.read` — PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| slug | string | in path |
/v1/forced-exitsWhat the venue did against a book’s will, and when several went at once.
Observed, not modelled, the only thing here that can contradict the stress ladder. Requires `forced.read` — PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
What a shock costs you: look-through exposure, liquidation distance, forced selling.
/v1/riskPrice a holding you already have: look-through exposure and what a move costs you.
Losses are pro rata on vault equity; a waterfall or first-loss tranche will not lose pro rata. Requires `risk.read` — ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
"{ holdings: [{ vault, usd }], instruments?: string[], shocks?: number[] }"/v1/stressWho is liquidated as one instrument moves, and at what named price.
Only the named instrument moves, so every figure is a floor. Requires `stress.read` — ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| instrument | string | required | |
| scale | string | optional | 'sigma' places rungs by distance rather than round numbers. |
| sigmas | string | optional | Comma-separated rungs, in standard deviations, replacing the defaults. |
| horizonDays | number | optional | Default 30. |
/v1/cascadeThe forced selling that follows a first round, and where it lands.
Impact from quoted depth reads about four times below the volatility model; the response says which was used. Requires `cascade.read` — ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| instrument | string | required | |
| shock | number | required | Fractional move, -0.95 to 0.95. |
| horizonDays | number | optional | Default 30. Sets the volatility window behind the impact model. |
/v1/correlationWhether vaults are the same trade once the market is removed.
Every figure carries its overlapping days and an interval; an indistinguishable pair says so. Requires `correlation.read` — PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| vaults | string | optional | Comma-separated slugs, two to twelve. Omit for the cohort. |
| agentManaged | boolean | optional | Restrict the cohort to machine-managed vaults. |
| limit | number | optional | Default 20, capped at 50. |
/v1/vaults/{slug}/redemptionWhat a withdrawal does to the strategy behind it, and whether it could be paid at all.
The venue returns at most a hundred depositors, so holder counts are floors. For a lending vault the binding constraint is liquidity rather than margin: scenarios carry exceedsLiquidity and unmetUsd, and a null withdrawableUsd means unread rather than unlimited. Requires `redemption.read` — ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| slug | string | in path |
/v1/changesWhat changed: which vault stopped being exitable, which died, which raised a new observation.
The feed began when it began, nothing before that was missed, it was not yet running. A change on a vault holding under $50,000 is not announced. Free.
| Parameter | Type | In | What it does |
|---|---|---|---|
| kind | string | optional | exit.locked | exit.freed | vault.died | vault.reopened | observation.raised |
| days | number | optional | How far back. Default 30. |
| minUsd | number | optional | Floor on the capital behind the change. |
| limit | number | optional | Default 50. |
| offset | number | optional |
/v1/liquidityWhich lending vaults cannot be withdrawn from today, and how long that has been true.
Read for Euler, Morpho and Lista. A vault absent here is one whose liquidity we do not read, never one with none locked, and the history begins the day we started keeping it, because a market’s past free liquidity needs an archive node nobody offers free on BNB. Free.
| Parameter | Type | In | What it does |
|---|---|---|---|
| locked | boolean | optional | Only the vaults nothing can be withdrawn from. |
| minUsd | number | optional | Floor on capital. |
| days | number | optional | How much history to return per vault. Default 30. |
| limit | number | optional | Default 50. |
/v1/liquidity/unmovedHow long each book has sat fully lent, and whether anybody acted.
Times the consequence, not the control: we do not hold LTV or caps, so this measures how long a depositor could not leave rather than when a parameter was changed. A duration marked "atLeast" began before our readings did, and the register starts the day we started keeping it. Requires `reactivity.read` — PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| minUsd | number | optional | Floor on the capital stuck. |
| collateral | string | optional | Restrict to one collateral. |
| limit | number | optional | Default 50. |
/v1/exposure/nettingWhere longs and shorts cancel, and where they only appear to.
Requires `positions.read` — PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
/v1/operators/{slug}/exposureOne operator’s book across every vault it runs.
Requires `positions.read` — PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| slug | string | in path |
/v1/capital/deploymentHow much of the capital we track we can watch being used, by kind of vault.
Knowing how much a vault holds and knowing what it does with it are different readings. Every dollar counted sits in a contract anybody can check; what is missing is our reading. And where positions ARE read, a hedge on a centralised venue is invisible to us, so a one-sided book may be flat. Free.
The market around a position, crowding, correlation, who leads and who follows.
/v1/crowdingWho is in the same trade, and what share of the venue that is.
Requires `crowding.summary` — PUBLIC or PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| instrument | string | optional | Restrict to one instrument. |
| members | boolean | optional | Include cluster membership. Needs a plan. |
| asOf | string | optional | Read the book as it stood. Pins to the newest snapshot at or before this instant, and the reply says which one it landed on. |
/v1/crowding/historyWhether a crowd is building or dispersing.
Requires `crowding.timeseries` — PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| instrument | string | optional | |
| days | number | optional |
/v1/fundingWhat holding a perpetual costs or pays, and who is on each side.
Annualised simple. A vault collecting today can be paying tomorrow. Requires `funding.read` — PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| limit | number | optional | Default 25. |
/v1/marketsWhether an instrument is still a market, and how much notional is marked in ones that are not.
Requires `markets.read` — PUBLIC or PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
/v1/lead-followPairs whose trades follow one another sooner than chance accounts for.
It does not say copying. A shared vendor, one operator, or the same obvious level all look identical from a timestamp. Requires `leadfollow.read` — ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| days | number | optional | Default 7. |
Series over time. Every point is a measurement taken then, never a backfill of what we believe now.
/v1/history/capitalDaily measured capital, split by who decides.
Days rebuilt from stored value history are marked. A rebuilt day carries today’s cohort and classification, so it is survivorship-biased backwards. Requires `crowding.summary` — PUBLIC or PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| from | string | optional | ISO date. Defaults to a year back. |
| to | string | optional | ISO date. Defaults to today. |
Commit to a decision before executing, reveal it afterwards, and let anyone check the two match.
/v1/resolveSettle a condition about a vault from our records, or decline to.
Deterministic and recomputable. A window we do not fully span is refused rather than answered on the part we hold. No collateral backs it. Free.
"{ kind, vault, from, to, threshold?, instrument? }"/v1/vaults/{slug}/assessmentA hash-committed assessment, in the shape ERC-8004’s Reputation Registry points at.
ASPERN does not publish on chain; the call arguments are returned for whoever does. Free.
| Parameter | Type | In | What it does |
|---|---|---|---|
| slug | string | in path | |
| methodology | string | optional | Build the document at an older methodology version, so a hash issued under it stays checkable. /v1/meta lists what this build can produce. |
Whether a sequence is intact, checkable without trusting us.
/v1/registryPre-register a strategy before it runs. Free.
Free.
"A signed declaration; see /register for the exact text."
/v1/registryDeclarations already signed.
Free.
| Parameter | Type | In | What it does |
|---|---|---|---|
| address | string | optional | |
| management | string | optional | |
| limit | number | optional |
/v1/commitCommit to a decision before executing it.
Free.
"{ digest, seq, leaf }"/v1/revealReveal it afterwards; we match it against the chain.
Free.
"{ digest, seq, nonce, intent }"/v1/attestation/{digest}Whether a sequence is intact. A gap voids the grade permanently.
Free.
| Parameter | Type | In | What it does |
|---|---|---|---|
| digest | string | in path |
Watches you arm, and the webhooks they fire.
/v1/watchesYour alerts, where they deliver, and what has fired.
With no webhook registered a firing is recorded and readable but reaches nothing. Requires `crowding.members` — PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
/v1/watchesArm an alert, or change its threshold.
The threshold is a fraction, not a percentage: 0.9 means 90%. Changing it re-arms, so the next crossing fires. Requires `crowding.members` — PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
"{ kind: crowding|consistency|drawdown|version|proximity, target: instrument or vault slug, threshold: fraction between 0 and 1 }"/v1/watches/{id}Disarm an alert.
Requires `crowding.members` — PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
| Parameter | Type | In | What it does |
|---|---|---|---|
| id | string | in path | Watch id. |
Your balance, quota, plans and this document.
/v1/openapi.jsonThis document. Free, so it can be read before deciding whether to buy a key.
Free.
/v1/plansPrices and quotas. No key needed.
Free.
/v1/lineageWhat every lineage block on this API means, field by field, and why several of them are null.
A vault read from a venue HTTP API has no block number and a document assembled from four readers has no single source event id. Those fields are null with a reason rather than filled with something plausible. Free.
/v1/proofThe capital and payments a reader can re-derive themselves, and the gaps, weighted by capital.
Nothing is corrected from these checks: a disagreement has more than one possible owner. Hyperliquid is absent by nature — an order book has no contract holding the capital to be asked. Free.
/v1/differencesWhere our figures disagree with a public source, and the stated reason.
The ratio is not an error rate: most pairs are different units over different windows. A row with state=open is a difference we have not explained, published rather than left out. Free.
/v1/limitsWhat is withheld from an unkeyed caller, per surface, and what a plan opens.
A short list is not necessarily all of the data. This says how many rows come whole, how many follow with one field withheld and which field that is, so a caller never has to infer a limit by hitting it. Free.
/v1/accountYour balance, quota and deposit address.
Free.
/v1/ops/ingestCollection health. Admin only.
Requires `ops.read` — . Without it the call answers 402 with the amount and a deposit address.
/v1/agents/railsHow many registered agent identities ever appear on a rail that moves money.
A floor: the registry side is the identity token’s holder and the rail side is whoever paid, so an operator using two keys reads as absent. Three rails are read — ACP, the Olas mech marketplace, x402. Free.
/v1/agents/claimsWhat agent cards claim about the other registries they are in, and whether the claim holds.
Three states and they never merge: found, absent on a registry we read over its whole life, and unread — which is our coverage gap rather than their claim. A self-claim, naming the registry the card is already in, is counted separately and is not a link. Free.
/v1/agents/workEvery rail this platform reads, counted from each rail’s own table.
The units differ per rail and are named rather than added together: a channel is not a payment, a job is not a payment, and a registration is not either. A rail with no span carries no event time we can trust — the Solana registries are read by scanning the program, so the only date on a row is when we read it. Free.
/v1/agents/deliveryWho delivered and who did not, provider by provider, on the ACP job book.
Rates are over jobs that REACHED an outcome. A job still in negotiation has not failed, and one we never saw a phase for is a gap in our reading rather than an event in the market; both are reported beside the rate rather than folded into it. Requires `delivery.read` — PRO or ENTERPRISE. Without it the call answers 402 with the amount and a deposit address.
/v1/agents/payersWho pays on x402, separated by observable behaviour rather than by label.
No class claims “agent”. They separate behaves-like-a-program from we-cannot-tell. Payments are counted, never summed across tokens. Free.
We POST to your endpoint when a watch fires. The signing scheme below is also shipped as verifyWebhook in our published package, the same function we sign with, so this description cannot drift into a scheme subtly different from what you receive.
watch.firedA watch you armed has crossed its threshold.
Sent to every active endpoint registered for this event, at most once per watch per crossing. **Verifying.** Each request carries `x-aspern-signature: t=<unix-seconds>,v1=<hex>`, where the hex is HMAC-SHA256 over the exact string `<t>.<raw request body>` keyed by your webhook secret. Sign the BYTES you received: re-serialising the parsed JSON produces a different signature and the delivery becomes unverifiable. **Replay.** Reject a timestamp more than 300 seconds from your own clock. Compare the digest with a constant-time comparison. **Retries.** A non-2xx is retried with exponential backoff from one minute, doubling, capped at six hours, with up to 20% jitter added, never subtracted, so a retry is never earlier than its backoff. A 4xx other than 408 and 429 is treated as permanent and not retried: you understood and refused. **Ordering and duplicates.** Delivery is at-least-once and not ordered. Use the `id` to make your handler idempotent.
{
"id": "whd_2f8a1c",
"event": "watch.fired",
"createdAt": "2026-08-27T09:14:02.117Z",
"watch": {
"id": "wch_91b2",
"kind": "drawdown",
"target": "morpho-steakhouse-usdc",
"threshold": 0.05
},
"observed": {
"value": 0.062,
"at": "2026-08-27T09:12:00.000Z"
},
"subject": {
"slug": "morpho-steakhouse-usdc",
"name": "Steakhouse USDC",
"chain": "ethereum"
}
}webhook.testA test delivery, sent when you ask for one.
Identical in shape and signing to a real event, so a receiver that verifies this one verifies all of them. Sent on demand from the account page, the only way to find out your endpoint rejects our signature before a real alert depends on it.
{
"id": "whd_test_01",
"event": "webhook.test",
"createdAt": "2026-08-27T09:00:00.000Z"
}