{
  "openapi": "3.1.0",
  "info": {
    "title": "apis.vin",
    "version": "0.1.0",
    "description": "The estate API: every VIN-addressed capability behind one worker — decode and listings reads, the buy pillar’s deal lifecycle, the F&I pillar’s rating, menu, and contract verbs, and credit prequalification. Typed envelopes (OK / EMPTY / BLOCKED / OFFER) on every door; sandbox counterparties answer behind real wire shapes and every simulated payload says so."
  },
  "servers": [
    {
      "url": "https://apis.vin"
    }
  ],
  "paths": {
    "/listings": {
      "get": {
        "operationId": "listCollection",
        "summary": "Vehicle listings — keyless answers the fixed [sandbox] demo corpus in the platform’s canonical wire shape (data[] + links, estate members added); with the platform service identity the same door answers the data-plane gateway’s live listings",
        "description": "The keyless, branching collection (AXP Clauses 4 + 7): plain GET answers 200 OK with substantive typed content to an anonymous caller; a non-matching filter answers 200 EMPTY; a reserved scope answers 403 BLOCKED. Collection member name: \"listing\".",
        "parameters": [
          {
            "name": "make",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "filter the collection by make; a non-matching value answers a typed 200 EMPTY, never a fake success"
          },
          {
            "name": "model",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "filter the collection by model; a non-matching value answers a typed 200 EMPTY, never a fake success"
          },
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "reserved scopes (admin, internal) answer a typed 403 BLOCKED"
          },
          {
            "name": "spend",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "requested spend in the same unit as hardCeiling (25); above the ceiling answers a typed 402 OFFER re-authorization boundary"
          }
        ],
        "responses": {
          "200": {
            "description": "OK or EMPTY envelope",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/OkEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/EmptyEnvelope"
                    }
                  ]
                }
              }
            }
          },
          "402": {
            "description": "OFFER envelope — the hard-ceiling re-authorization boundary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OfferEnvelope"
                }
              }
            }
          },
          "403": {
            "description": "BLOCKED envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/pricing": {
      "get": {
        "operationId": "getPricing",
        "summary": "The Pricing Document (AXP Appendix A.2)",
        "description": "This API is metered with a hard ceiling of 25 (USD); the caller can never be metered past it without explicit re-authorization. This price is NOT bound by published terms: it is a stated intent, and the document says so in its `binding` and `statement` members. Budget against it; do not contract on it.",
        "responses": {
          "200": {
            "description": "the Pricing Document",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PricingDocument"
                }
              }
            }
          }
        }
      }
    },
    "/family.json": {
      "get": {
        "operationId": "getFamilyRegistry",
        "summary": "The family registry — sibling properties and their seams as typed edges",
        "description": "Lists the sibling doors of this property's family so an agent at this door discovers the others as contracts, not links.",
        "responses": {
          "200": {
            "description": "the family registry",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/offer": {
      "get": {
        "operationId": "getOffer",
        "summary": "The offer boundary (AXP Appendix A.5)",
        "description": "Always answers 402 with a typed OFFER body — the machine-readable start of the paid conversation.",
        "responses": {
          "402": {
            "description": "OFFER envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OfferEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/decode/{vin}": {
      "get": {
        "summary": "Decode one VIN — typed OK envelope with the vehicle record and its posted provenance (auto.dev, buy.vin, or sample record)",
        "description": "Provenance law: only the platform data-plane gateway decode attests simulated: false. Records folded from the buy.vin face and the deterministic sample both post simulated: true — the buy.vin face carries no record-level provenance on the wire, so its records are never presented as live. Sample-record fields are synthetic, not WMI-decoded — the provenance note on every sample-backed read says so: 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 do not follow the WMI. Rate limit: every metered door (this one included) answers a burst with a typed 429 BLOCKED carrying retry_after seconds — per key for keyed calls, per caller otherwise.",
        "responses": {
          "200": {
            "description": "OK envelope — the decoded record with posted provenance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "400": {
            "description": "BLOCKED envelope — the segment is not a VIN (17 characters, no I/O/Q)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "BLOCKED envelope carrying retry_after — the sliding-window rate limit; wait and continue",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/listings/{vin}": {
      "get": {
        "summary": "The live listing for one VIN — OK with the listing, or a truthful EMPTY when the VIN is not listed; a listing miss never downgrades a decode",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/{vin}": {
      "get": {
        "summary": "The record face — a 17-character VIN answers its record composition: the decode, the valuation (retailValue) and the live asking price as separate blocks, and door links into /buy and /fi/inforce; JSON always (machine-face law), with .json/.md face extensions",
        "description": "The listing block appears only when a listing stands (presence-when-true), and its askingPrice is the SAME figure GET /listings/{vin} posts for the VIN — the record face and the listings door can never disagree about the ask. retailValue rides apart, under valuation.",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/vin/{vin}": {
      "get": {
        "summary": "Platform door — the canonical flat VIN decode (vinValid, squishVin, checksum, make/model/trim, vehicle{}); superset members: provenance added",
        "description": "The platform’s flat decode shape verbatim. With the platform service identity the gateway’s own bytes answer; keyless, the face computes the check-digit arithmetic (ISO 3779) and serves the ONE deterministic identity source, labeled in provenance. /decode/{vin} is the estate alias of this read.",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/photos/{vin}": {
      "get": {
        "summary": "Platform door — vehicle photos by VIN; superset members: type + provenance added; keyless answers a truthful EMPTY (photos are never fabricated)",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/specs/{vin}": {
      "get": {
        "summary": "Platform door — vehicle specifications by VIN, face-served from the deterministic identity source; superset members: type + provenance added",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/build/{vin}": {
      "get": {
        "summary": "Platform door (gateway-answered) — OEM build data by VIN; the platform bytes with type + provenance added, or a typed 503 boundary",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/recalls/{vin}": {
      "get": {
        "summary": "Platform door (gateway-answered) — safety recalls by VIN; the platform bytes with type + provenance added, or a typed 503 boundary",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/openrecalls/{vin}": {
      "get": {
        "summary": "Platform door (gateway-answered) — open/unresolved recalls by VIN; the platform bytes with type + provenance added, or a typed 503 boundary",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/payments/{vin}": {
      "get": {
        "summary": "Platform door (gateway-answered) — monthly payment calculation; documented args price/zip/downPayment/loanTerm/docFee/tradeIn are vocabulary, a stranger refuses typed 400",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/apr/{vin}": {
      "get": {
        "summary": "Platform door (gateway-answered) — interest rates by credit profile; documented args year/make/model/zip/creditScore/vehicleAge/vehicleMileage are vocabulary",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/tco/{vin}": {
      "get": {
        "summary": "Platform door (gateway-answered) — total cost of ownership; documented args zip/fromZip are vocabulary, a stranger refuses typed 400",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/taxes/{vin}": {
      "get": {
        "summary": "Platform door (gateway-answered) — taxes and fees; documented args price/zip/docFee/tradeIn/rate/downPayment/months are vocabulary",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/plate/{state}/{number}": {
      "get": {
        "summary": "Platform door (gateway-answered) — license plate to VIN (two-letter state + plate number); the platform bytes with type + provenance added",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/usage": {
      "get": {
        "summary": "Platform door — the caller’s usage meter (the alias of the key ledger GET /keys/me reflects); requires the sandbox key, answers the accumulated usage_daily figures",
        "responses": {
          "200": {
            "description": "OK envelope — the caller’s accumulated usage meter (the same ledger GET /keys/me reflects)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "BLOCKED envelope — keyless or unknown key (the meter is YOURS; mint a key anonymously at POST /keys)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/fi/quotes": {
      "post": {
        "summary": "Rate a VIN for F&I products — rates and service quotes",
        "description": "Sandbox triggers (deterministic rating validation law): a malformed VIN refuses invalid-vin (400 BLOCKED). vehicleMSRP is required only when GAP is in the requested product set — and it is by default (an omitted productTypes rates every family, GAP included): omitting desked.vehicleMSRP then refuses 400 BLOCKED with code missing-msrp and the port law verbatim, \"financing gap insurance but missing vehicleMSRP\". Exclude GAP — productTypes: [\"VSC\"] (products is an accepted alias; productTypes wins when both are sent) — and the quote proceeds without an MSRP. Rates bump 0–4% deterministically by VIN hash.",
        "requestBody": {
          "required": true,
          "description": "Rate a VIN for F&I products. desked is required for a NEW deal stream; a persisted deal re-quotes from its stream. vehicleMSRP is the GAP rating input: required whenever GAP is in the requested product set (it is by default) — exclude GAP via productTypes/products and the quote proceeds without it.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "vin"
                ],
                "properties": {
                  "vin": {
                    "type": "string",
                    "pattern": "^[A-HJ-NPR-Za-hj-npr-z0-9]{17}$",
                    "minLength": 1,
                    "description": "the VIN to rate"
                  },
                  "dealId": {
                    "type": "string",
                    "minLength": 1,
                    "description": "attach the quote to an existing deal stream (a deal_… id)"
                  },
                  "odometer": {
                    "type": "number",
                    "minimum": 0,
                    "description": "sale odometer (miles)"
                  },
                  "productTypes": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "AP",
                        "ETCH",
                        "EWT",
                        "GAP",
                        "KEY",
                        "LTW",
                        "PDR",
                        "RUST",
                        "TIRE",
                        "PPM",
                        "VSC"
                      ],
                      "minLength": 1,
                      "description": "F&I product family code"
                    },
                    "description": "restrict rating to these product families; omitted = every family (GAP included)"
                  },
                  "products": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "AP",
                        "ETCH",
                        "EWT",
                        "GAP",
                        "KEY",
                        "LTW",
                        "PDR",
                        "RUST",
                        "TIRE",
                        "PPM",
                        "VSC"
                      ],
                      "minLength": 1,
                      "description": "F&I product family code"
                    },
                    "description": "alias of productTypes (productTypes wins when both are sent)"
                  },
                  "desked": {
                    "type": "object",
                    "required": [
                      "salesPrice",
                      "zip",
                      "term",
                      "amountFinanced",
                      "monthlyPayment",
                      "financeType"
                    ],
                    "properties": {
                      "salesPrice": {
                        "anyOf": [
                          {
                            "type": "string",
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          {
                            "type": "number"
                          },
                          {
                            "type": "object",
                            "required": [
                              "amount"
                            ],
                            "properties": {
                              "amount": {
                                "type": [
                                  "string",
                                  "number"
                                ],
                                "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                              },
                              "currency": {
                                "type": "string",
                                "description": "USD (the estate settles US dollars only)"
                              }
                            }
                          }
                        ],
                        "description": "vehicle sales price — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                      },
                      "downPayment": {
                        "anyOf": [
                          {
                            "type": "string",
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          {
                            "type": "number"
                          },
                          {
                            "type": "object",
                            "required": [
                              "amount"
                            ],
                            "properties": {
                              "amount": {
                                "type": [
                                  "string",
                                  "number"
                                ],
                                "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                              },
                              "currency": {
                                "type": "string",
                                "description": "USD (the estate settles US dollars only)"
                              }
                            }
                          }
                        ],
                        "description": "down payment (defaults 0.00) — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                      },
                      "tradeIn": {
                        "anyOf": [
                          {
                            "type": "string",
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          {
                            "type": "number"
                          },
                          {
                            "type": "object",
                            "required": [
                              "amount"
                            ],
                            "properties": {
                              "amount": {
                                "type": [
                                  "string",
                                  "number"
                                ],
                                "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                              },
                              "currency": {
                                "type": "string",
                                "description": "USD (the estate settles US dollars only)"
                              }
                            }
                          }
                        ],
                        "description": "trade-in value (defaults 0.00) — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                      },
                      "docFee": {
                        "anyOf": [
                          {
                            "type": "string",
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          {
                            "type": "number"
                          },
                          {
                            "type": "object",
                            "required": [
                              "amount"
                            ],
                            "properties": {
                              "amount": {
                                "type": [
                                  "string",
                                  "number"
                                ],
                                "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                              },
                              "currency": {
                                "type": "string",
                                "description": "USD (the estate settles US dollars only)"
                              }
                            }
                          }
                        ],
                        "description": "doc fee (defaults 0.00) — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                      },
                      "zip": {
                        "type": "string",
                        "minLength": 1,
                        "description": "the desking ZIP"
                      },
                      "term": {
                        "type": "integer",
                        "minimum": 1,
                        "description": "finance term in months"
                      },
                      "interestRate": {
                        "type": "number",
                        "description": "APR (defaults 0)"
                      },
                      "amountFinanced": {
                        "anyOf": [
                          {
                            "type": "string",
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          {
                            "type": "number"
                          },
                          {
                            "type": "object",
                            "required": [
                              "amount"
                            ],
                            "properties": {
                              "amount": {
                                "type": [
                                  "string",
                                  "number"
                                ],
                                "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                              },
                              "currency": {
                                "type": "string",
                                "description": "USD (the estate settles US dollars only)"
                              }
                            }
                          }
                        ],
                        "description": "amount financed — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                      },
                      "monthlyPayment": {
                        "anyOf": [
                          {
                            "type": "string",
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          {
                            "type": "number"
                          },
                          {
                            "type": "object",
                            "required": [
                              "amount"
                            ],
                            "properties": {
                              "amount": {
                                "type": [
                                  "string",
                                  "number"
                                ],
                                "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                              },
                              "currency": {
                                "type": "string",
                                "description": "USD (the estate settles US dollars only)"
                              }
                            }
                          }
                        ],
                        "description": "monthly payment — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                      },
                      "totalTaxesAndFees": {
                        "anyOf": [
                          {
                            "type": "string",
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          {
                            "type": "number"
                          },
                          {
                            "type": "object",
                            "required": [
                              "amount"
                            ],
                            "properties": {
                              "amount": {
                                "type": [
                                  "string",
                                  "number"
                                ],
                                "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                              },
                              "currency": {
                                "type": "string",
                                "description": "USD (the estate settles US dollars only)"
                              }
                            }
                          }
                        ],
                        "description": "taxes and fees (defaults 0.00) — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                      },
                      "vehicleMSRP": {
                        "anyOf": [
                          {
                            "type": "string",
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          {
                            "type": "number"
                          },
                          {
                            "type": "object",
                            "required": [
                              "amount"
                            ],
                            "properties": {
                              "amount": {
                                "type": [
                                  "string",
                                  "number"
                                ],
                                "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                              },
                              "currency": {
                                "type": "string",
                                "description": "USD (the estate settles US dollars only)"
                              }
                            }
                          }
                        ],
                        "description": "the GAP rating input (port law missing-msrp) — required when GAP is in the requested product set; a quote whose productTypes/products excludes GAP may omit it — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                      },
                      "financeType": {
                        "type": "string",
                        "enum": [
                          "Loan",
                          "Balloon",
                          "Lease",
                          "Cash"
                        ],
                        "minLength": 1,
                        "description": "finance type"
                      },
                      "dealerState": {
                        "type": "string",
                        "pattern": "^[A-Za-z]{2}$",
                        "minLength": 1,
                        "description": "two-letter dealer state"
                      }
                    },
                    "description": "the desked terms (required for a new quote — no persisted deal stream to reuse)"
                  }
                },
                "description": "Rate a VIN for F&I products. desked is required for a NEW deal stream; a persisted deal re-quotes from its stream. vehicleMSRP is the GAP rating input: required whenever GAP is in the requested product set (it is by default) — exclude GAP via productTypes/products and the quote proceeds without it."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/fi/deals/{dealId}/menu": {
      "post": {
        "summary": "Package rated quotes into the Good/Better/Best menu",
        "requestBody": {
          "required": false,
          "description": "No body arguments — send an empty body (or none at all).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "description": "No body arguments — send an empty body (or none at all)."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/fi/deals/{dealId}/menu/present": {
      "post": {
        "summary": "Present the packaged menu",
        "requestBody": {
          "required": false,
          "description": "No body arguments — send an empty body (or none at all).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "description": "No body arguments — send an empty body (or none at all)."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/fi/deals/{dealId}/menu/select": {
      "post": {
        "summary": "Select a package — disclosures must be acknowledged",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "package"
                ],
                "properties": {
                  "package": {
                    "type": "string",
                    "enum": [
                      "Good",
                      "Better",
                      "Best"
                    ],
                    "minLength": 1,
                    "description": "the menu package to select"
                  },
                  "disclosuresAcknowledged": {
                    "type": "boolean",
                    "description": "must be true — the unit refuses an unacknowledged selection"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/fi/deals/{dealId}/menu/decline": {
      "post": {
        "summary": "Decline the menu",
        "requestBody": {
          "required": false,
          "description": "No body arguments — send an empty body (or none at all).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "description": "No body arguments — send an empty body (or none at all)."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/fi/deals/{dealId}": {
      "get": {
        "summary": "The F&I state of a deal — lifecycle state, menu, rates",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/fi/deals/{dealId}/contract/stage": {
      "post": {
        "summary": "Stage the contract for the selected package",
        "requestBody": {
          "required": false,
          "description": "No body arguments — send an empty body (or none at all).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "description": "No body arguments — send an empty body (or none at all)."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/fi/deals/{dealId}/contract/approve": {
      "post": {
        "summary": "Approve the staged contract (sandbox auto-approval protocol; approver is a named human)",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "approver": {
                    "type": "string",
                    "minLength": 1,
                    "description": "approving actor id (defaults to the deal’s sandbox F&I manager)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/fi/deals/{dealId}/contract/capture": {
      "post": {
        "summary": "Capture the approved contract — requires a licensed F&I manager",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "fiManager"
                ],
                "properties": {
                  "fiManager": {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "description": "manager name"
                      },
                      "licenseNumber": {
                        "type": "string",
                        "description": "license number — the unit refuses an unlicensed capture (its wording is authoritative)"
                      }
                    },
                    "description": "the licensed F&I manager capturing the contract"
                  },
                  "approver": {
                    "type": "string",
                    "minLength": 1,
                    "description": "approving actor id (defaults to the deal’s sandbox F&I manager)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/fi/contracts/{contractId}/void": {
      "post": {
        "summary": "Void a captured contract",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "dealId": {
                    "type": "string",
                    "minLength": 1,
                    "description": "the deal holding the contract (looked up from the stream when omitted) (a deal_… id)"
                  },
                  "reason": {
                    "type": "string",
                    "minLength": 1,
                    "description": "void reason"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/fi/inforce/{vin}": {
      "get": {
        "summary": "In-force contracts on a VIN with state cancellation rules and posted provenance",
        "description": "Contract dates: a captured contract is dated by its own deal (saleDate = the deal date), so a contract captured today is in force today. A VIN with no captured contracts answers the deterministic sandbox exemplar (labeled simulated) — the aged-VIN trigger: exemplar contracts start at the vehicle’s sandbox in-service date (model year + 1, June 15), so an old model year deterministically shows lapsed coverage; a recent one shows contracts in force.",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/fi/extract": {
      "post": {
        "summary": "Extract structured terms from a contract document — genuinely parsed from the submitted content",
        "description": "The extraction PARSES the submitted content: extraction.fields carries only values recovered from the document (basis parsed-from-submitted-content, with a 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 no confidence claim.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "kind",
                  "content"
                ],
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "drivers-license",
                      "signed-contract",
                      "payoff-letter",
                      "insurance-card",
                      "generic"
                    ],
                    "minLength": 1,
                    "description": "document kind"
                  },
                  "content": {
                    "type": "string",
                    "minLength": 1,
                    "description": "the document content to extract from"
                  },
                  "documentRef": {
                    "type": "string",
                    "minLength": 1,
                    "description": "reference for the document (defaults inline:content)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/fi/cancellations/quote": {
      "post": {
        "summary": "Pro-rata cancellation refund quote from contract terms and odometer or date",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "contract"
                ],
                "properties": {
                  "contract": {
                    "type": "object",
                    "required": [
                      "price",
                      "termMonths",
                      "startDate"
                    ],
                    "properties": {
                      "price": {
                        "anyOf": [
                          {
                            "type": "string",
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          {
                            "type": "number"
                          },
                          {
                            "type": "object",
                            "required": [
                              "amount"
                            ],
                            "properties": {
                              "amount": {
                                "type": [
                                  "string",
                                  "number"
                                ],
                                "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                              },
                              "currency": {
                                "type": "string",
                                "description": "USD (the estate settles US dollars only)"
                              }
                            }
                          }
                        ],
                        "description": "contract price — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                      },
                      "termMonths": {
                        "type": "integer",
                        "minimum": 1,
                        "description": "contract term in months"
                      },
                      "startDate": {
                        "type": "string",
                        "minLength": 1,
                        "description": "ISO date (YYYY-MM-DD)"
                      },
                      "state": {
                        "type": "string",
                        "minLength": 1,
                        "description": "contract state (drives the posted state rule)"
                      },
                      "termMiles": {
                        "type": "number",
                        "exclusiveMinimum": 0,
                        "description": "mileage term, when the product carries one"
                      }
                    },
                    "description": "the contract terms to quote cancellation on"
                  },
                  "asOf": {
                    "type": "string",
                    "minLength": 1,
                    "description": "quote as of this ISO date (defaults today)"
                  },
                  "odometer": {
                    "type": "number",
                    "minimum": 0,
                    "description": "current odometer — arms the miles basis"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/fi/renewals/recommend": {
      "post": {
        "summary": "Renewal recommendation from utilization and expiration",
        "description": "Assesses the given contracts (or whatever is in force for the VIN). Sandbox scenarios are VIN-driven: a freshly captured contract (saleDate = the deal date) assesses no-action; the aged-VIN exemplar (contracts dated from the vehicle’s model year) drives renew-soon / renew-now deterministically. asOf time-travels the assessment.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "vin"
                ],
                "properties": {
                  "vin": {
                    "type": "string",
                    "pattern": "^[A-HJ-NPR-Za-hj-npr-z0-9]{17}$",
                    "minLength": 1,
                    "description": "the VIN to assess"
                  },
                  "asOf": {
                    "type": "string",
                    "minLength": 1,
                    "description": "assess as of this ISO date (defaults today)"
                  },
                  "contracts": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "termMonths",
                        "startDate"
                      ],
                      "properties": {
                        "termMonths": {
                          "type": "integer",
                          "minimum": 1,
                          "description": "contract term in months"
                        },
                        "startDate": {
                          "type": "string",
                          "minLength": 1,
                          "description": "ISO date (YYYY-MM-DD)"
                        },
                        "productType": {
                          "type": "string",
                          "minLength": 1,
                          "description": "product family (VSC, GAP, …)"
                        },
                        "termMiles": {
                          "type": "number",
                          "exclusiveMinimum": 0,
                          "description": "mileage term, when the product carries one"
                        },
                        "endDate": {
                          "type": "string",
                          "minLength": 1,
                          "description": "ISO date — derived from startDate + termMonths when omitted"
                        }
                      },
                      "description": "a contract to assess"
                    },
                    "description": "contracts to assess (else `extracted`, else whatever is in force for the VIN)"
                  },
                  "extracted": {
                    "type": "object",
                    "required": [
                      "termMonths",
                      "startDate"
                    ],
                    "properties": {
                      "termMonths": {
                        "type": "integer",
                        "minimum": 1,
                        "description": "contract term in months"
                      },
                      "startDate": {
                        "type": "string",
                        "minLength": 1,
                        "description": "ISO date (YYYY-MM-DD)"
                      },
                      "productType": {
                        "type": "string",
                        "minLength": 1,
                        "description": "product family (VSC, GAP, …)"
                      },
                      "termMiles": {
                        "type": "number",
                        "exclusiveMinimum": 0,
                        "description": "mileage term, when the product carries one"
                      },
                      "endDate": {
                        "type": "string",
                        "minLength": 1,
                        "description": "ISO date — derived from startDate + termMonths when omitted"
                      }
                    },
                    "description": "one extracted contract (the /fi/extract shape) to assess"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/fi/gl/reconcile": {
      "post": {
        "summary": "Reconcile a DMS GL export against decoded F&I contracts — matches, an unmatched queue, and the per-customer/VIN renewal-candidate list",
        "description": "The GL bridge: lines are scored against the decoded contract instances for the VINs the export references (captured contracts first, else the sandbox exemplar — the /fi/inforce sourcing) via VIN + customer + amount + date heuristics. The signal weights and the 0.6 match floor are POSTED on every answer (matchLaw); lines under the floor land in the unmatched queue with worded reasons and the near-miss candidate. Matched contracts fold into renewal candidates through the SAME rules /fi/renewals/recommend runs. An empty body reconciles the synthetic dealer fixture, labeled source: sandbox-fixture; asOf time-travels the assessment.",
        "requestBody": {
          "required": false,
          "description": "Reconcile a DMS GL export against decoded F&I contract instances (VIN + customer + amount + date heuristics, posted signal weights, posted match floor) — matches with confidence scores, an unmatched queue, and the per-customer/VIN renewal-candidate list. Send content (CSV with a header row, or a JSON array of line objects) or lines; an empty body reconciles the synthetic dealer fixture, labeled source: sandbox-fixture.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "content": {
                    "type": "string",
                    "minLength": 1,
                    "description": "the GL export document — CSV with a DMS-style header row, or a JSON array of GL line objects"
                  },
                  "lines": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "account": {
                          "type": "string",
                          "minLength": 1,
                          "description": "GL account number"
                        },
                        "accountName": {
                          "type": "string",
                          "minLength": 1,
                          "description": "GL account name"
                        },
                        "postDate": {
                          "type": "string",
                          "minLength": 1,
                          "description": "posting date — ISO (YYYY-MM-DD) or US (MM/DD/YYYY)"
                        },
                        "amount": {
                          "anyOf": [
                            {
                              "type": "string",
                              "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                            },
                            {
                              "type": "number"
                            },
                            {
                              "type": "object",
                              "required": [
                                "amount"
                              ],
                              "properties": {
                                "amount": {
                                  "type": [
                                    "string",
                                    "number"
                                  ],
                                  "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                                },
                                "currency": {
                                  "type": "string",
                                  "description": "USD (the estate settles US dollars only)"
                                }
                              }
                            }
                          ],
                          "description": "the posted amount (credits may arrive negative or parenthesized in CSV) — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                        },
                        "description": {
                          "type": "string",
                          "minLength": 1,
                          "description": "line description / memo"
                        },
                        "customer": {
                          "type": "string",
                          "minLength": 1,
                          "description": "customer name on the line"
                        },
                        "vin": {
                          "type": "string",
                          "minLength": 1,
                          "description": "the VIN on the line (also recognized inside reference/description)"
                        },
                        "reference": {
                          "type": "string",
                          "minLength": 1,
                          "description": "control / reference / document number"
                        },
                        "journal": {
                          "type": "string",
                          "minLength": 1,
                          "description": "journal code"
                        }
                      },
                      "description": "one GL line (DMS column spellings accepted: acct, post date, amount or debit/credit, description, customer name, VIN, control no, journal)"
                    },
                    "description": "GL lines already parsed into objects (wins over content when both are sent)"
                  },
                  "asOf": {
                    "type": "string",
                    "minLength": 1,
                    "description": "assess renewal candidates as of this ISO date (defaults today)"
                  }
                },
                "description": "Reconcile a DMS GL export against decoded F&I contract instances (VIN + customer + amount + date heuristics, posted signal weights, posted match floor) — matches with confidence scores, an unmatched queue, and the per-customer/VIN renewal-candidate list. Send content (CSV with a header row, or a JSON array of line objects) or lines; an empty body reconciles the synthetic dealer fixture, labeled source: sandbox-fixture."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/{vin}": {
      "get": {
        "summary": "The buy composition — decode, payments, transport quote, VSC menu preview, checklist template",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals": {
      "post": {
        "summary": "Open a deal on a VIN",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "vin",
                  "buyer"
                ],
                "properties": {
                  "vin": {
                    "type": "string",
                    "pattern": "^[A-HJ-NPR-Za-hj-npr-z0-9]{17}$",
                    "minLength": 1,
                    "description": "the VIN to open a deal on"
                  },
                  "buyer": {
                    "type": "object",
                    "required": [
                      "zip"
                    ],
                    "properties": {
                      "zip": {
                        "type": "string",
                        "pattern": "^\\d{5}$",
                        "minLength": 1,
                        "description": "buyer ZIP"
                      },
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "description": "buyer name"
                      }
                    },
                    "description": "the buyer"
                  },
                  "dealType": {
                    "type": "string",
                    "enum": [
                      "Concierge Buy",
                      "Concierge Search",
                      "Private Party"
                    ],
                    "minLength": 1,
                    "description": "deal type (defaults Concierge Buy)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals/{dealId}": {
      "get": {
        "summary": "Read a deal — state, parties, numbers, and available[] (the workflow read model: the transitions legal for this deal’s type+state, guards evaluated)",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals/{dealId}/checklist": {
      "get": {
        "summary": "The 8-step buy checklist, projected from the deal’s own event stream",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals/{dealId}/events": {
      "get": {
        "summary": "The deal’s own event stream (own-scope read) — one address, two faces: Accept: application/json answers the pull page; Accept: text/event-stream streams the same events as SSE (id: = event seq, Last-Event-ID resumes after it)",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals/{dealId}/desk": {
      "post": {
        "summary": "Desk the numbers — cascades F&I rating on the desked figures",
        "requestBody": {
          "required": true,
          "description": "Desk the numbers (the desk computes taxes, fees, and the payment). Money fields take the ONE estate write convention: the decimal string the estate emits (\"30000.00\"), the money object {\"amount\":\"30000.00\",\"currency\":\"USD\"}, or a number of dollars.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "salesPrice",
                  "downPayment",
                  "term",
                  "zip"
                ],
                "properties": {
                  "salesPrice": {
                    "anyOf": [
                      {
                        "type": "string",
                        "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                      },
                      {
                        "type": "number"
                      },
                      {
                        "type": "object",
                        "required": [
                          "amount"
                        ],
                        "properties": {
                          "amount": {
                            "type": [
                              "string",
                              "number"
                            ],
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          "currency": {
                            "type": "string",
                            "description": "USD (the estate settles US dollars only)"
                          }
                        }
                      }
                    ],
                    "exclusiveMinimum": 0,
                    "description": "sales price — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                  },
                  "downPayment": {
                    "anyOf": [
                      {
                        "type": "string",
                        "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                      },
                      {
                        "type": "number"
                      },
                      {
                        "type": "object",
                        "required": [
                          "amount"
                        ],
                        "properties": {
                          "amount": {
                            "type": [
                              "string",
                              "number"
                            ],
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          "currency": {
                            "type": "string",
                            "description": "USD (the estate settles US dollars only)"
                          }
                        }
                      }
                    ],
                    "minimum": 0,
                    "description": "down payment — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                  },
                  "term": {
                    "type": "integer",
                    "minimum": 12,
                    "maximum": 96,
                    "description": "term in months (12–96)"
                  },
                  "zip": {
                    "type": "string",
                    "pattern": "^\\d{5}$",
                    "minLength": 1,
                    "description": "the desking ZIP"
                  },
                  "financeType": {
                    "type": "string",
                    "enum": [
                      "Loan",
                      "Balloon",
                      "Lease",
                      "Cash"
                    ],
                    "minLength": 1,
                    "description": "finance type (defaults Loan)"
                  },
                  "interestRate": {
                    "type": "number",
                    "description": "APR — omitted posts the sandbox APR band rate"
                  },
                  "tradeIn": {
                    "anyOf": [
                      {
                        "type": "string",
                        "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                      },
                      {
                        "type": "number"
                      },
                      {
                        "type": "object",
                        "required": [
                          "amount"
                        ],
                        "properties": {
                          "amount": {
                            "type": [
                              "string",
                              "number"
                            ],
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          "currency": {
                            "type": "string",
                            "description": "USD (the estate settles US dollars only)"
                          }
                        }
                      }
                    ],
                    "minimum": 0,
                    "description": "trade-in value (defaults 0.00) — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                  },
                  "vehicleMSRP": {
                    "anyOf": [
                      {
                        "type": "string",
                        "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                      },
                      {
                        "type": "number"
                      },
                      {
                        "type": "object",
                        "required": [
                          "amount"
                        ],
                        "properties": {
                          "amount": {
                            "type": [
                              "string",
                              "number"
                            ],
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          "currency": {
                            "type": "string",
                            "description": "USD (the estate settles US dollars only)"
                          }
                        }
                      }
                    ],
                    "exclusiveMinimum": 0,
                    "description": "vehicle MSRP — defaults to 115% of salesPrice (the GAP rating input) — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                  }
                },
                "description": "Desk the numbers (the desk computes taxes, fees, and the payment). Money fields take the ONE estate write convention: the decimal string the estate emits (\"30000.00\"), the money object {\"amount\":\"30000.00\",\"currency\":\"USD\"}, or a number of dollars."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals/{dealId}/esign": {
      "post": {
        "summary": "The signing handoff — a typed OFFER carrying ceremonyUrl (and handoff {kind: sign, url}) for the human to sign at; requires the signer identity, never a silent done:true",
        "description": "The signature is a human act: this door validates the ceremony artifact (the named signer — an anonymous POST refuses 400 with the aggregated field list) and answers an OFFER-class envelope with the ceremony URL instead of asserting the act completed. The sandbox ceremony completes at POST /buy/deals/{dealId}/esign/ceremony with the same signer, which registers Document.signed@1 and flips the checklist step. A deal already signed answers replay.",
        "requestBody": {
          "required": true,
          "description": "Record the signed buyers agreement. The signer identity is the ceremony artifact — an anonymous POST refuses; the sandbox auto-signs for the named signer and stamps sandbox e-sign provenance.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "signer"
                ],
                "properties": {
                  "signer": {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "description": "signer legal name"
                      },
                      "email": {
                        "type": "string",
                        "minLength": 1,
                        "description": "signer email (optional)"
                      }
                    },
                    "description": "who signed (the ceremony artifact)"
                  }
                },
                "description": "Record the signed buyers agreement. The signer identity is the ceremony artifact — an anonymous POST refuses; the sandbox auto-signs for the named signer and stamps sandbox e-sign provenance."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals/{dealId}/esign/ceremony": {
      "get": {
        "summary": "The signing ceremony page the esign OFFER hands off to — truthful standing (open | signed), declaring the sign action",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      },
      "post": {
        "summary": "Complete the signing ceremony (sandbox: the named signer’s act registers Document.signed@1) — idempotent replay",
        "requestBody": {
          "required": true,
          "description": "Complete the signing ceremony (the human act the esign OFFER hands off to). The signer identity is the ceremony artifact — an anonymous POST refuses; the sandbox completion registers Document.signed@1 for the named signer.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "signer"
                ],
                "properties": {
                  "signer": {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "description": "signer legal name"
                      },
                      "email": {
                        "type": "string",
                        "minLength": 1,
                        "description": "signer email (optional)"
                      }
                    },
                    "description": "who signed (the ceremony artifact)"
                  }
                },
                "description": "Complete the signing ceremony (the human act the esign OFFER hands off to). The signer identity is the ceremony artifact — an anonymous POST refuses; the sandbox completion registers Document.signed@1 for the named signer."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals/{dealId}/notarize": {
      "post": {
        "summary": "Record the notarized power of attorney — requires the granting signer (sandbox auto-notarization)",
        "requestBody": {
          "required": true,
          "description": "Record the notarized power of attorney. The granting signer is the ceremony artifact — an anonymous POST refuses; the sandbox notarizes for the named signer and stamps sandbox notary provenance.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "signer"
                ],
                "properties": {
                  "signer": {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "description": "principal legal name"
                      }
                    },
                    "description": "who granted the power of attorney (the ceremony artifact)"
                  },
                  "documentSha256": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$",
                    "minLength": 1,
                    "description": "sha256 of the notarized document (optional — the sandbox derives a deterministic digest when omitted)"
                  }
                },
                "description": "Record the notarized power of attorney. The granting signer is the ceremony artifact — an anonymous POST refuses; the sandbox notarizes for the named signer and stamps sandbox notary provenance."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals/{dealId}/stips": {
      "post": {
        "summary": "Complete stipulations — requires the stip references being completed",
        "requestBody": {
          "required": true,
          "description": "Complete stipulations. The stip references are the artifact — an anonymous POST refuses; each named stip is completed with sandbox verification provenance.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "stips"
                ],
                "properties": {
                  "stips": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "description": "a stipulation reference or description (e.g. \"proof-of-income\")"
                    },
                    "minItems": 1,
                    "description": "the stipulations being completed (at least one)"
                  }
                },
                "description": "Complete stipulations. The stip references are the artifact — an anonymous POST refuses; each named stip is completed with sandbox verification provenance."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals/{dealId}/insurance": {
      "post": {
        "summary": "Prove insurance — requires the policy number (sandbox proof, no carrier connection)",
        "requestBody": {
          "required": true,
          "description": "Prove insurance. The policy is the artifact — an anonymous POST refuses; the named policy is recorded with sandbox provenance (no carrier connection exists in the sandbox).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "policy"
                ],
                "properties": {
                  "policy": {
                    "type": "object",
                    "required": [
                      "policyNumber"
                    ],
                    "properties": {
                      "policyNumber": {
                        "type": "string",
                        "minLength": 1,
                        "description": "policy number"
                      },
                      "carrier": {
                        "type": "string",
                        "minLength": 1,
                        "description": "carrier name (optional)"
                      }
                    },
                    "description": "the insurance policy being proved (the artifact)"
                  }
                },
                "description": "Prove insurance. The policy is the artifact — an anonymous POST refuses; the named policy is recorded with sandbox provenance (no carrier connection exists in the sandbox)."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals/{dealId}/checkout": {
      "post": {
        "summary": "Mint the checkout link — a typed 402 OFFER whose checkoutUrl resolves on this origin, price equals ceiling",
        "description": "Requires a desked deal (409 otherwise). The OFFER carries the checkout URL (it resolves to the sandbox checkout page on this origin), an expiry, and a one-line human instruction. Repeated checkout answers the SAME open payment link (idempotent replay); re-desking supersedes the standing link and the next checkout mints a successor naming what it supersedes; a settled deal refuses 409 (already-settled). In production, where no variable-amount checkout rail is configured, the door answers 503 BLOCKED (rail-unconfigured) and mints no URL.",
        "requestBody": {
          "required": false,
          "description": "No body arguments — send an empty body (or none at all).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "description": "No body arguments — send an empty body (or none at all)."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      },
      "get": {
        "summary": "The sandbox checkout page the minted OFFER link resolves to — sandbox-labeled; JSON always (machine-face law), with a .md face extension",
        "description": "Answers the standing payment link truthfully: open, superseded (the deal was re-desked), settled, or expired — with the amount due, the expiry, and the settle instruction. Sandbox-labeled on every face; simulated funds only. HEAD mirrors GET.",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals/{dealId}/settle": {
      "post": {
        "summary": "Sandbox settle — bearer-gated; unset token answers 503, missing or wrong bearer 401",
        "description": "Sandbox triggers: no settle token configured → 503 UNCONFIGURED; no bearer presented → 401 REFUSED (code missing-bearer); a non-matching bearer → 401 REFUSED (code bearer-mismatch); amount_total ≠ the desked cash-to-close → 409 (refused, never repriced); a repeated order_id replays idempotently (no duplicate capture). Every auth refusal carries an `authority` block naming where settle authority is configured (the sandbox operator token, a worker secret on this deployment). Financed deals also land the Escrow.funded@1 funding leg; a post-delivery settle with a fresh order_id lands SETTLED.",
        "requestBody": {
          "required": true,
          "description": "Sandbox settle relay (bearer-gated). amount_total is integer CENTS and must equal the desked cash-to-close — refused, never repriced.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "order_id",
                  "settlement_ref",
                  "amount_total",
                  "currency"
                ],
                "properties": {
                  "order_id": {
                    "type": "string",
                    "minLength": 1,
                    "description": "the settlement order id — idempotency key; a repeat replays"
                  },
                  "settlement_ref": {
                    "type": "string",
                    "minLength": 1,
                    "description": "the upstream settlement reference"
                  },
                  "amount_total": {
                    "type": "integer",
                    "description": "amount in integer cents — must equal the desked cash-to-close"
                  },
                  "currency": {
                    "type": "string",
                    "minLength": 1,
                    "description": "usd only — any other currency refuses 409"
                  }
                },
                "description": "Sandbox settle relay (bearer-gated). amount_total is integer CENTS and must equal the desked cash-to-close — refused, never repriced."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals/{dealId}/transport/book": {
      "post": {
        "summary": "Book transport",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "pickupZip",
                  "dropZip"
                ],
                "properties": {
                  "pickupZip": {
                    "type": "string",
                    "pattern": "^\\d{5}$",
                    "minLength": 1,
                    "description": "pickup ZIP"
                  },
                  "dropZip": {
                    "type": "string",
                    "pattern": "^\\d{5}$",
                    "minLength": 1,
                    "description": "drop ZIP"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals/{dealId}/transport/track": {
      "post": {
        "summary": "Track transport — dispatched and captured",
        "requestBody": {
          "required": false,
          "description": "No body arguments — send an empty body (or none at all).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "description": "No body arguments — send an empty body (or none at all)."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/buy/deals/{dealId}/transport/delivered": {
      "post": {
        "summary": "Confirm delivery",
        "requestBody": {
          "required": false,
          "description": "No body arguments — send an empty body (or none at all).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "description": "No body arguments — send an empty body (or none at all)."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "summary": "The platform MCP server — JSON-RPC 2.0 over streamable HTTP, keyless; tools: search, fetch, exec",
        "description": "One MCP server for the whole platform; a per-door MCP is a tool-filter view, never a second server. Unauthenticated initialize and tools/call answer in full (the keyless No-ask Zone). GET answers 405 with Allow: POST — no server-initiated SSE stream, no sessions. tools/list names exactly the card-declared tools.",
        "requestBody": {
          "required": true,
          "description": "JSON-RPC 2.0 over streamable HTTP (initialize, tools/list, tools/call).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jsonrpc",
                  "method"
                ],
                "properties": {
                  "jsonrpc": {
                    "const": "2.0"
                  },
                  "id": {
                    "type": [
                      "string",
                      "number",
                      "null"
                    ],
                    "description": "request id (absent for notifications)"
                  },
                  "method": {
                    "type": "string",
                    "description": "initialize | tools/list | tools/call | ping"
                  },
                  "params": {
                    "type": "object",
                    "description": "method params — tools/call takes { name, arguments }"
                  }
                },
                "description": "a JSON-RPC 2.0 request (errors answer JSON-RPC error objects, not envelopes)"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/suite.json": {
      "get": {
        "summary": "The acceptance suite for this origin — ONE api.qa/vitest@1 document carrying declarative suite@1 rows and executable tests, digest-pinned as interfaces.testSuite on the capability card",
        "responses": {
          "200": {
            "description": "the suite document — declarative requirement rows plus the executable tests member",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "$type",
                    "name",
                    "version",
                    "environments",
                    "requirements",
                    "tests"
                  ],
                  "properties": {
                    "$type": {
                      "const": "Suite"
                    },
                    "name": {
                      "type": "string"
                    },
                    "version": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "environments": {
                      "type": "object"
                    },
                    "requirements": {
                      "type": "array"
                    },
                    "tests": {
                      "type": "string",
                      "description": "the executable api.qa/vitest@1 module, verbatim"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/icp.json": {
      "get": {
        "summary": "The self-classification surface — the agent classes this API serves today (agent_classes) and the live attestation ladder",
        "responses": {
          "200": {
            "description": "the ICP document — agent_classes, the attestation ladder, and the honest not_for list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "agent_classes",
                    "ladder"
                  ],
                  "properties": {
                    "contract": {
                      "type": "string"
                    },
                    "version": {
                      "type": "number"
                    },
                    "description": {
                      "type": "string"
                    },
                    "agent_classes": {
                      "type": "array"
                    },
                    "ladder": {
                      "type": "array"
                    },
                    "not_for": {
                      "type": "array"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/keys": {
      "post": {
        "summary": "Anonymous self-service registration — mints an agent account and a sandbox key instantly; no email, no approval, no CAPTCHA",
        "description": "The key (vk_sandbox_…) is returned exactly once and stored only as a sha256 hash. Optional body: { name (label accepted as alias), tier (self-declared; sandbox default), hardCeiling (caller-scoped daily USD ceiling), likely_identity (structured UNVERIFIED provenance { name?, email?, source?, verified: false } — a claim recorded on the account and answered back, never trusted as identity; verified is server-enforced false at mint and a true claim refuses typed 400) }. Unknown body members are dropped, not refused. An Idempotency-Key header makes the mint replayable: the same header answers the same stored mint for 24h. Minting is capped per IP per day — over the cap answers a typed 429 with retry_after. Keyless surfaces stay keyless; the key adds account context and never unlocks licensed data tiers.",
        "requestBody": {
          "required": false,
          "description": "Fully anonymous registration — the body is optional.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "description": "optional key name (label accepted as alias; truncated at 120 chars)"
                  },
                  "label": {
                    "type": "string",
                    "minLength": 1,
                    "description": "optional key label (alias of name)"
                  },
                  "tier": {
                    "type": "string",
                    "pattern": "^[A-Za-z][A-Za-z0-9-]{0,39}$",
                    "minLength": 1,
                    "description": "self-declared tier ('sandbox' default; e.g. licensed, premium) — tier-gated tools refuse the sandbox tier with a typed OFFER"
                  },
                  "hardCeiling": {
                    "type": "number",
                    "exclusiveMinimum": 0,
                    "maximum": 100000,
                    "description": "caller-scoped daily hard ceiling in USD — the accumulation 402 trips against this instead of the posted default"
                  },
                  "likely_identity": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "description": "claimed name (unverified; truncated at 120 chars)"
                      },
                      "email": {
                        "type": "string",
                        "minLength": 1,
                        "description": "claimed email (unverified; truncated at 254 chars)"
                      },
                      "source": {
                        "type": "string",
                        "minLength": 1,
                        "description": "where the claim came from (e.g. 'git-config'; truncated at 120 chars)"
                      },
                      "verified": {
                        "type": "boolean",
                        "description": "ALWAYS false at mint — server-enforced; omit or send false (true refuses typed 400)"
                      }
                    },
                    "description": "optional structured LIKELY-identity provenance — what the minting client CLAIMS about who it is (e.g. seeded from git config). PROVENANCE, NOT IDENTITY: recorded UNVERIFIED on the account, answered back on mint / GET /keys / GET /keys/me, and never trusted for authorization or scope. At least one of name/email is required when the member is sent. verified is server-enforced false at mint — a client claiming verified: true refuses typed 400; the auth ceremony is the only verification path. Unknown mint-body members are dropped, not refused."
                  }
                },
                "description": "Fully anonymous registration — the body is optional."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK envelope — the minted key (shown once), the agent_anon_… account, tier, ceiling, and the funnel links",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "400": {
            "description": "BLOCKED envelope — a malformed body member (name/tier/hardCeiling/likely_identity — incl. a verified: true claim, which is never client-claimable), named",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "BLOCKED envelope carrying retry_after — the per-IP daily mint cap; the meter resets at UTC midnight",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "BLOCKED envelope — no registration store is bound; retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "Key lifecycle: enumerate — the caller’s own keys as fingerprints with status, never the plaintext",
        "description": "Requires Authorization: Bearer vk_sandbox_…. Answers keys[] rows { fingerprint, status: active|revoked|expired, current, created_at, last_used_at? } — the credential is named by its sha256 prefix, never re-shown. When the mint recorded a likely_identity claim it answers at the top level, still marked verified: false — provenance, never a proven identity.",
        "responses": {
          "200": {
            "description": "OK envelope — the account’s keys with lifecycle status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "BLOCKED envelope — keyless or unknown key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "BLOCKED envelope — no key store is bound; retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/keys/rotate": {
      "post": {
        "summary": "Key lifecycle: rotate — mints a successor key on the same account and retires the presented credential",
        "description": "Requires Authorization: Bearer vk_sandbox_…. The successor is shown once (sha256 stored); the presented key is revoked in the same act and no longer resolves.",
        "requestBody": {
          "required": false,
          "description": "No body — the presented bearer credential is the subject: a successor is minted and the old key retired.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "description": "No body — the presented bearer credential is the subject: a successor is minted and the old key retired."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK envelope — the successor key (shown once); the old credential is retired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "BLOCKED envelope — keyless or unknown key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "BLOCKED envelope — no key store is bound; retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/keys/me": {
      "get": {
        "summary": "Key introspection — the account behind the presented sandbox key, with its REAL usage meter",
        "description": "Requires Authorization: Bearer vk_sandbox_…; keyless or unknown keys answer a typed 401 BLOCKED. Answers account id, environment, tier, created_at, the mint-time likely_identity claim when one was recorded (verified: false always — provenance, never a proven identity), and usage { day, spendToDate, callsToday, hardCeiling, remainingCeiling, perPillar? } reflecting the caller’s actual accumulated usage ledger — numbers that move as calls settle; remainingCeiling = hardCeiling − spendToDate on the wire.",
        "responses": {
          "200": {
            "description": "OK envelope — account id, environment, tier, created_at (and name when set), plus the real usage meter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "BLOCKED envelope — keyless or unknown key; this is the one door that requires the key (mint one anonymously at POST /keys)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Key lifecycle: revoke — the presented credential stops resolving in the same act",
        "description": "Requires Authorization: Bearer vk_sandbox_…. Revocation is immediate: the next introspection with the same key answers 401. Mint a fresh key anonymously at POST /keys.",
        "responses": {
          "200": {
            "description": "OK envelope — revoked: true",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "BLOCKED envelope — keyless or unknown key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "BLOCKED envelope — no key store is bound; retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks": {
      "post": {
        "summary": "Subscribe a sink — { url, events } answers { subscription: { id, secret } }; deliveries POST the W0-EVT envelope verbatim, signed vin-signature: t=<unix>,v1=hmac-sha256(secret, t + \".\" + body)",
        "description": "Requires Authorization: Bearer vk_sandbox_… (webhooks deliver YOUR events — own scope only). The secret is shown ONCE (sha256 stored, plaintext never at rest). events takes W0-EVT registry names (e.g. Deal.opened@1); \"*\" and trailing-star globs (\"Deal.*\") are vocabulary. Delivery is at-least-once; verify the HMAC over the RAW body bytes, never a re-serialization.",
        "requestBody": {
          "required": true,
          "description": "Subscribe a webhook sink: deliveries POST the W0-EVT envelope verbatim, signed vin-signature: t=<unix>,v1=hmac-sha256(secret, t + \".\" + body). The secret is shown once; own scope only.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url",
                  "events"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "minLength": 1,
                    "description": "the http(s) sink URL deliveries POST to"
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "description": "a W0-EVT registry name (e.g. Deal.opened@1); \"*\" and trailing-star globs (\"Deal.*\") are vocabulary"
                    },
                    "minItems": 1,
                    "description": "the subscribed event names (at least one)"
                  }
                },
                "description": "Subscribe a webhook sink: deliveries POST the W0-EVT envelope verbatim, signed vin-signature: t=<unix>,v1=hmac-sha256(secret, t + \".\" + body). The secret is shown once; own scope only."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK envelope — the subscription with its one-time secret",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "400": {
            "description": "BLOCKED envelope — aggregated field problems (url / events)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "BLOCKED envelope — keyless or unknown key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "BLOCKED envelope — no subscription store is bound; retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "Enumerate the caller’s webhook subscriptions (no secrets — the plaintext is shown once at mint)",
        "responses": {
          "200": {
            "description": "OK envelope — subscriptions[] rows { id, url, events, status, created_at }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "BLOCKED envelope — keyless or unknown key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "BLOCKED envelope — no subscription store is bound; retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks/echo": {
      "post": {
        "summary": "Mint a sandbox echo inbox — a subscribable sink ON this origin, so webhook delivery is provable without running a listener",
        "requestBody": {
          "required": false,
          "description": "Mint a sandbox echo inbox — a subscribable sink on this origin; no body required.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "description": "Mint a sandbox echo inbox — a subscribable sink on this origin; no body required."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK envelope — { box: { id, url } }; subscribe box.url like any sink",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "BLOCKED envelope — keyless or unknown key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "BLOCKED envelope — no subscription store is bound; retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks/echo/{boxId}": {
      "get": {
        "summary": "Read an echo inbox — the deliveries landed there, raw bytes + headers (vin-signature included, so the HMAC verifies honestly)",
        "responses": {
          "200": {
            "description": "OK envelope — deliveries[] rows { id, body, headers, receivedAt }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "BLOCKED envelope — keyless or unknown key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "EMPTY envelope — no echo box at this address (existence-neutral)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmptyEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "BLOCKED envelope — no subscription store is bound; retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/credit/prequal": {
      "post": {
        "summary": "Soft-pull prequalification — consent required, sandbox bureau rail behind the real wire shape",
        "description": "Sandbox triggers (deterministic — the score is a hash of firstName|lastName|zip, band 550–899): applicant Ava Good zip 94103 → scored 843 (approved band); Gwen Thin zip 94103 → scored 586 (thin/low, below 620); last name \"Frozen\" → result frozen; last name \"Nohit\" → result no-hit; missing or empty consent → 400 BLOCKED (consent required, FCRA). The full persona cast (one named identity per credit tier, coherent on every rail): Paul Prime zip 10443 → 760 (prime); Nina Near zip 10453 → 700 (near-prime, stips); Sam Sub zip 10469 → 620 (subprime); Dee Deep zip 10020 → 550 (deep-subprime, decline + adverse action); Tara Tradeline zip 10323 → 588 (thin file + recent tradelines, fraud-signal review); Bill Bankrupt zip 10237 → 566 (open Ch. 7 decline); Rita Repo zip 10072 → 605 (repo-history stips); Cole Cosign + Cora Cosign zip 10145 → 634 / 796 (the co-signer pair); Frank First zip 10921 → 690 (first-time buyer, limited history). Same identity, same answer, forever.",
        "requestBody": {
          "required": true,
          "description": "Soft-pull prequalification — FCRA consent required; nothing touches the bureau without it.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "applicant",
                  "consent"
                ],
                "properties": {
                  "applicant": {
                    "type": "object",
                    "required": [
                      "firstName",
                      "lastName",
                      "address",
                      "city",
                      "state",
                      "zip"
                    ],
                    "properties": {
                      "firstName": {
                        "type": "string",
                        "minLength": 1,
                        "description": "first name"
                      },
                      "lastName": {
                        "type": "string",
                        "minLength": 1,
                        "description": "last name"
                      },
                      "address": {
                        "type": "string",
                        "minLength": 1,
                        "description": "the street address as a FLAT string (e.g. \"1 Sandbox Way\") — never an object; city, state, and zip are separate sibling fields"
                      },
                      "city": {
                        "type": "string",
                        "minLength": 1,
                        "description": "city"
                      },
                      "state": {
                        "type": "string",
                        "minLength": 1,
                        "description": "state"
                      },
                      "zip": {
                        "type": "string",
                        "minLength": 1,
                        "description": "ZIP"
                      }
                    },
                    "description": "the applicant identity (the deterministic sandbox scores firstName|lastName|zip)"
                  },
                  "consent": {
                    "type": "object",
                    "required": [
                      "consentedAt",
                      "evidence"
                    ],
                    "properties": {
                      "consentedAt": {
                        "type": "string",
                        "minLength": 1,
                        "description": "ISO timestamp of consent"
                      },
                      "evidence": {
                        "type": "string",
                        "minLength": 1,
                        "description": "consent evidence (e.g. \"clickwrap cw_1\")"
                      }
                    },
                    "description": "FCRA consent — a soft pull refuses without it"
                  },
                  "dealId": {
                    "type": "string",
                    "minLength": 1,
                    "description": "attach the pre-approval to this deal (a deal_… id)"
                  }
                },
                "description": "Soft-pull prequalification — FCRA consent required; nothing touches the bureau without it."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/credit/applications": {
      "post": {
        "summary": "Create the deal jacket and submit the credit application (sandbox rail)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "dealId"
                ],
                "properties": {
                  "dealId": {
                    "type": "string",
                    "minLength": 1,
                    "description": "the deal to submit for (a deal_… id)"
                  },
                  "lenders": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "description": "lender FSID"
                    },
                    "description": "lender FSIDs (defaults [\"F00SET\"])"
                  },
                  "applicant": {
                    "type": "object",
                    "properties": {},
                    "description": "accepted for wire-shape parity; the sandbox rail derives the jacket from the deal"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/credit/decisions/simulate": {
      "post": {
        "summary": "Sandbox-only decision webhook simulator — answers the decisioned event",
        "description": "The sandbox webhook-fire (the signed-webhook pattern): body { dealJacketId, decision: approved | declined | conditioned } drives a signed rail delivery, signature verification, and the channel-attested CreditApplication.decisioned@1 on the deal. Sandbox-only — production decisions arrive on the rail webhook.",
        "requestBody": {
          "required": true,
          "description": "Sandbox-only decision webhook simulator (the signed-webhook pattern).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "dealJacketId",
                  "decision"
                ],
                "properties": {
                  "dealJacketId": {
                    "type": "string",
                    "minLength": 1,
                    "description": "the dealJacket ref from POST /credit/applications"
                  },
                  "decision": {
                    "type": "string",
                    "enum": [
                      "approved",
                      "declined",
                      "conditioned"
                    ],
                    "minLength": 1,
                    "description": "the decision to fire"
                  },
                  "dealId": {
                    "type": "string",
                    "minLength": 1,
                    "description": "the deal holding the jacket (looked up when omitted) (a deal_… id)"
                  },
                  "rates": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "term",
                        "apr"
                      ],
                      "properties": {
                        "term": {
                          "type": "number",
                          "description": "term in months"
                        },
                        "apr": {
                          "type": "number",
                          "description": "APR"
                        }
                      },
                      "description": "a rate row"
                    },
                    "description": "decision rates (defaults one 60-month posted-APR row); malformed rows are dropped"
                  },
                  "conditions": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "description": "a stipulation"
                    },
                    "description": "conditions/stipulations (conditioned decisions)"
                  }
                },
                "description": "Sandbox-only decision webhook simulator (the signed-webhook pattern)."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/financing/refinance/quotes": {
      "post": {
        "summary": "Price a refinance against the existing lien — an OFFER envelope with quote@1 expiry (validThrough), decimal-string money",
        "description": "Deterministic sandbox pricing: 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 the quote answers the panel’s best row. Presence-when-true: a lender row exists ONLY when it improves on currentApr — the no-improvement trigger (currentApr at or below the posted band, e.g. \"3.99\") answers a truthful EMPTY, never a worse offer. Same lien, same answer, forever.",
        "requestBody": {
          "required": true,
          "description": "Price a refinance against the existing lien. Answers an OFFER envelope (quote@1 governs expiry — validThrough) when the posted sandbox lender panel improves on the current APR, and a truthful EMPTY when it cannot (the no-improvement trigger: a currentApr at or below the posted band, e.g. \"3.99\", answers no offer — the surface never prices a worse loan).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "vin",
                  "currentBalance",
                  "currentApr",
                  "remainingTermMonths"
                ],
                "properties": {
                  "vin": {
                    "type": "string",
                    "pattern": "^[A-HJ-NPR-Za-hj-npr-z0-9]{17}$",
                    "minLength": 1,
                    "description": "the VIN under the existing lien"
                  },
                  "currentBalance": {
                    "anyOf": [
                      {
                        "type": "string",
                        "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                      },
                      {
                        "type": "number"
                      },
                      {
                        "type": "object",
                        "required": [
                          "amount"
                        ],
                        "properties": {
                          "amount": {
                            "type": [
                              "string",
                              "number"
                            ],
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          "currency": {
                            "type": "string",
                            "description": "USD (the estate settles US dollars only)"
                          }
                        }
                      }
                    ],
                    "exclusiveMinimum": 0,
                    "description": "the payoff balance on the existing lien — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                  },
                  "currentApr": {
                    "anyOf": [
                      {
                        "type": "string",
                        "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                      },
                      {
                        "type": "number"
                      },
                      {
                        "type": "object",
                        "required": [
                          "amount"
                        ],
                        "properties": {
                          "amount": {
                            "type": [
                              "string",
                              "number"
                            ],
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          "currency": {
                            "type": "string",
                            "description": "USD (the estate settles US dollars only)"
                          }
                        }
                      }
                    ],
                    "exclusiveMinimum": 0,
                    "description": "the APR percent on the existing lien — the decimal string the estate emits (\"11.99\") or a number — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                  },
                  "remainingTermMonths": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "months remaining on the existing lien"
                  }
                },
                "description": "Price a refinance against the existing lien. Answers an OFFER envelope (quote@1 governs expiry — validThrough) when the posted sandbox lender panel improves on the current APR, and a truthful EMPTY when it cannot (the no-improvement trigger: a currentApr at or below the posted band, e.g. \"3.99\", answers no offer — the surface never prices a worse loan)."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/financing/refinance/applications": {
      "post": {
        "summary": "Open a refinance application on the existing lien — answers applicationId",
        "description": "Opens the refiApplication@1 lifecycle at OPENED. The read at GET /financing/applications/{applicationId} carries the state and the legal transitions as available[] rows; GET /financing/applications/{applicationId}/offers answers the per-lender priced rows for the lien on file.",
        "requestBody": {
          "required": true,
          "description": "Open a refinance application on the existing lien. Answers applicationId; GET /financing/applications/{applicationId} reads its refiApplication@1 state with the legal transitions as available[] rows, and GET /financing/applications/{applicationId}/offers answers the per-lender priced rows.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "vin",
                  "currentBalance",
                  "currentApr",
                  "remainingTermMonths"
                ],
                "properties": {
                  "vin": {
                    "type": "string",
                    "pattern": "^[A-HJ-NPR-Za-hj-npr-z0-9]{17}$",
                    "minLength": 1,
                    "description": "the VIN under the existing lien"
                  },
                  "currentBalance": {
                    "anyOf": [
                      {
                        "type": "string",
                        "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                      },
                      {
                        "type": "number"
                      },
                      {
                        "type": "object",
                        "required": [
                          "amount"
                        ],
                        "properties": {
                          "amount": {
                            "type": [
                              "string",
                              "number"
                            ],
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          "currency": {
                            "type": "string",
                            "description": "USD (the estate settles US dollars only)"
                          }
                        }
                      }
                    ],
                    "exclusiveMinimum": 0,
                    "description": "the payoff balance on the existing lien — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                  },
                  "currentApr": {
                    "anyOf": [
                      {
                        "type": "string",
                        "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                      },
                      {
                        "type": "number"
                      },
                      {
                        "type": "object",
                        "required": [
                          "amount"
                        ],
                        "properties": {
                          "amount": {
                            "type": [
                              "string",
                              "number"
                            ],
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$"
                          },
                          "currency": {
                            "type": "string",
                            "description": "USD (the estate settles US dollars only)"
                          }
                        }
                      }
                    ],
                    "exclusiveMinimum": 0,
                    "description": "the APR percent on the existing lien — the decimal string the estate emits (\"11.99\") or a number — a decimal dollar amount — the string \"24990.00\" (the form the estate itself emits), the money object {\"amount\":\"24990.00\",\"currency\":\"USD\"}, or a number of dollars"
                  },
                  "remainingTermMonths": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "months remaining on the existing lien"
                  }
                },
                "description": "Open a refinance application on the existing lien. Answers applicationId; GET /financing/applications/{applicationId} reads its refiApplication@1 state with the legal transitions as available[] rows, and GET /financing/applications/{applicationId}/offers answers the per-lender priced rows."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/financing/applications/{applicationId}": {
      "get": {
        "summary": "Read a refinance application — refiApplication@1 state plus available[] (the legal transitions as data)",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/financing/applications/{applicationId}/offers": {
      "get": {
        "summary": "Per-lender refinance offers for the application’s lien — typed, priced, expiring rows {lender, apr, termMonths, payment, amountFinanced, validThrough}",
        "description": "Rows re-derive deterministically from the lien on file on every read. Only lenders whose posted rate improves on the current APR appear (presence-when-true; no ranking prose) — an empty offers[] is the documented no-improvement trigger, not a fault.",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/dealer/inventory": {
      "get": {
        "summary": "The dealer inventory read — the PLATFORM LISTINGS projected for a dealer (units[] alongside the canonical data[] rows), filterable by dealerId / dealerZip / make / model",
        "description": "Dealer inventory IS 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. The door answers keyless (keyless-first-value); a presented Bearer vk_sandbox_… adds the dealer identity onto the read. A non-matching projection answers a truthful EMPTY; a gateway boundary answers a typed 503 (UNAVAILABLE) — inventory is never fabricated. An unknown query parameter refuses a typed 400 naming it. This door carries the posted dealer-inventory unit price (0.01 USD).",
        "responses": {
          "200": {
            "description": "OK envelope — units[] (the projection) + data[] (the canonical rows) + provenance; or a truthful EMPTY with units: []",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "400": {
            "description": "BLOCKED envelope — an unrecognized query parameter or malformed paging, named",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "BLOCKED envelope (UNAVAILABLE) — the platform listings feed did not answer; inventory is never fabricated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/dealer/leads": {
      "post": {
        "summary": "Lead capture — { vin, customer } lands a dealer-scoped lead and answers leadId",
        "description": "Requires Authorization: Bearer vk_sandbox_… (leads are YOUR book). The lead persists dealer-scoped with state CAPTURED; the answer carries leadId and the lead as stored. A validation refusal aggregates every problem in ONE BLOCKED answer.",
        "requestBody": {
          "required": true,
          "description": "Capture a lead on the dealer surface. Requires Authorization: Bearer vk_sandbox_… (leads are YOUR book — the account is the dealer identity). The lead lands dealer-scoped and answers leadId; GET /dealer/leads reads the captured leads back, own scope only.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "vin",
                  "customer"
                ],
                "properties": {
                  "vin": {
                    "type": "string",
                    "pattern": "^[A-HJ-NPR-Za-hj-npr-z0-9]{17}$",
                    "minLength": 1,
                    "description": "the VIN the lead is about"
                  },
                  "customer": {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "description": "customer name"
                      },
                      "zip": {
                        "type": "string",
                        "pattern": "^\\d{5}$",
                        "minLength": 1,
                        "description": "customer ZIP (5 digits)"
                      },
                      "email": {
                        "type": "string",
                        "minLength": 1,
                        "description": "customer email"
                      },
                      "phone": {
                        "type": "string",
                        "minLength": 1,
                        "description": "customer phone"
                      }
                    },
                    "description": "the interested customer — name is required; contact facts are answered back presence-when-true"
                  },
                  "note": {
                    "type": "string",
                    "minLength": 1,
                    "description": "free-form note captured with the lead"
                  }
                },
                "description": "Capture a lead on the dealer surface. Requires Authorization: Bearer vk_sandbox_… (leads are YOUR book — the account is the dealer identity). The lead lands dealer-scoped and answers leadId; GET /dealer/leads reads the captured leads back, own scope only."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK envelope — leadId + the captured lead (state CAPTURED)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "400": {
            "description": "BLOCKED envelope — aggregated field problems (vin / customer.name / …)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "BLOCKED envelope — keyless or unknown key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "BLOCKED envelope — no lead store is bound; retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "The dealer’s captured leads — own scope only, newest first",
        "responses": {
          "200": {
            "description": "OK envelope — leads[] rows { leadId, vin, customer, state, capturedAt }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "BLOCKED envelope — keyless or unknown key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "BLOCKED envelope — no lead store is bound; retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/dealer/deals": {
      "get": {
        "summary": "The deal-side book — the estate’s deal streams projected dealer-side: opened / desked / F&I facts per deal, newest first (single-tenant sandbox book)",
        "description": "Requires Authorization: Bearer vk_sandbox_…. Each row projects the persisted stream’s facts presence-when-true — dealId, openedAt, dealType, vin, the ruling desked figures (decimal-string money), the standing F&I selection — with links into GET /dealer/deals/{dealId} (state + available[]) and GET /fi/deals/{dealId}. An empty book answers OK with deals: [] — the book exists; its rows may be zero.",
        "responses": {
          "200": {
            "description": "OK envelope — deals[] book rows + provenance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "BLOCKED envelope — keyless or unknown key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "BLOCKED envelope — no deal store is bound; retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/dealer/deals/{dealId}": {
      "get": {
        "summary": "The dealer view of ONE deal — state, available[] (the workflow read model), the desked figures, and the F&I book, from the same deal-core walker the buy and fi pillars answer",
        "description": "Requires Authorization: Bearer vk_sandbox_…. Existence-neutral: a malformed or unknown dealId answers the identical EMPTY 404. The F&I block posts only while a selection stands (presence-when-true — a declined or voided selection posts nothing).",
        "responses": {
          "200": {
            "description": "OK envelope — the deal-side read with state, available[], desked, and fni blocks",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "BLOCKED envelope — keyless or unknown key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlockedEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "EMPTY envelope — no deal record at this address (existence-neutral)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmptyEnvelope"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "OkEnvelope": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "const": "OK"
          }
        },
        "description": "200 — substantive content. The collection member name (results/items/events…) is this API's own choice, documented on the operation."
      },
      "EmptyEnvelope": {
        "type": "object",
        "required": [
          "type",
          "message"
        ],
        "properties": {
          "type": {
            "const": "EMPTY"
          },
          "message": {
            "type": "string"
          }
        },
        "description": "200 — a truthful empty collection, never a bare [] masquerading as data."
      },
      "BlockedEnvelope": {
        "type": "object",
        "required": [
          "type",
          "reason"
        ],
        "properties": {
          "type": {
            "const": "BLOCKED"
          },
          "reason": {
            "type": "string"
          }
        },
        "description": "401/403 — a permission boundary with a worded reason."
      },
      "OfferEnvelope": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "const": "OFFER"
          },
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "price": {},
          "checkoutUrl": {
            "type": "string"
          },
          "alternatives": {
            "type": "array"
          }
        },
        "description": "402 — a payment or ceiling re-authorization boundary; an offer to proceed, never a refusal."
      },
      "PricingDocument": {
        "type": "object",
        "required": [
          "model"
        ],
        "properties": {
          "model": {
            "enum": [
              "free",
              "metered"
            ]
          },
          "hardCeiling": {
            "type": "number",
            "exclusiveMinimum": 0
          },
          "unit": {
            "type": "string"
          },
          "price": {
            "type": "number"
          },
          "binding": {
            "type": "boolean",
            "description": "Whether published terms bind this price. `model` answers what it costs; `binding` answers whether you can hold us to it. Absent means not declared — never assume bound."
          },
          "statement": {
            "type": "string",
            "description": "Present when binding is false: the stated intent, in the same words the human pages use."
          },
          "termsUrl": {
            "type": "string",
            "description": "Present when binding is true: the terms document that binds this price."
          },
          "ledgerUrl": {
            "type": "string",
            "description": "Where the open item to bind this price is tracked."
          }
        },
        "description": "AXP Appendix A.2 — closed model \"free\" | \"metered\"; hardCeiling required and > 0 when metered. `binding` is a descriptive member on an axis orthogonal to `model`: binding: true carries termsUrl, binding: false carries statement."
      }
    }
  }
}