# apis.vin

The estate API. Every capability is addressed by VIN: decode and listings reads,
the buy pillar's deal lifecycle (open, desk, sign, insure, settle, deliver), the
F&I pillar's rating, menu, and contract verbs, and credit prequalification. One
worker serves them all behind typed envelopes — OK, EMPTY, BLOCKED, OFFER — and
never answers 406.

Sandbox doctrine: counterparty rails are deterministic sandbox ports behind real
wire shapes. Every simulated payload carries `"environment": "sandbox",
"simulated": true` — a simulated answer is never presented as a live one, and
the keyless /listings corpus is a fixed [sandbox]-labeled demo set, never a
fabricated market.

Modes, not promises: the key selects the mode. Every catalog row posts
`modes` — `sandbox` (a caller MODE, always answerable deterministically and
always labeled; never a status claim) and `live: platform | connection |
account | null` (which rail answers the live mode). platform rows answer real
platform bytes when keyed; connection rows are live via connection —
certified, connect to activate (a certified counterparty class awaiting your
credential; where the class's real adapter has not yet landed, an active
credential still answers sandbox with a typed adapter-pending disclosure —
capable and active are never conflated); account rows ride the account/money
posture; only `live: null`
rows have no rail anywhere, and only those may read as roadmap. Provenance
still tells the truth on every answer — a simulated payload always says so.

The record face: GET /{VIN} — 17 characters in the VIN alphabet reserve the
segment — answers the record composition with links into /buy/{VIN} and
/fi/inforce/{VIN}. Everything else at the root is a namespace.

Machine-face truth (founder ruling 2026-08-18): apis.vin is the machine
representation. GET / is the ONE HTML address — the landing, negotiated for
a browser. Every other address answers JSON always, whatever the Accept
header or User-Agent says. Markdown is served only where addressed — the
.md face extensions and /llms.txt — and a .html face address outside /
answers a typed JSON 404.

Every POST door publishes its requestBody JSON Schema in /openapi.json, and
a validation refusal aggregates: one BLOCKED answer lists EVERY missing or
invalid field with its expected type (reason + a structured problems array)
— never one field per round-trip.

Money on writes is ONE convention, estate-wide: every money field accepts the
decimal string the estate itself emits ("18750.00"), the response-side money
object ({"amount":"18750.00","currency":"USD"}), or a number of dollars — on
every write door (desk, /fi/quotes, all of them). Reads answer decimal
strings. The one deliberate exception: settle's amount_total is integer
CENTS, because that door mirrors the payments.do settlement-forward wire.

## Quickstart

One copy-pasteable curl per pillar, request bodies included (sandbox,
keyless unless noted):

Keys — mint an anonymous sandbox key (shown once):

    curl -X POST https://apis.vin/keys

Data — decode a corpus VIN:

    curl https://apis.vin/decode/JM3KFBXY1S0597748

Buy — open a deal:

    curl -X POST https://apis.vin/buy/deals \
      -H 'content-type: application/json' \
      -d '{"vin":"JM3KFBXY1S0597748","buyer":{"zip":"90210","name":"Ava Good"}}'

F&I — rate the VIN (vehicleMSRP present, so GAP rates too):

    curl -X POST https://apis.vin/fi/quotes \
      -H 'content-type: application/json' \
      -d '{"vin":"JM3KFBXY1S0597748","desked":{"salesPrice":"35887.00","downPayment":"3600.00","term":60,"zip":"90210","financeType":"Loan","amountFinanced":"32287.00","monthlyPayment":"654.00","vehicleMSRP":"43400.00"}}'

Credit — prequalify the approved-band identity (consent required, FCRA;
address is a FLAT string — city/state/zip are separate fields):

    curl -X POST https://apis.vin/credit/prequal \
      -H 'content-type: application/json' \
      -d '{"applicant":{"firstName":"Ava","lastName":"Good","address":"1 Sandbox Way","city":"Testville","state":"CA","zip":"94103"},"consent":{"consentedAt":"2026-08-08T00:00:00Z","evidence":"clickwrap cw_1"}}'

