Every snapshot includes a data.derived block. These are not new data —
they are transparent arithmetic on the exact on-chain values already in the response.
Each metric, its formula, and its edge cases are defined below so any caller can
reproduce every number. Agents can fetch the same definitions as JSON at
https://orcpin.dev/methodology.
Applies to: /v1/wallet-snapshot, /v1/defi-snapshot, /v1/batch-snapshot
Present in every snapshot under data.derived. Computed from account flags, the native balance, and the current gas price at the anchored block.
| Field | Formula | Notes |
|---|---|---|
wallet_typeWallet type |
is_contract ? "contract" : "eoa"enum: "eoa" | "contract" |
Based on whether the address has bytecode at the anchored block. |
activity_tierActivity tier |
0 → "new"; 1–9 → "low"; 10–99 → "active"; ≥100 → "power"enum: "new" | "low" | "active" | "power" |
Buckets on the outbound nonce only. A coarse activity heuristic — not an age, identity, or reputation score. |
gas_runway.gas_price_weiGas price (wei) |
eth_gasPrice at request timewei (string) |
The whole gas_runway object is null if the gas-price read fails. |
gas_runway.assumed_gas_unitsAssumed gas units |
constant 21000gas units |
Gas for a simple native ETH transfer. Contract calls cost more, so this is a best-case upper bound. |
gas_runway.est_tx_cost_weiEstimated tx cost (wei) |
gas_price_wei × 21000wei (string) |
Cost of one simple transfer at the current gas price. |
gas_runway.simple_transfers_affordableSimple transfers affordable |
floor(native_balance.wei ÷ est_tx_cost_wei)integer count |
How many simple transfers the ETH balance could pay for at the current gas price. Gas price varies block to block, so treat as an estimate. |
Applies to: /v1/defi-snapshot
Present under data.derived.aave only when the address has an Aave v3 position (aave_v3.available && aave_v3.has_position); otherwise data.derived.aave is null. USD figures use Aave's base currency (8 decimals). Below, C = total_collateral, D = total_debt, HF = health_factor.
| Field | Formula | Notes |
|---|---|---|
net_equityNet equity |
C − DUSD (8 decimals) |
Position value net of debt. |
unused_borrow_powerUnused borrow power |
available_borrows (pass-through)USD (8 decimals) |
The value Aave reports as still borrowable. |
ltv_utilization_pctLTV utilization |
D == 0 → 0; else (D ÷ C) ÷ (loan_to_value_bps ÷ 10000) × 100percent (1 dp) |
null when C = 0 or loan_to_value_bps = 0 — Percent of the maximum borrow allowed by LTV that is currently used. |
leverage_multiplierLeverage multiplier |
C ÷ (C − D)ratio (2 dp) |
null when equity (C − D) ≤ 0 — Equity multiplier of the position. |
health_factor_bandHealth factor band |
no debt → "no_debt"; HF ≥ 2 → "safe"; 1.5 ≤ HF < 2 → "moderate"; 1.1 ≤ HF < 1.5 → "elevated"; HF < 1.1 → "critical"enum: "no_debt" | "safe" | "moderate" | "elevated" | "critical" |
Fixed thresholds on Aave's reported health factor. A label, not a recommendation. |
collateral_drawdown_tolerance_pctCollateral drawdown tolerance |
(1 − 1 ÷ HF) × 100percent (1 dp) |
null when no outstanding debt — Percent the collateral value can fall before HF reaches 1 (Aave's liquidation point). Derived from Aave's own definition HF = (collateral × liquidation_threshold) ÷ debt: holding debt and the threshold constant, HF scales linearly with collateral value, so collateral can drop by (1 − 1/HF) before HF = 1. Assumes a uniform collateral price move with debt and threshold constant; it is a point-in-time estimate, not a prediction or advice. |
Applies to: /v1/endpoint-reliability, /v1/endpoint-reliability/batch
Unlike the snapshot metrics above, these facts are NOT computed from a single response — they aggregate Orcpin's own independent probe history for a target x402 endpoint over a rolling ~60-day window. Each probe is an unpaid request with no body (which returns the endpoint's 402 challenge at zero cost, before the endpoint does any work). We probe with GET first; if the endpoint answers with a status that indicates the wrong verb rather than a fault (404, 405, 501) we retry once with POST and record only that result — a large share of x402 endpoints are POST-only, and counting our own wrong verb against them would understate their reliability. A small, opt-in sample of probes additionally make a real PAID call to verify delivery. The subject is software delivery (did it respond, was the 402 well-formed, how fast) — NOT the financial quality or accuracy of any data the endpoint returns. Every value is a raw measured rate or count: there is no composite 'trust score' and no 'scam'/'safe' label. The caller applies its own thresholds. Below, P = total probes recorded.
Coverage. Two things populate the measurement history. A scheduled sweep continuously re-probes a worklist drawn from the public CDP Bazaar catalog and ordered by real demand (unique payers over the last 30 days), so the endpoints agents actually pay for hold the deepest samples. Anything else is probed on demand: ask about an endpoint we hold no measurement for — through either the single or the batch route — and it is probed live before the response is built, then kept for subsequent callers. A first-ever lookup therefore returns a one-sample measurement carrying the 'low_sample' flag, never a blank. We make no claim to have pre-measured the whole catalog, and 'unmeasured' means exactly what it says: no probe history and no live probe reached it.
| Field | Formula | Notes |
|---|---|---|
reachable_rateReachable rate |
probes that returned any HTTP response ÷ Pratio 0–1 (3 dp), null when P = 0 |
A probe is 'reachable' if it got an HTTP response at all (no timeout or transport error). Says nothing about the status code. |
http_success_rateHTTP success rate |
probes whose status was 2xx OR a well-formed 402 ÷ Pratio 0–1 (3 dp), null when P = 0 |
For an x402 endpoint a 402 is correct behaviour (it is demanding payment), so it counts as success. Measures whether the endpoint responded as expected — not whether returned data is correct. |
valid_402_rateValid 402 rate |
probes whose 402 body was a well-formed x402 challenge ÷ Pratio 0–1 (3 dp), null when P = 0 |
A 402 is 'valid' when its body parses as an x402 challenge (has an `accepts` array or an `x402Version`). Distinguishes a real paywalled endpoint from a generic 402. |
latency_ms.p50 / p95 / p99Latency percentiles |
percentiles over a fixed 7-bucket histogram with edges 100/250/500/1000/2500/5000 ms; the reported value is the upper edge of the bucket the percentile falls intomilliseconds (bucketed estimate), null when no timed probes |
Bucketed, so these are estimates, not exact percentiles — the response marks basis:'histogram'. Round-trip wall-clock time of the probe request. |
last_statusLast status |
HTTP status code of the most recent probeHTTP status integer, null when unknown |
402 is normal and healthy for a paid endpoint. |
consecutive_failuresConsecutive failures |
count of probes since the last success; reset to 0 on any successinteger count |
— |
delivery_verifiedDelivery verification |
verified = (paid probes that returned a parseable response > 0); samples = paid probes attemptedobject { verified, at, samples }, null when no paid probe has run |
Present only when sampled PAID verification has been run for the endpoint (off by default). It is the only fact whose measurement involved spending. Confirms the endpoint actually returns a response after payment; it does not judge the returned data. |
flagsFactual flags |
"unmeasured" when P = 0; "unprobeable_url" when the URL can't be safely probed; "low_sample" when 0 < P < 5; "unreachable" when 0 of ≥5 probes got any response; "consecutive_failures" when consecutive_failures ≥ 3; "last_probe_error" when last_status ≥ 500; "stale_measurement" when the last probe is older than 7 days; "delivery_failed" when every paid delivery attempt failedarray of enumerated string markers (may be empty) |
Enumerated factual markers, each with a fixed mechanical trigger above. Condition flags (unreachable / consecutive_failures / last_probe_error) are suppressed below 5 probes — a single transient bad sweep never flags an endpoint; "low_sample" is emitted instead and the raw rates still report what was seen. Never adjectives like 'scam' or 'unsafe', and never a recommendation — the caller decides what they mean for its use. |
Applies to: /v1/holding-period, /v1/settlement-dates, /v1/settlement-date, /v1/wash-sale-status
Unlike the chain metrics above, these are computed ONLY from the trade data the caller supplies in the request (a JSON body, or query params for the single-trade /v1/settlement-date GET) — nothing is fetched, and nothing is stored. Pure calendar arithmetic (UTC days) with the statutory threshold cited as a published fact; the response never states a verdict about the caller. All conventions below are deterministic: same inputs, same output, no server clock. Trading-day math (T+1 settlement) uses a versioned, published NYSE holiday table echoed as calendarVersion in each response; dates outside its range are a 400, never a guess.
| Field | Formula | Notes |
|---|---|---|
lots[].daysHeldDays held |
asOf − acquireDate, in whole UTC calendar daysinteger days |
The holding period begins the day AFTER acquisition (IRS Pub 550), so the acquisition day itself counts 0. |
lots[].longTermFromLong-term from |
acquireDate + 1 year + 1 day (UTC calendar)date (YYYY-MM-DD) |
First date on which a sale is long-term under IRC §1222 (held MORE than one year): a sale exactly on the one-year anniversary is short-term. Feb 29 acquisitions roll the anniversary to Mar 1 (the later, conservative boundary). |
lots[].character / sell.allocations[].characterGain character |
(evaluation date ≥ longTermFrom) ? "long_term" : "short_term"enum: "short_term" | "long_term" |
A definitional label from the cited threshold — not a recommendation about whether or when to sell. |
sell.allocations[]Sell allocation |
method "fifo": consume matching-symbol lots oldest acquireDate first; method "as_supplied": consume in the caller's array order (specific identification). The last lot consumed may be split.array of per-lot allocations |
Selling more shares than the supplied lots hold is a 400 error, never a partial answer. |
sell.allocations[].realizedGainRealized gain per allocation |
proceeds − allocated basis, where proceeds = quantity × sell.price and allocated basis = lot.costBasis × (quantity ÷ lot.quantity); both rounded to centsUSD (2 dp) |
null when the lot has no costBasis, or the sell has no price — Cost basis is used exactly as supplied — wash-sale basis adjustments, corporate actions, and splits are not applied. |
sell.totalsPer-character totals |
sum of allocation quantities and realizedGain per character (short_term / long_term)object per character |
null when realizedGain is null when ANY allocation in that character bucket lacks basis or price — a partial sum would misstate the total |
trades[].settlementDate (settlement-dates)Settlement date |
the next NYSE trading day strictly after tradeDate (T+1), per the versioned holiday tabledate (YYYY-MM-DD) |
SEC Rule 15c6-1 (as amended, effective 2024-05-28) is cited separately in rule_citation. Assumes standard US equity settlement; other instruments can differ. |
trades[].settledAsOfSettled as of |
asOf ≥ settlementDateboolean |
Settlement completes on the settlement date itself. A dates fact — never a violation determination. |
matches[].daysFromOrder (wash-sale-status)Days from order |
saleDate − order.tradeDate, signed UTC calendar days; a sale matches when |daysFromOrder| ≤ 30 and the ticker is identicalsigned integer days |
IRC §1091's 61-day window (±30 days, boundary-inclusive) is cited separately in rule_citation. v1 matches exact tickers only; substantially identical securities are out of scope and the disclaimer says so. Sales with zero/absent realizedLoss are ignored by construction. |
status (wash-sale-status)Wash-sale status |
matches.length > 0 ? "would_trigger" : coverage.complete === true ? "clear" : "insufficient_data"; sell orders return "not_applicable"enum |
coverage.complete = salesCoverageFrom ≤ order.tradeDate − 30 days; undeclared coverage is null and an empty sales list then reads insufficient_data, never a false clear. A tax STATUS with the rule cited — never advisability; a disallowed loss defers into replacement basis rather than being forfeited. |
Applies to: /v1/statement
The statement is structured like an auditor's letter. `verified` holds facts Orcpin read itself: every outgoing USDC transfer from the wallet in the window, from the public Base explorer, at the block shown. `representations` holds figures the requester's own meter reported, attested AS REPORTED by digest and never verified — Orcpin cannot see the requester's HTTP responses and does not pretend to. `reconciliation` is the arithmetic between the two. The whole document is canonicalised (keys sorted at every level, no whitespace), ed25519-signed, and its hash appended to a public transparency log; verification needs nothing from Orcpin but the published key.
| Field | Formula | Notes |
|---|---|---|
verified.settlementsSettlements |
count of outgoing USDC transfers from the wallet in the window with value > 0count |
— |
verified.usdSpent |
sum of those transfers' values ÷ 10^6USD (6 dp) |
— |
verified.zero_value_transfersZero-value transfers |
count of outgoing transfers with value = 0count |
Moved no money and are not settlements. Kept apart because a run of them to an address that looks like one you pay is the address-poisoning pattern. |
verified.by_counterparty[].flagsAddress flags |
lookalike_of:<addr> when the first and last four hex characters match a payee this wallet actually paid; zero_value_only when every transfer to it was zero-valuelist |
A pattern is named; no verdict is given about any party. |
verified.by_counterparty[].resources[].matches_settlement_amountsPrice match |
true when this wallet paid the payee an amount equal to the resource's catalog priceboolean |
A likely attribution, not a proof of which call was made. |
reconciliation.unaccounted_usdUnaccounted |
max(0, verified.usd − representations.delivered_usd)USD |
null when no representations were supplied |
signature.payload_sha256Payload hash |
sha256 of the canonical JSON of everything except signature, signed and transparencyhex |
The value logged in the transparency log; a hash that is not there under the signing key's kid is a forgery. |
Applies to: /v1/door-report
Four parts, in the order a buyer meets them. Quote: one unpaid request to the door records its status, latency and 402 challenge, and the same door is looked up on every surface that advertises it — the seller's own /.well-known/x402 manifest, the CDP Bazaar merchant listing for the payee, and Orcpin's weekly crawl — to see whether each names the same price and payee. Purchase: N real purchases with Orcpin's separately funded audit wallet, each recorded as quoted (the 402 the wallet saw), signed (the EIP-3009 authorization it sent), settled (the facilitator's payment-response), chain (that transaction's USDC Transfer read from the node), and delivered (a 2xx with valid JSON); then the first purchase's exact payment header is sent again, and a well-formed header that is not a payment is sent, and the door's answers are recorded. Books: every incoming USDC transfer to the payee over the last 30 days, from the public explorer, aggregated to counts and amounts — payer addresses are held in memory for the call and never returned. Cost: what a delivered response cost in this audit, and the share of USDC-priced doors in the public catalog priced below and above this one. Every figure is a raw count, amount, share or status; `attention` names patterns and the reader draws the conclusion. Nothing is charged for a URL that does not present a valid 402 on the audit's network.
| Field | Formula | Notes |
|---|---|---|
quote.price_consistentPrice consistency |
every surface that lists the door agrees with the 402's amount to the atomic unitboolean |
A surface that does not list the door neither agrees nor disagrees. |
purchase.records[].outcomePurchase outcome |
delivered = settled and 2xx with valid JSON; paid_not_delivered = settled without that; settlement_failed = the facilitator reported failure; delivered_without_payment = content came back with no retry; no_response = nothing usable came backenum |
— |
purchase.records[].chain.matches_signedReceipt confirmed |
the settlement transaction's USDC Transfer is from the audit wallet, to the quoted payee, for the signed amountboolean |
null when no receipt could be read |
purchase.replay.deliveredReplay delivered |
the first purchase's exact payment header, sent again, produced a 2xx with valid JSONboolean |
An EIP-3009 nonce is single-use on chain; a second delivery is one the seller was not paid for. |
books.repeat_payersRepeat payers |
distinct payers with settlements on two or more distinct UTC days in the windowcount |
— |
books.single_settlement_payers_at_this_priceOne-shot buyers at list price |
distinct payers with exactly one settlement in the window, equal to the door's quoted pricecount |
Consistent with verifiers and probes; stated as a count, not a classification of anyone. |
books.top_payer_shareTop payer share |
settlements by the single most frequent payer ÷ settlementsratio 0–1 |
null when no settlements |
cost.this_audit.usd_per_delivered_responseCost per delivered response |
USD settled in this audit ÷ purchases that were deliveredUSD |
null when nothing was delivered |
cost.catalog.share_priced_belowCatalog share below |
USDC-priced doors on this network in Orcpin's catalog crawl priced strictly below this door ÷ all such doorsratio 0–1 |
null when the crawl is empty |
Applies to: the Monthly Snapshot and any dollar total quoted from the x402 catalog
Figures for how much AI agents spend arrive in tiers that differ by about ten times each, and most coverage quotes the biggest one. The same 30 days, measured four ways, look like this. The scale is a standing reference: the top three bars come from one independent analysis and do not change month to month, and only the bottom bar is re-measured in each edition of the Monthly Snapshot, which states its current value and points here.
The same independent analysts give the longer arc: genuine spending peaked around $5.15M a month in November 2025, bottomed near $1.19M in May 2026, and roughly doubled off that floor in June. Meanwhile the x402 Foundation launched under the Linux Foundation with every major card network as a premier member, and the most-publicized agent checkout on the card side was withdrawn for lack of purchases. All of those are true at once: the money is small and does not move in a straight line, and the companies that own the payment pipes are standardizing the meter anyway. The gap between those two facts is the whole bet the industry is making.
Derived metrics are transparent arithmetic on the same on-chain values already in each response — not financial, legal, or investment advice, and not predictions. Read-only and factual. See /terms for acceptable use.