Pull our numbers into your notebook and check us.
Every figure ParetoAlpha shows a family starts from tables the family loaded. The API hands those tables back as they stood for any statement date, as they were known on any day since, with the hash of every stored version and of every response. The returns, exposures and factor estimates come from the same deterministic engine the portal uses, and their methods are written out below. If your number disagrees with ours, you will be able to say exactly where.
Can I call it before I talk to anyone?
Yes. The token below is public on purpose. It reads one synthetic family (three entities, ten positions, two closed-end funds, thirty month-ends; invented, nobody’s money) on the production API, through the same code, database isolation and rate limit a client’s token gets. Both dates are pinned, and the simulation is seeded, so the content hash you receive is the one everyone receives: run it twice, or next month. Our own monitor asks the same questions every five minutes and alarms if a hash moves without a new engine digest; its record is public on the status page.
export PA=pa_live_tKS9QsWktZz43k5lIeulnyXM5_F-DhcDhsCGtqrSjn4
Q='asOf=2026-06-30&knownAt=2026-09-21T18:24:17.951Z'
# what each entity's capital calls would require, across 2,000 seeded paths
curl -s -H "Authorization: Bearer $PA" "https://paretoalphasystems.com/api/v1/pacing?$Q&paths=2000&quarters=20&seed=20260921" | head -c 900
# the same, under fat tails (a shared crisis regime, kurtosis 7.65), with what the buffer and CVaR owe to the tail
# assumption and to the size of the shocks: same paths, other laws
curl -s -H "Authorization: Bearer $PA" "https://paretoalphasystems.com/api/v1/pacing?$Q&paths=2000&quarters=20&seed=20260921&tails=fat&sensitivity=on" | head -c 900
# where the same risk sits in several entities, with standard errors
curl -s -H "Authorization: Bearer $PA" "https://paretoalphasystems.com/api/v1/concentration?$Q&view=loadings"
# the after-tax cost of raising 250,000 in one entity, lot by lot (arithmetic, executes nothing)
curl -s -H "Authorization: Bearer $PA" "https://paretoalphasystems.com/api/v1/sequence?$Q&entity=T1&cash=250000"
# the same, for what the capital-call simulation says the entity needs: one call, one seed, and a ladder
# of lot lists at 50/75/90/95/99% confidence, so you see which lots enter as the stress rises
curl -s -H "Authorization: Bearer $PA" "https://paretoalphasystems.com/api/v1/sequence?$Q&entity=T1&cash=calls&seed=11&stress=on&exclude=RE-L1"
# then check the hash yourself (prints True)
curl -s https://paretoalphasystems.com/developers/verify.py -o verify.py
curl -s -H "Authorization: Bearer $PA" "https://paretoalphasystems.com/api/v1/book?$Q" -o book.json
python3 -c "import json, verify; b = json.load(open('book.json')); print(verify.content_sha256(b['data']) == b['meta']['contentSha256'])"The sandbox token is shared, so its 240 reads per ten minutes are shared too; a 429 means someone else is busy. It expires 2027-09-22 and is replaced here before then. Rebalancing is switched off on this deployment and unpublished. What these three endpoints answer for a family, in plain words: FULCRUM, the forward view. To run this on your own book, ask for access.
What is the difference between asOf and knownAt?
asOf is the statement date the rows describe: the book at 31 March. knownAt is the instant by which a version had been recorded: the book at 31 March as we knew it on 15 April. A March statement restated in August answers asOf=2026-03-31 today and does not answer asOf=2026-03-31&knownAt=2026-04-15. For each table the API returns the version with the latest statement date on or before asOf, among those recorded on or before knownAt; within one statement date the latest recording wins. A table with no such version is absent, never empty, and the sample book is never served.
Versions are append-only and hash-chained; nothing is edited in place. meta.restatedSince lists any table whose answer has been superseded by a later recording, so a backtest can tell a restatement from a disagreement. A bare knownAt date means the end of that day, UTC.
# A backtest that cannot see the future: each date reads the book as it was KNOWN 45 days later.
import pandas as pd
dates = requests.get(f"{BASE}", headers=H).json()["data"]["statementDates"]
frames = []
for d in dates:
known = (pd.Timestamp(d) + pd.Timedelta(days=45)).date().isoformat()
b = requests.get(f"{BASE}/book", headers=H, params={"asOf": d, "knownAt": known, "tables": "positions"}).json()
if b["meta"]["restatedSince"]: # the figure you would see today differs from what was known then
print(d, "was restated after", known)
frames.append(pd.DataFrame(b["data"].get("positions", [])).assign(asOf=d))
panel = pd.concat(frames)What can be read?
| GET | Returns |
|---|---|
| /api/v1 | This index: endpoints, the statement dates on file, and the range of recording times. |
| /api/v1/versions | Every recorded version of every table: statement date, when and by whom it was recorded, row count, the SHA-256 of its rows and its link in the anchored chain. No rows. |
| /api/v1/book?asOf=YYYY-MM-DD&knownAt=…&tables=positions,cashflows | The raw tables as they stood for a statement date, as known at an instant. Add &table=positions&format=csv for one table as CSV. |
| /api/v1/series?asOf=…&knownAt=… | Net worth by statement date and the period returns between them, computed by the same engine the portal uses, from the versions known at knownAt. |
| /api/v1/exposures?asOf=…&knownAt=… | Holdings-based exposures: asset class, liquidity, currency, entity, manager, and single-name concentration across entities and, when the family has loaded what its funds hold, through the funds (&lookthrough=off to see it without). |
| /api/v1/factors?asOf=…&knownAt=…&factors=ref:id,… | Returns-based factor exposure: a regression of the book's period returns on the factor series you name, with standard errors (classical, or Newey–West with &se=hac), or a refusal when there are too few observations. |
| /api/v1/concentration?asOf=…&knownAt=…&factors=equity:ref,rates:ref&limits=equity:60 | Factor exposure and risk added up across the family's entities through the ownership chain: shares of risk by factor and by entity (they add to one), the effective number of bets, and any factor spread across entities so that no one set of accounts shows it. With no factors named, one factor (broad equity at a stated volatility); with series named by role, an estimated covariance and loadings updated from the family's own marks. &view=loadings for the model itself. Measurement only: no trade is proposed. |
| /api/v1/pacing?asOf=…&knownAt=…&quarters=40&confidence=0.95&seed=… | Capital calls and distributions simulated fund by fund over up to ten years: the cash each entity needs to cover its peak net outflow at the confidence asked (exact to the cent), its CVaR, the chance today's liquid assets fall short, the programme by quarter against the deterministic forecast, and each fund's DPI, TVPI and forward PME by year. The bitemporal record of commitments, calls, distributions and marks replaces the book's cumulative figures where the family keeps one. Seeded: the same query returns the same content hash. |
| /api/v1/sequence?entity=…&cash=250000&neededBy=… | For a sale the family has already decided on, to put a stated amount of cash in one entity's hands after tax: its tax lots ranked by the tax each creates per dollar of cash it raises, which for this problem is provably the cheapest order. The family chooses; lots with no basis, pledged collateral and losses inside a wash-sale window in any entity are left out and listed. Exact to the cent. Nothing is ordered or sold. |
| /api/v1/stress?asOf=…&shocks=public_equity:-30,fixed_income:-8&rateBps=200 | The book run through every historical episode the engine carries, or through a shock you define: P&L by class, loan-to-value breaches and the cash to cure them, floating-rate repricing, and whether liquid assets last through drawdown and recovery. Deterministic; no simulation. |
| /api/v1/benchmarks | The series on file for this family (its own and the public reference series), with licence and provenance. |
| /api/v1/ledger?entity=…&asOf=…&knownAt=…&since=… | The general ledger's trial balance for a date, from the postings known at an instant: an entry reversed later still stands. With &since, the list of what was recorded between since and knownAt about dates up to asOf, with the cause and reason of each correction. |
| /api/v1/marks?asOf=…&knownAt=… | The latest valuation of each holding for a date, as known at an instant, with its basis, evidence grade and source. A NAV restated after knownAt is not served. &history=on for every recording, restated and withdrawn ones included. |
| /api/v1/fund-flows?asOf=…&knownAt=… | Private-fund commitments, calls and distributions dated up to asOf as known at an instant, with exact totals per fund: committed, called, distributed, unfunded. |
| /api/v1/ownership?asOf=…&knownAt=… | The ownership record: who holds what share of which entity on a date, as known at an instant, with the instrument that says so and the grade of that evidence. A share restated or an edge ended is a new row naming the one it supersedes; &history=all shows both. Cross-holdings are resolved exactly; a closed cycle, or owners adding to more than the whole, is refused when it is recorded. Where a family keeps this record, /concentration reads the chain through it (meta.ownershipFrom says which). |
| /api/v1/seals | FULCRUM seals: results a named person chose to keep. Each is the question, the answer's hash, the engine digest, and a statement of those facts signed with Ed25519 (public keys: /.well-known/fulcrum-keys.json), on an anchored chain. Read-only here: a seal is made from a signed-in session in the portal, never with a token, and the answer is computed again and compared first. Exploring is never counted; the same question under the same engine is sealed once. A seal instructs no one and executes nothing. |
| /api/v1/seals/[id] | One seal, with the exact bytes that were signed. verify_seal.py checks it with the standard library and no call to us: python3 verify_seal.py seal.json keys.json. |
| /api/v1/usage | The family's seal usage by calendar month (UTC), last twelve, from the same record the invoice is built on: seals made, the allowance the CIO seat carries, the number beyond it and their price, and whether the overage is metered to the card on file or billed by invoice. &format=csv for the months as CSV. |
| /api/v1/export?asOf=…&knownAt=… | Everything in /book as one bundle with a manifest, recorded in the export ledger under an export id and its SHA-256. |
JSON by default; &format=csv where a response is one table. There is no write endpoint. Authenticate with a signed-in session, or with a read-only token a principal or COO creates under Data access: Authorization: Bearer pa_live_…. A token belongs to one family, expires within 366 days, can be revoked at once, and only its SHA-256 is stored. Every read is on the family’s audit log; a bulk export is entered in the export ledger with the hash of the exact bytes. 240 reads per ten minutes per caller.
How do I check a response has not been altered?
meta.contentSha256 is SHA-256 of the canonical JSON of data, and the same value is in the X-PA-Content-SHA256 header. Each stored version carries rowsSha256 and its rowHash in the family’s chain, whose head is copied daily to write-once storage and timestamped by an outside authority under RFC 3161. meta.engine is the digest of the engine source that computed the answer, the same digest sealed into every proof. The canonical form writes numbers the way JavaScript does, which Python does not by default; verify.py does it in sixty lines of standard library, and our release checks run it against the server’s own hashes.
# https://paretoalphasystems.com/developers/verify.py (standard library only; read it, it is 60 lines)
from verify import content_sha256
r = requests.get("https://paretoalphasystems.com/api/v1/book", headers=H, params={"asOf": "2026-03-31"})
body = r.json()
assert content_sha256(body["data"]) == body["meta"]["contentSha256"] == r.headers["X-PA-Content-SHA256"]
# The same hash is written to the family's audit log with the read, so "what the API served me"
# can be matched to "what the log says was served" by someone who was not there.Which result did the committee rely on?
Run a question as often as you like: it is seeded, so the same question returns the same bytes, and exploring is never counted. When one result is the one a committee will rely on, a principal or COO seals it in the portal. The answer is computed again and compared with the hash you saw. Only then is a statement of the facts (the question, the answer’s hash, the engine digest, both dates, who and why) signed with Ed25519 and entered on a chain that is anchored nightly. The same question under the same engine is sealed once. The public keys are at /.well-known/fulcrum-keys.json, retired keys included, and verify_seal.py checks a seal with the standard library and no call to us. A seal is a record of an analysis. It instructs no one, is addressed to no custodian or broker, and executes nothing.
curl -s -H "Authorization: Bearer $TOKEN" https://paretoalphasystems.com/api/v1/seals/1 > seal.json curl -s https://paretoalphasystems.com/.well-known/fulcrum-keys.json > keys.json python3 verify_seal.py seal.json keys.json # every line true, exit 0 curl -s -H "Authorization: Bearer $TOKEN" https://paretoalphasystems.com/api/v1/usage # seals by month, the allowance, what is beyond it
How is each number computed?
Period returns
Modified Dietz between consecutive statement dates: R = (V₁ − V₀ − F) / (V₀ + Σ wᵢFᵢ), with wᵢ the share of the period remaining when flow i occurred. Each period is labelled exact (every external flow on a boundary, so it is a true time-weighted return), dietz (a flow inside the period, so it is an approximation) or undefined (the capital base was not positive; the return is withheld, not reported as zero). Periods are linked geometrically and annualised only when the record spans a year. External flows are cash leaving or entering the family; moves between the family’s own entities are not flows. Drawdown is taken on the linked return index, so spending is not counted as a loss.
Holdings-based exposures
Exact sums of position values by asset class, liquidity, currency, entity, manager, custodian and declared risk factor. Currency exposure is net of the hedged share: value × (1 − hedged%). Single-name concentration adds the same name across entities before weighting, reports the Herfindahl–Hirschman index H = Σ wᵢ² and effective names 1/H. When the family has loaded what its funds hold (the lookthrough table: position, issuer, percent of the fund), each fund’s value is handed to its holdings in proportion and merged with direct positions, so one company held directly, in a fund and in an ETF is one exposure, with via saying how. Whatever a fund does not disclose stays under the fund’s own name; lines that add up to more than the whole fund are refused, never rescaled. The response reports how much of the book was opened and the date of the oldest manager report used.
Stress scenarios
A scenario is a return for each asset class, a rate move, an inflation figure and a length. Each position moves by its class’s return; every loan is re-tested against its shocked collateral and a breach needs cash to cure; floating-rate debt reprices; spending continues through drawdown and recovery and is financed from liquid assets. survives is true when liquid assets after debt, cures and spending stay positive. The historical scenarios carry the series each class figure was read from, and a class with no series is labelled an analogy. There are no random numbers: the same shock on the same book gives the same answer, and ?shocks= runs your own.
Returns-based factor exposure
Family office statement dates are irregular, so ordinary least squares on raw period returns is inefficient and its standard errors are wrong. Each period is scaled by 1/√days: y/√d = α·√d + Σ βⱼ·xⱼ/√d + e, which is generalised least squares under a random-walk variance assumption and reduces to OLS with an intercept when periods are equal. α is a return per day, annualised ×365.25. Factor returns are level ratios over each period’s own dates, using the last level on or before each date and refusing one more than ten days stale. Long-only factors and the book are taken in excess of the risk-free return when one is named.
Reported for every coefficient: estimate, standard error, t, two-sided p and the 95% interval from Student’s t with n − k − 1 degrees of freedom, plus a variance inflation factor. Reported for the fit: R², adjusted R², annualised residual volatility, Durbin–Watson, and every period’s fitted value and residual. Standard errors are classical by default; se=hac gives Newey–West (Bartlett weights, rule-of-thumb lag ⌊4(n/100)^(2/9)⌋ unless you set hacLags, n/(n − k − 1) correction), and the response says which it used. With fewer than 12 usable periods, or fewer than 8 degrees of freedom, the answer is a refusal and the number needed, not a beta. Linearly dependent factors are refused, not given arbitrary coefficients.
Appraised and lagged marks smooth returns and bias a contemporaneous beta toward zero. lags=1 adds each factor’s previous-period return and reports the sum of the two coefficients (Dimson), with the standard error of the sum from the full covariance matrix. The exposures endpoint reports the share of the book carrying stale marks, so you know when to ask for it.
The estimator is checked on every release against an independent numpy and scipy implementation (coefficients, standard errors, p values, R², Durbin–Watson, VIF), against statsmodels for the Newey–West errors, against data constructed so the answer is known exactly, and against each refusal.
Where do the factor series come from?
From you, or from the public domain. Index and factor values are licensed, and we publish none we do not hold the right to publish. A family loads the series its custodian, consultant or data vendor already gives it, and they are shown only to that family. We supply the 3-month Treasury bill rate (Board of Governors, H.15) compounded to an index by a stated method, and the Consumer Price Index (Bureau of Labor Statistics) as published. Every series carries its licence and provenance in the response, and one whose terms do not permit showing it is listed without its values.
The limits, stated once.
- Not a market-data feed. There are no prices here that the family did not load or that are not public domain.
- Look-through is only as good as what managers disclose and as fresh as their last report. A fund with no rows loaded is one name.
- Stress scenarios move each asset class by one number. They do not model correlation between positions inside a class, or second-round effects beyond loans, floating rates and spending.
- No write access, by token or otherwise. Nothing in /api/v1 changes a family's record.
- A small family record is a small sample. The API will tell you how many observations it used, and refuse when there are too few.