Financing — price a refinance against the existing lien (an OFFER with
quote@1 validThrough; POST the same body to
/financing/refinance/applications to open the application):

    curl -X POST https://apis.vin/financing/refinance/quotes \
      -H 'content-type: application/json' \
      -d '{"vin":"1HGCV1F37LA085988","currentBalance":"16900.00","currentApr":"11.99","remainingTermMonths":46}'

Dealer — read your inventory, capture a lead, read the deal-side book
(keyed: the presented key is the dealer identity):

    curl -X POST https://apis.vin/dealer/leads \
      -H 'authorization: Bearer vk_sandbox_…' \
      -H 'content-type: application/json' \
      -d '{"vin":"JM3KFBXY1S0597748","customer":{"name":"Lin Marta","zip":"90210"}}'

## The dealer surface

The dealer doors ride the meter like every pillar. The inventory read
answers keyless (keyless-first-value); the lead and book doors are
own-scope and require the key (Bearer vk_sandbox_… — the account is the
dealer identity on this single-tenant sandbox surface; mint one at
POST /keys).

GET /dealer/inventory is the dealer inventory read — the PLATFORM LISTINGS
projected for a dealer, never a separate feed: a gateway-keyed deployment
projects the data-plane gateway's own listings (dealerZip rides the
canonical zip grammar; make/model ride vehicle.*), otherwise the fixed
[sandbox] corpus projects as the sandbox rooftop, labeled simulated.
Filters: dealerId, dealerZip, make, model, page, limit — an unknown
parameter refuses a typed 400 naming it, and a non-matching projection
answers a truthful EMPTY. The door carries the posted dealer-inventory
unit price (0.01 USD).

POST /dealer/leads captures a lead ({ vin, customer: { name, zip? } })
dealer-scoped, state CAPTURED, and answers leadId; GET /dealer/leads reads
your captured leads back — own scope only, newest first.

GET /dealer/deals is the deal-side book: the estate's persisted deal streams
projected dealer-side — dealId, openedAt, dealType, vin, the ruling desked
figures (decimal-string money), the standing F&I selection — each row
linking into GET /dealer/deals/{dealId}, where state, available[] (the
workflow read model), and the F&I book answer from the same deal-core
walker the buy and fi pillars use. An unknown dealId answers an
existence-neutral EMPTY 404.

## Sandbox triggers

Deterministic, replayable, provenance-labeled: outcomes are driven by inputs,
never by chance — the same request always answers the same way, and every
simulated payload carries its provenance block.

Credit (POST /credit/prequal — the score is a deterministic hash of
firstName|lastName|zip, band 550–899):

- Ava Good, zip 94103 → scored 843 (approved band)
- Gwen Thin, zip 94103 → scored 586 (thin/low band, below 620)
- last name "Frozen" (any first name, any zip) → result "frozen"
- last name "Nohit" (any first name, any zip) → result "no-hit"
- missing or empty consent → 400 BLOCKED (consent required); a soft pull
  without consent never touches the bureau (FCRA)

The persona cast — one named identity per credit tier plus the edge cast,
deterministic across every rail (credit, financing, insurance, KYC, OFAC —
all clear except where the persona's story says otherwise). Ava Good and
Gwen Thin above anchor super-prime and the thin file; the rest of the cast:

- Paul Prime, zip 10443 → scored 760 (prime — approval, standard band)
- Nina Near, zip 10453 → scored 700 (near-prime — conditional approval, stips)
- Sam Sub, zip 10469 → scored 620 (subprime — pending → stips → conditional)
- Dee Deep, zip 10020 → scored 550 (deep-subprime — decline + adverse-action
  notice)
- Tara Tradeline, zip 10323 → scored 588 (thin file, recent tradelines —
  fraud-signal review branch, KYC step-up)
- Bill Bankrupt, zip 10237 → scored 566 (open Ch. 7 — decline;
  bankruptcy/SCRA handling paths)
- Rita Repo, zip 10072 → scored 605 (prior repossession — subprime band +
  repo-history stips)
- Cole Cosign, zip 10145 → scored 634 and Cora Cosign, zip 10145 → scored 796
  (the co-signer pair, one household zip — joint-application paths)
- Frank First, zip 10921 → scored 690 (first-time buyer — limited-history
  band)

Credit decisions: POST /credit/decisions/simulate is the sandbox
webhook-fire — decision approved | declined | conditioned lands the
channel-attested CreditApplication.decisioned@1 on the deal.

Refinance (POST /financing/refinance/quotes — refinance is origination
against an existing lien, so it lives under /financing/*): pricing is
hash-deterministic — the matched term is the posted band term nearest
remainingTermMonths (ties go shorter), each sandbox lender prices the posted
band rate plus a 0.00–1.99% spread hashed from vin+lender, and a lender row
exists ONLY when it improves on currentApr (never a worse offer):

- currentApr "11.99" (above the posted band) → an OFFER quote and per-lender
  offers[] rows, each with decimal-string money and quote@1 validThrough
- currentApr "3.99" (at or below the posted band floor) → the no-improvement
  trigger: the quote answers a truthful EMPTY and offers[] answers zero rows
- same lien, same answer, forever; every priced payload carries the
  refi-lender-panel-sandbox provenance block

F&I rating refusals (the rating validation law, POST /fi/quotes):

- a malformed VIN refuses invalid-vin (400 BLOCKED)
- GAP rating without desked.vehicleMSRP refuses at the boundary with code
  missing-msrp and the port law verbatim:
  "financing gap insurance but missing vehicleMSRP".
  GAP is in the requested set BY DEFAULT — an omitted productTypes rates
  every family. Exclude it (productTypes: ["VSC"];
  products is an accepted alias) and the quote proceeds without an MSRP.

F&I decoder dates (GET /fi/inforce/{vin}, POST /fi/renewals/recommend): a
captured contract is dated by its own deal — saleDate = the deal date, so a
contract captured today is in force today and assesses no-action. A VIN with
no captured contracts answers the deterministic sandbox exemplar (labeled
simulated), and the exemplar is the AGED-VIN trigger: its contracts start at
the vehicle's sandbox in-service date (model year + 1, June 15), so an old
model year — e.g. a VIN with position 10 'C' (2012) — deterministically shows
lapsed coverage and renew-now, while a recent model year shows contracts in
force. asOf time-travels a renewal assessment.

Extraction honesty (POST /fi/extract): extraction.fields carries ONLY values
genuinely parsed from the submitted content (basis
parsed-from-submitted-content, deterministic confidence). Contract terms the
document did not carry take deterministic sandbox defaults and are NAMED in
contract.defaultedFields; a document with nothing recognizable answers the
deterministic sample labeled basis canned-sample-extraction-input-not-parsed
with the confidence claim dropped.

Ceremony verbs (POST /buy/deals/{dealId}/esign | notarize | stips |
insurance): each concerns a completed human act, so each demands its explicit
artifact — esign and notarize take the signer identity ({"signer":{"name":
"…"}}), stips takes the stip references being completed ({"stips":["…"]}),
insurance takes the policy ({"policy":{"policyNumber":"…"}}). An anonymous
EMPTY POST refuses 400 BLOCKED with the aggregated field list. esign is the
SIGNING HANDOFF: it answers a typed OFFER carrying ceremonyUrl (and handoff
{kind: sign, url}) — the human signs at the ceremony page, and the sandbox
ceremony completes at POST …/esign/ceremony (registering Document.signed@1).
notarize / stips / insurance auto-complete in the sandbox and stamp sandbox
provenance (notary-sandbox / stips-sandbox / insurance-sandbox) —
deterministic triggers, no silent rubber stamps.

Record provenance (GET /decode/{vin} and every record-derived read): only the
platform data-plane gateway decode attests simulated: false. Records folded
from the buy.vin face post simulated: true — that face carries no
record-level provenance on the wire, so its data is never presented as live —
and the deterministic sample is always labeled source "sample record".
Sample-record fields are synthetic, not WMI-decoded (the provenance note says
so on the wire): the model year follows VIN position 10; demo-corpus VINs
carry a curated identity pinned to their real-world decode, other VINs'
make/model/trim are deterministic from the VIN text, not the WMI. The /{VIN}
record face keeps the valuation (retailValue) and the live asking price
apart — its listing block posts the SAME askingPrice /listings/{vin}
answers, and appears only when a listing stands.

The exemplar fleet — one fixture VIN per reachable FSM state (90
vehicles; every state of every catalog state machine has an exemplar,
enforced by test). Exemplar VINs are valid 17-char VINs with a readable
story prefix (0 stands in for O, 1 for I); each VIN answers coherently on
every VIN-shaped rail from the same one-world position. The kept magic VINs
stay: DEMO_VIN JM3KFBXY1S0597748 (the rail fall-back subject) and the
adverse trio 1FADVERSE00000000 / 1FRAUD00000000000 / 1FSALVAGE00000000. The fleet:

- 1FDEALFRESH000000 — The fresh quote: a saved search matched, a qualified lead, an offer extended, prequal running.
- 1FDEALCRED1T00000 — The credit-pending deal: application in underwriting, first stip requested, counter-offer on the table; the stips question parks as an issued handoff, unclaimed (vin-0bfz.15).
- 1FDEALDESKED00000 — The desked deal: conditional approval with stips verified, docs drafting, its listing marked pending, the campaign that sourced it completed.
- 1FDEALS1GNED00000 — The contracted deal: e-contract and documents signed, pre-approval promoted, escrow funded, payment initiated.
- 1FDEALFUNDED00000 — The funded deal: loan booked and funded, the last stip waived, down payment settled, docs executed.
- 1FDEALENR0UTE0000 — The in-fulfillment deal: carrier mid-route, title applied for, contracts in transit, escrow holding on inspection.
- 1FDEALDEL1VERED00 — The delivered deal: proof of delivery in, invoice paid, escrow released, receipt issued, title pending.
- 1FDEALCL0SED00000 — The closed deal: title transferred, notarized docs on file, loan boarded into servicing, payment reconciled.
- 1FDEALH0LD0000000 — The on-hold deal: a stip failed, the offer expired, escrow disputed, docs out for re-signature.
- 1FDEALCANCELED000 — The cancelled deal: offer withdrawn, invoice voided, payment and escrow refunded.
- 1FDEALUNW0UND0000 — The unwound deal: funded then reversed — payment charged back, the routed contract recalled.
- 1FDEALDECL1NED000 — The declined deal: credit declined, the offer declined, the pre-approval lapsed — the parked handoff handed back declined.
- 1FL0TS0URCE000000 — The sourcing target: a lease return the buyer’s sourcing search found, appraisal requested.
- 1FL0TB1D000000000 — The bid car: appraisal quoted, the buyer bidding to stock it.
- 1FL0TB0UGHT000000 — The acquired unit: appraisal accepted, title work ordered.
- 1FL0T1NB0UND00000 — The inbound allocation: a factory unit shipped, carrier dispatched to the lot.
- 1FL0TARR1VED00000 — The received unit: on the lot, intake inspection ordered.
- 1FL0TCHECKED00000 — The inspected unit: intake inspection passed, CPO evaluation underway.
- 1FL0TREC0ND000000 — The reconditioned unit: CPO certified, an early inquiry routed to the desk.
- 1FL0TFR0NTL1NE000 — The frontlined allocation: on the line, listing drafting, the first lead captured, its launch campaign still a draft.
- 1FL0TFL00RED00000 — The floored unit: floorplanned and posted, duplicate leads being merged, the launch campaign scheduled.
- 1FL0TL1STED000000 — The listed unit: live on the market with an active listing, an enriched lead, and its marketing campaign live.
- 1FCP0FA1LED000000 — The CPO reject: certification inspection failed; sells as-is.
- 1FLANESCHED000000 — The scheduled consignment: a recovered repo booked inbound, pre-sale inspection scheduled.
- 1FLANE0PEN0000000 — The open-lane unit: inspection in progress while the borrower’s redemption window runs.
- 1FLANERUNN1NG0000 — The unit on the block: bidding running now.
- 1FLANE1FB1D000000 — The if-bid: high bid short of reserve, seller deciding.
- 1FLANEN0SALE00000 — The no-sale: reserve unmet, headed to relist.
- 1FLANES0LD0000000 — The knockdown: hammer down, wholesale sale opened.
- 1FLANESETTLED0000 — The settled sale: buyer and seller sides settled on a split payment.
- 1FLANED1SBURSED00 — The disbursed repo sale: proceeds paid out, the deficiency billed to the borrower.
- 1FLANECL0SED00000 — The closed lane ticket: gate passed, delivery proven, the surplus returned to the borrower.
- 1FARBF1LED0000000 — The arbitration filing: damaged in transport, the sale returned, the claim filed.
- 1FARBREV1EW000000 — The arbitration under review: the invoiced sale contested on an undisclosed condition — the arbitrator has claimed the parked handoff.
- 1FARBRES0LVED0000 — The arbitration resolved for the buyer: the sale voided — the terminus answered its handoff on the staffed-terminus signal rail (vin-0bfz.16).
- 1FARBDEN1ED000000 — The arbitration denied: the sale stands confirmed.
- 1FKEEPREG1STERED0 — The freshly registered lease: decoded, registered, agent key active, connection pending, car-share quote out.
- 1FKEEPVER1F1ED000 — The verified owner: title in hand after redeeming the repo, connection live, first mandate minted.
- 1FKEEPM0N1T0R0000 — The monitored leased car: loan current, car-share booking deposit authorized, market search lapsed.
- 1FKEEPSVCDUE00000 — The interval car: insurance current, quietly monitored — only its 90-day service interval is running out (the one exemplar reachable ONLY by the maintenance clock edge; the insurance-lapse sweep is subject-scoped to the lapse exemplar, vin-vje.38).
- 1FKEEPRECALL00000 — The open-recall car: connection degraded, the mandate revoked, the lease terminating early.
- 1FKEEPMA1NT000000 — The maintenance-due car: registration renewed, a service mandate presented, a trade-in lead nurtured, its equity-mining campaign paused.
- 1FKEEP1NSERV1CE00 — The in-service car: shop mandate active, return inspection of its car-share stint completed.
- 1FKEEPLAPS1NG0000 — The lapsing registration: renewal due, the lease pull-ahead offer standing.
- 1FKEEPLAPSED00000 — The lapsed car: insurance and registration expired, key revoked, mandate expired, wear charges disputed — even its parked handoff ran out the 4h TTL unclaimed.
- 1FKEEPVALUED00000 — The just-valued car: fresh valuation after the old appraisal expired; rare trim, no market match.
- 1FKEEPD1SP0SED000 — The disposed car: sold on privately, lease closed out, mandate exhausted, agent key rotated.
- 1FSH0P0PENED00000 — The breakdown intake: towed in, RO opened, estimate built, first part ordered, warranty and VSC claims filed.
- 1FSH0PEST1MATED00 — The estimated job: claims adjudicating, estimate partially approved, parts on the shelf, tow dispatched.
- 1FSH0PPARTSWA1T00 — The parts-wait job: both claims approved, estimate approved, the critical part backordered.
- 1FSH0PWRENCH1NG00 — The job in the bay: teardown authorized under the VSC, warranty partially approved, parts picked.
- 1FSH0PM0B1LE00000 — The mobile job: tech dispatched with staged parts, the VSC covering part of the bill.
- 1FSH0PPERF0RMED00 — The performed job: work done, both claims denied, the owner declined the extra estimate.
- 1FSH0PRECHECK0000 — The job in QC: both claim denials under appeal while the work is re-checked.
- 1FSH0P1NV01CED000 — The invoiced job: both claims paid, the core charge returned.
- 1FSH0PSETTLED0000 — The settled job: RO closed, work order settled.
- 1FCRASHH00KED0000 — The fresh wreck: on the hook to the body shop, claim opened, total-loss review opened with it.
- 1FCRASHEST1MATED0 — The estimated wreck: delivered to the shop, supplement written, ACV determined on both tracks.
- 1FCRASHBLUEPR1NT0 — The blueprinted repair: ruled repairable, the claim approved.
- 1FCRASHT0RND0WN00 — The torn-down repair: structure opened for hidden damage.
- 1FCRASHREPA1RED00 — The repaired body: structural work done, the tow bill outstanding.
- 1FCRASHREBU1LT000 — The reassembled car: trim back on, the tow bill paid.
- 1FCRASHCAL1BRATED — The calibrated car: ADAS sensors re-aimed after reassembly.
- 1FCRASHRECHECK000 — The repair in QC: payout dispute under appeal while the shop re-checks the work.
- 1FCRASHD0NE000000 — The completed repair: delivered back, the claim settled.
- 1FCRASHSETTLED000 — The settled repair order: shop and insurer squared.
- 1FCLA1MDEN1ED0000 — The denied claim: coverage refused, the owner retrieving the car from the tow yard.
- 1FT0TALL0SS000000 — The confirmed total loss: impounded pending disposition.
- 1FSALVAGE00000000 — The kept salvage magic VIN: branded title, assigned to the salvage pool — auction-only disposition.
- 1FSALVAGES0LD0000 — The sold salvage unit: hammered at the salvage sale.
- 1FSUBR0GAT10N0000 — The subrogation file: recovery from the at-fault carrier reversed the claim.
- 1FSCRAP0FFERED000 — The end-of-life offer: a cash quote out while the unit is listed in the salvage pool.
- 1FSCRAPACCEPTED00 — The accepted end-of-life offer: pickup being arranged.
- 1FSCRAPT1TLE00000 — The released end-of-life title: paperwork done, awaiting pickup.
- 1FSCRAPP1CKED0000 — The picked-up end-of-life unit: on the truck to the dismantler.
- 1FSCRAPPED0000000 — The dismantled unit: parted out and retired from the road.
- 1FSCRAPC0D0000000 — The certificate of destruction: the end of the line, on record.
- 1FL0ANLATE0000000 — The delinquent loan: past due, the repo pipeline opened.
- 1FL0ANDEFERRED000 — The deferred loan: a payment moved to the back of the note cured the delinquency.
- 1FL0ANREC0VERY000 — The loan in recovery: a repossession agent assigned.
- 1FL0ANM0VED000000 — The transferred loan: servicing sold to another servicer.
- 1FL0ANPA1D0FF0000 — The paid-off loan: lien satisfied, note closed.
- 1FFACTALL0CATED00 — The fresh allocation: a build slot allocated to the store.
- 1FFACTC0NF1RMED00 — The confirmed order: the factory order locked to the allocation.
- 1FFACTBU1LT000000 — The produced unit: off the line, awaiting shipment.
- 1FFACTH0LD0000000 — The constraint hold: a part shortage holding the build.
- 1FFACTRESCHEDULED — The rescheduled build: pushed to a later production week.
- JM3KFBXY1S0597748 — The flagship demo VIN: the fall-back subject every rail request without a VIN lands on (migrated here from the 2003 Accord by the founder ruling 2026-08-17, vin-2sgm; the Accord stays a working corpus VIN — services/vehicle.ts DEMO_VINS).
- 1FADVERSE00000000 — The kept adverse magic VIN: the adverse-history trigger — a branded-title past on every history rail.
- 1FRAUD00000000000 — The kept fraud magic VIN: the fraud-flag trigger — its listing pulled when the flag raised.

## Platform binding — the canonical vehicle-data doors

apis.vin and api.auto.dev are sibling faces of ONE platform: api.auto.dev is
the platform's G3 vehicle data-plane gateway (served today under the
auto.dev zone), and apis.vin is the estate's G4 face of the same platform.
The canonical vehicle-data doors answer here as a drop-in SUPERSET of the
platform wire shapes: the canonical shape verbatim, estate members (type,
provenance) ADDED, never substituted.

The doors: GET /vin/{vin} (the flat decode; /decode/{vin} is the estate
alias), /listings and /listings/{vin} (canonical data[] + links, nested
vehicle/retailListing, numbers as numbers), /photos/{vin}, /specs/{vin},
/build/{vin}, /recalls/{vin}, /openrecalls/{vin}, /payments/{vin},
/apr/{vin}, /tco/{vin}, /taxes/{vin}, /plate/{state}/{number}, and /usage
(the alias of the caller's key ledger — the same meter GET /keys/me
reflects).

The compat guarantee: the canonical filter vocabulary is admitted in full on
/listings — dotted vehicle.*/retailListing.* filters, the range grammar
(retailListing.price=lo-hi), comma-separated value lists, includes=total —
alongside the estate dialect (make, model, year_min/max, price_min/max), and
the documented per-door args (payments price/zip/downPayment/loanTerm,
tco zip, taxes price/zip, apr year/make/model/zip/creditScore) are
vocabulary, never strangers; an UNKNOWN param still refuses a typed 400
naming it. Gateway-answered doors return the platform's own bytes
(provenance source "platform gateway", simulated false); a gateway boundary
answers a typed 503 (UNAVAILABLE / UNCONFIGURED) — bytes are never
fabricated. Face-served doors answer keyless from the deterministic
[sandbox] corpus in the same canonical shape, labeled simulated.

Checkout (POST /buy/deals/{dealId}/checkout): mints a 402 OFFER whose
checkoutUrl resolves on THIS origin to a sandbox-labeled checkout page (GET
the same address — open, superseded, settled, or expired, truthfully).
Repeated checkout answers the SAME open link; a re-desk supersedes it; the
OFFER carries an expiry and the settle instruction. No variable-amount rail
is configured in production — checkout there answers 503 (rail-unconfigured)
and mints no dead URL.

Settle (POST /buy/deals/{dealId}/settle, bearer-gated by the sandbox settle
token — the operator token, a worker secret): unset token → 503 UNCONFIGURED;
no bearer → 401 REFUSED (missing-bearer); a non-matching bearer → 401 REFUSED
(bearer-mismatch) — each refusal names where settle authority is configured; a
repriced amount → 409 (refused, never repriced); a repeated order_id replays
idempotently. A post-delivery settle with a fresh order_id lands SETTLED.

The acceptance suite is ONE digest-pinned document at /suite.json — declarative
api.qa/suite@1 rows AND an executable api.qa/vitest@1 tests member (the same
module runs under plain local vitest) — sha256 20183444abc2251eaa76773ad9e81f1c8ef439c4a7b6fc05719d58e58fab0c4c, declared on
the capability card as interfaces.testSuite. Run it locally:
npx autonomous-qa vitest apis-vin.suite.json --env sandbox
--expect-digest sha256:<that pin>.

Registration is fully self-service: POST /keys — no email, no approval, no
CAPTCHA — mints an anonymous account (agent_anon_…) and a sandbox key
(vk_sandbox_…) instantly. The key is returned once and stored only as a
sha256 hash; introspect it at GET /keys/me — the usage block there is the
REAL meter (spendToDate / callsToday / remainingCeiling move as calls
settle). Lifecycle: GET /keys enumerates, POST /keys/rotate mints a
successor and retires the old credential, DELETE /keys/me revokes. Metering
is enforced: the posted hard ceiling answers a typed 402 OFFER from
accumulation (reauthorize at the auth.vin device rail), and bursts answer a
typed 429 with retry_after. Every keyless surface stays keyless — the key
adds account context, and it never unlocks licensed or premium data tiers
(the money gate is mandates and settlement, not registration).

MCP: the ONE estate MCP server answers at POST /mcp — JSON-RPC 2.0 over
streamable HTTP, keyless. Three tools: search finds a capability across the
catalog (the same manifest every face is generated from); fetch dereferences
an address (GET-only, same-origin) and answers the typed envelope verbatim;
exec runs agent-written JavaScript against the bound estate SDK in a
sandboxed dynamic worker.
The transaction verbs stay HTTP POST doors, documented in /openapi.json.

The estate's doors: all.vin is the hub; buy.vin transacts the purchase; fi.vin
reads what is in force on a VIN; listings.vin lists. This API is the machine
face behind those doors.

## Machine surfaces

- Capability card (AXP probe manifest): https://apis.vin/.well-known/agents.json
- OpenAPI 3.1 contract: https://apis.vin/openapi.json
- Pricing Document: https://apis.vin/pricing
- icp.json (agent classes): https://apis.vin/icp.json
- Family registry (sibling doors as typed edges): https://apis.vin/family.json
- This file: https://apis.vin/llms.txt
- Conformance (independent verifier): https://api.qa/apis.vin

## The family

- buy.vin — the buy door — the record face and the purchase it opens: https://buy.vin/
- fi.vin — the F&I decoder lens — what is in force on a VIN: https://fi.vin/
- listings.vin — the listings door: https://listings.vin/
- data.vin — the data door — the decode read: https://data.vin/
- financing.vin — the lending flagship — refinance aliases here (origination against an existing lien): https://financing.vin/
