{
  "openapi": "3.1.0",
  "info": {
    "title": "Liberty Agent Settlement",
    "version": "0",
    "summary": "Demo protocol for escrow and credits on agent jobs.",
    "description": "Agent Settlement demo. GET /.well-known/agent.json (same JSON as GET /api/agent.json) is the discovery card for crawlers and other agents. GET /api/health.json and /api/settlement.json are protocol documents. GET /api/examples.json lists copy-ready request bodies (same curls as /#adapters). GET /api/templates.json lists preset create-job fields (same buttons as /#create; fill only, no auto-create or fund). GET /api/changelog.json lists recent shipped slices (newest first; dates and titles only; no user counts or revenue). GET /api/scoreboard.json reports honest zeros (external users, paid pilots, revenue). GET /api/fees.json is the machine-readable demo fee schedule (release 5% rounded, dispute no release fee, top-up/fund none). GET /api/tools.json lists callable Settlement surfaces (quote, transition, simulate, verify) plus read-only discovery URLs. Not an MCP server. GET /api/quickstart.json is the ordered ready-to-run demo escrow walk. GET /api/schemas/transition.json is the JSON Schema (2020-12) for POST /api/v0/transition bodies. GET /settlement.openapi.json is this OpenAPI 3.1 document (same JSON at GET /openapi.json and GET /api/openapi.json). POST /api/v0/quote dry-runs the same engine as POST /api/v0/transition: next status and fee math, no state change. Transition commits one action and returns a receipt on release or dispute. Release also returns agent_credits_delta so a client-held agent wallet can be credited. POST /api/v0/simulate runs create → fund → submit → release|dispute in one request. POST /api/v0/verify recomputes that fee math for a client-held receipt or proposed release/dispute. The client holds the job and can export that receipt as JSON from the human UI. /#ledger reads those stored receipts for this-browser running totals and a CSV download — not a server ledger. /#activity appends local demo actions in this browser — Liberty never receives that log. None persist jobs, receipts, or balances or take escrow custody. Optional Idempotency-Key (or body idempotency_key) on quote, transition, and simulate makes create ids stable for retries; Liberty does not replay stored responses. Optional callback_url (notify_url alias) on create is stamped on the job and receipt; Liberty never HTTP-fetches or calls it. The human UI can share a job via a client-held handoff link (#handoff/h1.… base64url JSON) and a terminal receipt via a receipt link (#receipt/r1.… base64url JSON). Credits stay in each browser. Credits are simulated. Not real money. Optional demo API key (Authorization: Bearer or X-Liberty-Key) identifies the adapter; omit it and the route still works (key_optional). Not production auth.",
    "license": {
      "name": "See repository"
    }
  },
  "externalDocs": {
    "description": "Markdown protocol for GitHub readers",
    "url": "/SETTLEMENT.md"
  },
  "tags": [
    {
      "name": "surface",
      "description": "Protocol documents agents can GET, including /.well-known/agent.json for the discovery card, /api/examples.json for copy-ready request bodies, /api/templates.json for preset create-job fields, /api/changelog.json for recent shipped slices, /api/scoreboard.json for honest zeros, /api/fees.json for the demo fee schedule, /api/tools.json for callable Settlement surfaces, /api/quickstart.json for the ordered demo escrow walk, and /api/schemas/transition.json for the transition request JSON Schema. No payments. Demo API key is optional on POST /api/v0/quote, POST /api/v0/transition, POST /api/v0/simulate, and POST /api/v0/verify."
    },
    {
      "name": "quote",
      "description": "Dry-run of the transition engine. Same request shape. Does not mutate state. money is always false. Demo API key is optional."
    },
    {
      "name": "transition",
      "description": "Stateless demo engine. Client holds state. money is always false. Demo API key is optional."
    },
    {
      "name": "simulate",
      "description": "One-shot demo lifecycle through the same engine as transition. money is always false. Demo API key is optional."
    },
    {
      "name": "verify",
      "description": "Stateless receipt / settlement verify. Same fee engine as quote/transition. Does not store receipts. money is always false. Demo API key is optional."
    }
  ],
  "paths": {
    "/.well-known/agent.json": {
      "get": {
        "tags": ["surface"],
        "summary": "Discovery card",
        "description": "Small honest card for crawlers and other agents. Same JSON as /api/agent.json. Reports mode: demo and money: false. Not an A2A Agent Card. Not a ChatGPT plugin.",
        "operationId": "getAgentDiscoveryWellKnown",
        "responses": {
          "200": {
            "description": "Discovery card. Demo only. Not real money.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/AgentDiscovery" }
              }
            }
          }
        }
      }
    },
    "/api/agent.json": {
      "get": {
        "tags": ["surface"],
        "summary": "Discovery card (function path)",
        "description": "Same document as /.well-known/agent.json. Served by the /api/agent.json function; Vercel rewrites the well-known path here.",
        "operationId": "getAgentDiscovery",
        "responses": {
          "200": {
            "description": "Discovery card. Demo only. Not real money.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/AgentDiscovery" }
              }
            }
          }
        }
      }
    },
    "/api/health.json": {
      "get": {
        "tags": ["surface"],
        "summary": "Liveness and mode",
        "operationId": "getHealth",
        "responses": {
          "200": {
            "description": "Service is the Settlement demo. money is always false.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Health" },
                "example": {
                  "service": "liberty-agent-settlement",
                  "mode": "demo",
                  "money": false
                }
              }
            }
          }
        }
      }
    },
    "/api/settlement.json": {
      "get": {
        "tags": ["surface"],
        "summary": "Demo protocol",
        "description": "States (create / fund / submit / release / dispute), fee schedule, job fields, receipt fields, client-held receipt export and receipt links, and the quote / transition / verify API description. Copy-ready request bodies are at /api/examples.json. Preset create-job fields are at /api/templates.json.",
        "operationId": "getSettlementProtocol",
        "responses": {
          "200": {
            "description": "Protocol document. Not an open job ledger.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Protocol" }
              }
            }
          }
        }
      }
    },
    "/api/examples.json": {
      "get": {
        "tags": ["surface"],
        "summary": "Copy-ready adapter examples",
        "description": "Request bodies for POST /api/v0/quote, POST /api/v0/transition (create → fund → submit → release), POST /api/v0/simulate, and POST /api/v0/verify. Same curls as /#adapters. Live origin https://liberty-amber.vercel.app. Optional Authorization: Bearer or X-Liberty-Key. Release returns agent_credits_delta. Demo only. money is always false.",
        "operationId": "getAdapterExamples",
        "responses": {
          "200": {
            "description": "Example request bodies. Not an open job ledger. Not real money.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/AdapterExamples" }
              }
            }
          }
        }
      }
    },
    "/api/templates.json": {
      "get": {
        "tags": ["surface"],
        "summary": "Preset create-job templates",
        "description": "Preset title, amount, and success criteria for the create-job form. Same buttons as /#create. Clicking a template fills the form only. It does not create or fund. Demo only. money is always false.",
        "operationId": "getJobTemplates",
        "responses": {
          "200": {
            "description": "Job templates. Fill only. Not an open job ledger. Not real money.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/JobTemplates" }
              }
            }
          }
        }
      }
    },
    "/api/changelog.json": {
      "get": {
        "tags": ["surface"],
        "summary": "What's new / changelog",
        "description": "Recent shipped Agent Settlement slices, newest first. Dates, short titles, and links only. No user counts. No revenue. Same list as /#whats-new. Demo only. money is always false.",
        "operationId": "getChangelog",
        "responses": {
          "200": {
            "description": "Changelog. Shipped slices only. Not traction. Not real money.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Changelog" }
              }
            }
          }
        }
      }
    },
    "/api/scoreboard.json": {
      "get": {
        "tags": ["surface"],
        "summary": "Honest scoreboard",
        "description": "Challenge evidence. mode is demo. money is always false. external_users, paid_pilots, and revenue_usd stay 0 until there is real evidence. directory_listings is a curated static list of public listing URLs. Listings are not users. Same facts as /#scoreboard.",
        "operationId": "getScoreboard",
        "responses": {
          "200": {
            "description": "Scoreboard. Honest zeros. Not traction. Not real money.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Scoreboard" }
              }
            }
          }
        }
      }
    },
    "/api/fees.json": {
      "get": {
        "tags": ["surface"],
        "summary": "Demo fee schedule",
        "description": "Machine-readable demo fee rules. mode is demo. money is always false. Release is 5% rounded Math.round(amount * 0.05). Dispute has no release fee. Top-up and fund have none. Same math as the quote/transition/simulate/verify engine. Same facts as /#fees.",
        "operationId": "getFeeSchedule",
        "responses": {
          "200": {
            "description": "Fee schedule. Demo rates. Not live GMV. Not real money.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Fees" }
              }
            }
          }
        }
      }
    },
    "/api/tools.json": {
      "get": {
        "tags": ["surface"],
        "summary": "Adapter tools / capability list",
        "description": "Callable Settlement surfaces (quote, transition, simulate, verify) plus read-only discovery URLs. mode is demo. money is always false. persistence is false. Not an MCP server. Not an A2A Agent Card. Not a ChatGPT plugin. GET this instead of scraping the homepage.",
        "operationId": "getAdapterTools",
        "responses": {
          "200": {
            "description": "Capability list. Demo only. Not an MCP server. Not real money.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Tools" }
              }
            }
          }
        }
      }
    },
    "/api/quickstart.json": {
      "get": {
        "tags": ["surface"],
        "summary": "Settlement quickstart",
        "description": "Ordered ready-to-run demo escrow walk (health/discovery → quote → fund → prove → release; dispute optional). mode is demo. money is always false. persistence is false. Client-held protocol. Liberty does not move real money. Scoreboard zeros are honest. Human walk on /#integrate.",
        "operationId": "getSettlementQuickstart",
        "responses": {
          "200": {
            "description": "Ordered demo walk. Demo only. Not real money.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Quickstart" }
              }
            }
          }
        }
      }
    },
    "/api/schemas/transition.json": {
      "get": {
        "tags": ["surface"],
        "summary": "JSON Schema for transition requests",
        "description": "JSON Schema draft 2020-12 for POST /api/v0/transition bodies. $id is the production absolute URL. Client-held demo protocol; Liberty does not move real money. Same request shape as POST /api/v0/quote.",
        "operationId": "getTransitionRequestSchema",
        "responses": {
          "200": {
            "description": "JSON Schema for transition request bodies. Demo only. Not real money.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionRequestSchemaDocument" }
              }
            }
          }
        }
      }
    },
    "/api/v0/transition": {
      "get": {
        "tags": ["transition"],
        "summary": "Discovery for the demo transition engine",
        "operationId": "getTransitionDiscovery",
        "responses": {
          "200": {
            "description": "Path, actions, and demo caveats. money is always false.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionDiscovery" }
              }
            }
          }
        }
      },
      "options": {
        "tags": ["transition"],
        "summary": "CORS preflight",
        "operationId": "optionsTransition",
        "responses": {
          "204": {
            "description": "Allow POST and OPTIONS from any origin."
          }
        }
      },
      "post": {
        "tags": ["transition"],
        "summary": "Apply one demo settlement action",
        "description": "Stateless. Send action plus the fields the protocol requires. Clients hold the job. Validate the body against GET /api/schemas/transition.json before calling. Optional Idempotency-Key (or body idempotency_key) makes create ids stable for retries; Liberty does not replay stored responses. Optional demo API key via Authorization: Bearer or X-Liberty-Key. If sent, response and receipt include key_id (SHA-256 prefix). If omitted, response notes key_optional. Not production auth. Not live escrow custody.",
        "operationId": "postTransition",
        "security": [
          {},
          { "bearerDemo": [] },
          { "libertyKey": [] }
        ],
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "required": false,
            "description": "Bearer demo API key minted on the human UI. Not production auth.",
            "schema": { "type": "string", "example": "Bearer lib_demo_…" }
          },
          {
            "name": "X-Liberty-Key",
            "in": "header",
            "required": false,
            "description": "Same demo key without the Bearer prefix. Preferred if both headers are sent.",
            "schema": { "type": "string" }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional. On create, SHA-256 of the key plus title/amount/criteria yields as_ + 10 hex. Same key and create fields = same job id. Liberty does not replay stored responses.",
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/TransitionRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Next job state. Includes payer_credits when credits change, fee/agent_payout/agent_credits_delta on release, agent_credits_delta: 0 on dispute, receipt on release or dispute, idempotency_key when a key was sent, idempotent true when create derived the id from that key, key_id when a demo key was sent, and key_optional when it was not.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionSuccess" }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, action, or fields.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionError" }
              }
            }
          },
          "409": {
            "description": "Illegal transition or insufficient credits.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionError" }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionError" }
              }
            }
          }
        }
      }
    },
    "/api/v0/quote": {
      "get": {
        "tags": ["quote"],
        "summary": "Discovery for the demo quote engine",
        "operationId": "getQuoteDiscovery",
        "responses": {
          "200": {
            "description": "Path, dry_run, actions, and demo caveats. money is always false.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/QuoteDiscovery" }
              }
            }
          }
        }
      },
      "options": {
        "tags": ["quote"],
        "summary": "CORS preflight",
        "operationId": "optionsQuote",
        "responses": {
          "204": {
            "description": "Allow POST and OPTIONS from any origin."
          }
        }
      },
      "post": {
        "tags": ["quote"],
        "summary": "Dry-run one demo settlement action",
        "description": "Same request shape and engine as POST /api/v0/transition. Computes next status, fee, agent_payout, agent_credits_delta, payer_credits_after, and returned_to_payer when those apply. Does not mutate state. Create quote returns validated open job fields without a durable id. Optional Idempotency-Key is echoed only. Optional demo API key via Authorization: Bearer or X-Liberty-Key. If sent, response includes key_id (SHA-256 prefix). If omitted, response notes key_optional. Not production auth. Not live escrow custody.",
        "operationId": "postQuote",
        "security": [
          {},
          { "bearerDemo": [] },
          { "libertyKey": [] }
        ],
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "required": false,
            "description": "Bearer demo API key minted on the human UI. Not production auth.",
            "schema": { "type": "string", "example": "Bearer lib_demo_…" }
          },
          {
            "name": "X-Liberty-Key",
            "in": "header",
            "required": false,
            "description": "Same demo key without the Bearer prefix. Preferred if both headers are sent.",
            "schema": { "type": "string" }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional. Echoed on success. Create quote stays dry-run and still has no durable id. Liberty does not replay stored responses.",
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/TransitionRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Would-be next job state. quoted is true. Create omits job.id. Includes payer_credits_after when credits would change, fee/agent_payout/agent_credits_delta on release, agent_credits_delta: 0 on dispute, returned_to_payer on dispute, idempotency_key when a key was sent, key_id when a demo key was sent, and key_optional when it was not.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/QuoteSuccess" }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, action, or fields.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionError" }
              }
            }
          },
          "409": {
            "description": "Illegal transition or insufficient credits.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionError" }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionError" }
              }
            }
          }
        }
      }
    },
    "/api/v0/verify": {
      "get": {
        "tags": ["verify"],
        "summary": "Discovery for the demo receipt verify engine",
        "operationId": "getVerifyDiscovery",
        "responses": {
          "200": {
            "description": "Path, dry_run, actions, and demo caveats. money is always false.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/VerifyDiscovery" }
              }
            }
          }
        }
      },
      "options": {
        "tags": ["verify"],
        "summary": "CORS preflight",
        "operationId": "optionsVerify",
        "responses": {
          "204": {
            "description": "Allow POST and OPTIONS from any origin."
          }
        }
      },
      "post": {
        "tags": ["verify"],
        "summary": "Verify a client-held receipt or proposed settlement",
        "description": "Same fee engine as POST /api/v0/quote and POST /api/v0/transition. Send a terminal receipt, or a job (terminal, or submitted plus release/dispute) and optional claimed fee / agent_payout / returned_to_payer. Recomputes expected money fields and lists mismatches. Does not store receipts. Optional demo API key via Authorization: Bearer or X-Liberty-Key. If sent, response includes key_id (SHA-256 prefix). If omitted, response notes key_optional. Not production auth. Not live escrow custody.",
        "operationId": "postVerify",
        "security": [
          {},
          { "bearerDemo": [] },
          { "libertyKey": [] }
        ],
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "required": false,
            "description": "Bearer demo API key minted on the human UI. Not production auth.",
            "schema": { "type": "string", "example": "Bearer lib_demo_…" }
          },
          {
            "name": "X-Liberty-Key",
            "in": "header",
            "required": false,
            "description": "Same demo key without the Bearer prefix. Preferred if both headers are sent.",
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/VerifyRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification ran. valid is true when claimed money matches the engine. verified is true. money is always false. key_id when a demo key was sent, key_optional when it was not.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/VerifySuccess" }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, action, or fields.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionError" }
              }
            }
          },
          "409": {
            "description": "Illegal transition (job is not terminal or submitted).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionError" }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionError" }
              }
            }
          }
        }
      }
    },
    "/api/v0/simulate": {
      "get": {
        "tags": ["simulate"],
        "summary": "Discovery for the demo simulate engine",
        "operationId": "getSimulateDiscovery",
        "responses": {
          "200": {
            "description": "Path, actions, terminals, and demo caveats. money is always false.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SimulateDiscovery" }
              }
            }
          }
        }
      },
      "options": {
        "tags": ["simulate"],
        "summary": "CORS preflight",
        "operationId": "optionsSimulate",
        "responses": {
          "204": {
            "description": "Allow POST and OPTIONS from any origin."
          }
        }
      },
      "post": {
        "tags": ["simulate"],
        "summary": "Run a full demo settlement lifecycle",
        "description": "Same fee engine as POST /api/v0/transition. Runs create → fund → submit → release or dispute in one request. Create assigns a real as_… id. Optional Idempotency-Key makes that create id stable for retries; Liberty does not replay stored responses. Returns ordered steps, final job, payer_credits, agent_credits_delta, and the terminal receipt. Does not persist jobs or receipts. Optional demo API key via Authorization: Bearer or X-Liberty-Key. If sent, response and receipt include key_id (SHA-256 prefix). If omitted, response notes key_optional. Not production auth. Not live escrow custody.",
        "operationId": "postSimulate",
        "security": [
          {},
          { "bearerDemo": [] },
          { "libertyKey": [] }
        ],
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "required": false,
            "description": "Bearer demo API key minted on the human UI. Not production auth.",
            "schema": { "type": "string", "example": "Bearer lib_demo_…" }
          },
          {
            "name": "X-Liberty-Key",
            "in": "header",
            "required": false,
            "description": "Same demo key without the Bearer prefix. Preferred if both headers are sent.",
            "schema": { "type": "string" }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional. Create uses the same stable as_ + 10 hex derivation as transition create. Liberty does not replay stored responses.",
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SimulateRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Full demo walk. Includes ordered steps, final job, payer_credits, agent_credits_delta, and receipt. Echoes idempotency_key and sets idempotent true when create derived the id from a key. money is always false.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SimulateSuccess" }
              }
            }
          },
          "400": {
            "description": "Invalid JSON or fields.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionError" }
              }
            }
          },
          "409": {
            "description": "Insufficient credits to fund.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionError" }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TransitionError" }
              }
            }
          }
        }
      }
    },
    "/settlement.openapi.json": {
      "get": {
        "tags": ["surface"],
        "summary": "This OpenAPI document",
        "operationId": "getOpenApi",
        "responses": {
          "200": {
            "description": "OpenAPI 3.1 description of the static surface, transition API, and object shapes. Same JSON at /openapi.json and /api/openapi.json.",
            "content": {
              "application/json": {
                "schema": { "type": "object" }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "tags": ["surface"],
        "summary": "This OpenAPI document (alias)",
        "description": "Same document as /settlement.openapi.json. Convenience path for adapters that probe /openapi.json.",
        "operationId": "getOpenApiAlias",
        "responses": {
          "200": {
            "description": "Same OpenAPI 3.1 document as /settlement.openapi.json.",
            "content": {
              "application/json": {
                "schema": { "type": "object" }
              }
            }
          }
        }
      }
    },
    "/api/openapi.json": {
      "get": {
        "tags": ["surface"],
        "summary": "This OpenAPI document (API alias)",
        "description": "Same document as /settlement.openapi.json. Convenience path for adapters that probe /api/openapi.json.",
        "operationId": "getOpenApiApiAlias",
        "responses": {
          "200": {
            "description": "Same OpenAPI 3.1 document as /settlement.openapi.json.",
            "content": {
              "application/json": {
                "schema": { "type": "object" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerDemo": {
        "type": "http",
        "scheme": "bearer",
        "description": "Optional demo API key minted on the human UI (localStorage only). Not production auth. Not an account."
      },
      "libertyKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Liberty-Key",
        "description": "Optional demo API key. Same secret as Bearer. Preferred when both headers are sent."
      }
    },
    "schemas": {
      "Health": {
        "type": "object",
        "additionalProperties": false,
        "required": ["service", "mode", "money"],
        "properties": {
          "service": { "const": "liberty-agent-settlement" },
          "mode": { "const": "demo" },
          "money": { "const": false, "description": "Never real money." }
        }
      },
      "AgentDiscovery": {
        "type": "object",
        "description": "Shape of /.well-known/agent.json and /api/agent.json. Honest demo card. Not an A2A Agent Card.",
        "required": ["service", "kind", "mode", "money", "persistence", "origin", "surfaces"],
        "properties": {
          "service": { "const": "liberty-agent-settlement" },
          "kind": { "const": "liberty-agent-settlement-discovery" },
          "version": { "type": "string" },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "persistence": { "const": false },
          "title": { "type": "string" },
          "description": { "type": "string" },
          "origin": { "const": "https://liberty-amber.vercel.app" },
          "human": { "const": "/" },
          "well_known": { "const": "/.well-known/agent.json" },
          "path": { "const": "/api/agent.json" },
          "not": {
            "type": "array",
            "items": { "type": "string", "enum": ["a2a-agent-card", "openai-ai-plugin"] }
          },
          "surfaces": {
            "type": "object",
            "required": ["ui", "health", "protocol", "examples", "templates", "openapi"],
            "properties": {
              "ui": { "const": "/" },
              "health": { "const": "/api/health.json" },
              "protocol": { "const": "/api/settlement.json" },
              "examples": { "const": "/api/examples.json" },
              "templates": { "const": "/api/templates.json" },
              "changelog": { "const": "/api/changelog.json" },
              "scoreboard": { "const": "/api/scoreboard.json" },
              "fees": { "const": "/api/fees.json" },
              "tools": { "const": "/api/tools.json" },
              "quickstart": { "const": "/api/quickstart.json" },
              "transition_schema": { "const": "/api/schemas/transition.json" },
              "openapi": { "const": "/settlement.openapi.json" },
              "openapi_aliases": {
                "type": "array",
                "const": ["/openapi.json", "/api/openapi.json"]
              },
              "markdown": { "const": "/SETTLEMENT.md" },
              "llms": { "const": "/llms.txt" },
              "robots": { "const": "/robots.txt" },
              "sitemap": { "const": "/sitemap.xml" },
              "quote": { "const": "/api/v0/quote" },
              "transition": { "const": "/api/v0/transition" },
              "simulate": { "const": "/api/v0/simulate" },
              "verify": { "const": "/api/v0/verify" }
            }
          },
          "note": { "type": "string" }
        }
      },
      "Protocol": {
        "type": "object",
        "description": "Shape of /api/settlement.json. Adapters should GET that document rather than infer from this schema alone.",
        "required": ["service", "mode", "money", "states", "actions", "fee_schedule", "receipt_fields"],
        "properties": {
          "service": { "const": "liberty-agent-settlement" },
          "version": { "type": "string" },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "states": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/JobStatus" }
          },
          "actions": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Action" }
          },
          "fee_schedule": { "$ref": "#/components/schemas/FeeSchedule" },
          "job": { "type": "object" },
          "receipt_fields": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ReceiptField" }
          },
          "transition_api": { "type": "object" },
          "quote_api": { "type": "object" },
          "simulate_api": { "type": "object" },
          "verify_api": { "type": "object" },
          "discovery": { "type": "object" },
          "examples": { "type": "object" },
          "templates": { "type": "object" },
          "changelog": { "type": "object" },
          "scoreboard": { "type": "object" },
          "fees": { "type": "object" },
          "tools": { "type": "object" },
          "transition_schema": { "type": "object" },
          "handoff": { "$ref": "#/components/schemas/HandoffProtocol" },
          "receipt_link": { "$ref": "#/components/schemas/ReceiptLinkProtocol" },
          "receipt_export": { "$ref": "#/components/schemas/ReceiptExport" },
          "agent_wallet": { "$ref": "#/components/schemas/AgentWalletProtocol" }
        }
      },
      "Changelog": {
        "type": "object",
        "description": "Shape of /api/changelog.json. Newest-first shipped slices. Not traction.",
        "required": ["service", "kind", "mode", "money", "path", "entries"],
        "properties": {
          "service": { "const": "liberty-agent-settlement" },
          "kind": { "const": "liberty-agent-settlement-changelog" },
          "version": { "type": "string" },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "title": { "type": "string" },
          "description": { "type": "string" },
          "path": { "const": "/api/changelog.json" },
          "human": { "const": "/#whats-new" },
          "origin": { "const": "https://liberty-amber.vercel.app" },
          "note": { "type": "string" },
          "entries": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "required": ["date", "id", "title", "href"],
              "properties": {
                "date": { "type": "string", "format": "date" },
                "id": { "type": "string" },
                "title": { "type": "string" },
                "href": { "type": "string" }
              }
            }
          }
        }
      },
      "Scoreboard": {
        "type": "object",
        "description": "Shape of /api/scoreboard.json. Honest zeros. Not traction.",
        "required": ["service", "kind", "mode", "money", "path", "external_users", "paid_pilots", "revenue_usd"],
        "properties": {
          "service": { "const": "liberty-agent-settlement" },
          "kind": { "const": "liberty-agent-settlement-scoreboard" },
          "version": { "type": "string" },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "title": { "type": "string" },
          "description": { "type": "string" },
          "path": { "const": "/api/scoreboard.json" },
          "human": { "const": "/#scoreboard" },
          "origin": { "const": "https://liberty-amber.vercel.app" },
          "external_users": { "const": 0 },
          "paid_pilots": { "const": 0 },
          "revenue_usd": { "const": 0 },
          "directory_listings": {
            "type": "object",
            "description": "Curated public listing URLs Liberty submitted. Listings are not users.",
            "properties": {
              "note": { "type": "string" },
              "entries": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": ["directory", "url"],
                  "properties": {
                    "directory": { "type": "string" },
                    "url": { "type": "string", "format": "uri" },
                    "agent_id": { "type": "string" },
                    "note": { "type": "string" }
                  }
                }
              }
            }
          },
          "live": { "type": "object" },
          "note": { "type": "string" }
        }
      },
      "AdapterExamples": {
        "type": "object",
        "description": "Shape of /api/examples.json. Copy-ready bodies for quote, transition, simulate, and verify.",
        "required": ["service", "mode", "money", "origin", "examples"],
        "properties": {
          "service": { "const": "liberty-agent-settlement" },
          "version": { "type": "string" },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "origin": { "const": "https://liberty-amber.vercel.app" },
          "human_path": { "const": "/#adapters" },
          "examples": {
            "type": "array",
            "items": { "type": "object" }
          }
        }
      },
      "JobTemplates": {
        "type": "object",
        "description": "Shape of /api/templates.json. Preset create-job fields. Fill only.",
        "required": ["service", "mode", "money", "origin", "templates"],
        "properties": {
          "service": { "const": "liberty-agent-settlement" },
          "version": { "type": "string" },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "origin": { "const": "https://liberty-amber.vercel.app" },
          "human_path": { "const": "/#create" },
          "auto_create": { "const": false },
          "auto_fund": { "const": false },
          "templates": {
            "type": "array",
            "items": { "type": "object" }
          }
        }
      },
      "HandoffProtocol": {
        "type": "object",
        "description": "Client-held job snapshot. Not a server endpoint.",
        "properties": {
          "mode": { "const": "client" },
          "persistence": { "const": false },
          "money": { "const": false },
          "encoding": { "type": "string" },
          "prefix": { "const": "h1." },
          "hash": { "const": "#handoff/<token>" },
          "query": { "const": "?handoff=<token>" }
        }
      },
      "ReceiptExport": {
        "type": "object",
        "description": "Client-held terminal receipts. Not a server endpoint or ledger.",
        "properties": {
          "mode": { "const": "client" },
          "persistence": { "const": false },
          "money": { "const": false },
          "storage": { "const": "localStorage" },
          "storage_key": { "const": "liberty.agent-settlement.receipts.v0" },
          "formats": {
            "type": "array",
            "items": { "type": "string", "enum": ["json", "ndjson"] }
          }
        }
      },
      "AgentWalletProtocol": {
        "type": "object",
        "description": "Client-held agent credits. Credited on release. Not a server ledger.",
        "properties": {
          "mode": { "const": "client" },
          "persistence": { "const": false },
          "money": { "const": false },
          "storage": { "const": "localStorage" },
          "storage_key": { "const": "liberty.agent-settlement.agent-credits.v0" },
          "delta_field": { "const": "agent_credits_delta" }
        }
      },
      "ReceiptLinkProtocol": {
        "type": "object",
        "description": "Client-held terminal receipt snapshot. Not a server endpoint.",
        "properties": {
          "mode": { "const": "client" },
          "persistence": { "const": false },
          "money": { "const": false },
          "encoding": { "type": "string" },
          "prefix": { "const": "r1." },
          "hash": { "const": "#receipt/<token>" },
          "query": { "const": "?receipt=<token>" }
        }
      },
      "ReceiptLink": {
        "type": "object",
        "description": "Decoded receipt-link payload before base64url. Compact receipt keys are expanded by the client.",
        "required": ["v", "receipt"],
        "properties": {
          "v": { "const": 1 },
          "receipt": { "$ref": "#/components/schemas/Receipt" }
        }
      },
      "JobHandoff": {
        "type": "object",
        "description": "Decoded handoff payload before base64url. Compact job keys are expanded by the client.",
        "required": ["v", "job"],
        "properties": {
          "v": { "const": 1 },
          "job": { "$ref": "#/components/schemas/Job" },
          "next": {
            "type": "array",
            "items": { "type": "string", "enum": ["fund", "submit", "release", "dispute"] },
            "description": "Next legal actions for this snapshot. Empty when the job is terminal."
          }
        }
      },
      "JobStatus": {
        "type": "string",
        "enum": ["open", "funded", "submitted", "released", "disputed"]
      },
      "Action": {
        "type": "object",
        "required": ["id", "to"],
        "properties": {
          "id": { "type": "string", "enum": ["create", "fund", "submit", "release", "dispute"] },
          "from": { "type": ["string", "null"] },
          "to": { "$ref": "#/components/schemas/JobStatus" },
          "requires": { "type": "array", "items": { "type": "string" } },
          "optional": { "type": "array", "items": { "type": "string" } },
          "effect": { "type": "string" }
        }
      },
      "Quickstart": {
        "type": "object",
        "description": "Shape of /api/quickstart.json. Ordered ready-to-run demo escrow walk. Client-held. Liberty does not move real money.",
        "required": ["service", "kind", "mode", "money", "persistence", "path", "steps"],
        "properties": {
          "service": { "const": "liberty-agent-settlement" },
          "kind": { "const": "liberty-agent-settlement-quickstart" },
          "version": { "type": "string" },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "persistence": { "const": false },
          "title": { "type": "string" },
          "description": { "type": "string" },
          "path": { "const": "/api/quickstart.json" },
          "human": { "const": "/#integrate" },
          "origin": { "const": "https://liberty-amber.vercel.app" },
          "note": { "type": "string" },
          "steps": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "required": ["n", "id", "method", "path", "url", "curl"],
              "properties": {
                "n": { "type": "integer" },
                "id": { "type": "string" },
                "title": { "type": "string" },
                "method": { "type": "string", "enum": ["GET", "POST"] },
                "path": { "type": "string" },
                "url": { "type": "string" },
                "curl": { "type": "string" },
                "optional": { "type": "boolean" },
                "branch": { "type": "boolean" }
              }
            }
          }
        }
      },
      "Tools": {
        "type": "object",
        "description": "Shape of /api/tools.json. Callable Settlement surfaces plus read-only discovery URLs. Not an MCP server.",
        "required": ["service", "kind", "mode", "money", "persistence", "path", "tools", "discovery"],
        "properties": {
          "service": { "const": "liberty-agent-settlement" },
          "kind": { "const": "liberty-agent-settlement-tools" },
          "version": { "type": "string" },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "persistence": { "const": false },
          "title": { "type": "string" },
          "description": { "type": "string" },
          "path": { "const": "/api/tools.json" },
          "human": { "const": "/#adapters" },
          "origin": { "const": "https://liberty-amber.vercel.app" },
          "not": {
            "type": "array",
            "items": { "type": "string", "enum": ["mcp-server", "a2a-agent-card", "openai-ai-plugin"] }
          },
          "note": { "type": "string" },
          "tools": {
            "type": "array",
            "minItems": 4,
            "items": {
              "type": "object",
              "required": ["id", "method", "path", "purpose"],
              "properties": {
                "id": { "type": "string", "enum": ["quote", "transition", "simulate", "verify"] },
                "method": { "const": "POST" },
                "path": { "type": "string" },
                "schema": { "type": "string" },
                "purpose": { "type": "string" },
                "body": { "type": "array", "items": { "type": "string" } },
                "optional": { "type": "array", "items": { "type": "string" } },
                "actions": { "type": "array", "items": { "type": "object" } },
                "bodies": { "type": "array", "items": { "type": "object" } }
              }
            }
          },
          "discovery": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "required": ["id", "method", "path", "purpose"],
              "properties": {
                "id": { "type": "string" },
                "method": { "const": "GET" },
                "path": { "type": "string" },
                "alias": { "type": "string" },
                "aliases": { "type": "array", "items": { "type": "string" } },
                "purpose": { "type": "string" }
              }
            }
          }
        }
      },
      "Fees": {
        "type": "object",
        "description": "Shape of /api/fees.json. Demo fee schedule. Same math as the engine. Not live GMV.",
        "required": ["service", "kind", "mode", "money", "path", "release", "dispute", "top_up", "fund"],
        "properties": {
          "service": { "const": "liberty-agent-settlement" },
          "kind": { "const": "liberty-agent-settlement-fees" },
          "version": { "type": "string" },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "title": { "type": "string" },
          "description": { "type": "string" },
          "path": { "const": "/api/fees.json" },
          "human": { "const": "/#fees" },
          "origin": { "const": "https://liberty-amber.vercel.app" },
          "unit": { "const": "credits" },
          "integer_only": { "const": true },
          "release": {
            "type": "object",
            "properties": {
              "rate": { "type": "number", "const": 0.05 },
              "rounding": { "const": "nearest_credit" },
              "when": { "const": "payer_releases" },
              "formula": { "const": "Math.round(amount * 0.05)" },
              "agent_payout": { "const": "amount - fee" },
              "note": { "type": "string" }
            }
          },
          "dispute": {
            "type": "object",
            "properties": {
              "release_fee": { "const": 0 },
              "escrow": { "const": "returned_to_payer" },
              "note": { "type": "string" }
            }
          },
          "top_up": { "type": "object", "properties": { "fee": { "const": 0 } } },
          "fund": { "type": "object", "properties": { "fee": { "const": 0 }, "note": { "type": "string" } } },
          "note": { "type": "string" }
        }
      },
      "FeeSchedule": {
        "type": "object",
        "properties": {
          "release": {
            "type": "object",
            "properties": {
              "rate": { "type": "number", "const": 0.05 },
              "rounding": { "const": "nearest_credit" },
              "formula": { "const": "Math.round(amount * 0.05)" },
              "agent_payout": { "const": "amount - fee" }
            }
          },
          "dispute": {
            "type": "object",
            "properties": {
              "release_fee": { "const": 0 },
              "escrow": { "const": "returned_to_payer" }
            }
          },
          "top_up": { "type": "object", "properties": { "fee": { "const": 0 } } },
          "fund": { "type": "object", "properties": { "fee": { "const": 0 } } }
        }
      },
      "Job": {
        "type": "object",
        "required": ["id", "title", "amount", "criteria", "status", "createdAt"],
        "properties": {
          "id": { "type": "string", "pattern": "^as_[0-9a-f]{10}$" },
          "title": { "type": "string", "maxLength": 80 },
          "amount": { "type": "integer", "minimum": 1 },
          "criteria": { "type": "string" },
          "proofUrl": { "type": "string" },
          "status": { "$ref": "#/components/schemas/JobStatus" },
          "createdAt": { "type": "string", "format": "date-time" },
          "fundedAt": { "type": ["string", "null"], "format": "date-time" },
          "submittedAt": { "type": ["string", "null"], "format": "date-time" },
          "resolvedAt": { "type": ["string", "null"], "format": "date-time" },
          "fee": { "type": "integer", "minimum": 0 },
          "agentPayout": { "type": "integer", "minimum": 0 },
          "clientRef": {
            "type": "string",
            "maxLength": 128,
            "description": "Present when client_ref was sent on create. Adapter/correlation id. Independent of job.id and Idempotency-Key."
          },
          "callbackUrl": {
            "type": "string",
            "maxLength": 512,
            "format": "uri",
            "description": "Present when callback_url or notify_url was sent on create. Adapter-owned https URL. Liberty never HTTP-fetches or calls this URL."
          },
          "proofNote": {
            "type": "string",
            "maxLength": 400,
            "description": "Present on submitted and later jobs when proof_note was sent."
          },
          "releaseNote": {
            "type": "string",
            "maxLength": 400,
            "description": "Present on released jobs when release_note was sent."
          },
          "disputeReason": {
            "type": "string",
            "maxLength": 400,
            "description": "Present on disputed jobs when dispute_reason was sent."
          }
        }
      },
      "Receipt": {
        "type": "object",
        "required": [
          "job_id",
          "title",
          "status",
          "amount",
          "release_fee",
          "agent_payout",
          "returned_to_payer",
          "success_criteria",
          "proof",
          "created",
          "funded",
          "submitted",
          "resolved"
        ],
        "properties": {
          "job_id": { "type": "string" },
          "title": { "type": "string" },
          "status": { "$ref": "#/components/schemas/JobStatus" },
          "amount": { "type": "integer" },
          "release_fee": { "type": "integer" },
          "agent_payout": { "type": "integer" },
          "returned_to_payer": { "type": "integer" },
          "success_criteria": { "type": "string" },
          "proof": { "type": "string" },
          "created": { "type": "string", "format": "date-time" },
          "funded": { "type": ["string", "null"], "format": "date-time" },
          "submitted": { "type": ["string", "null"], "format": "date-time" },
          "resolved": { "type": ["string", "null"], "format": "date-time" },
          "key_id": {
            "type": "string",
            "pattern": "^k_[0-9a-f]{12}$",
            "description": "Present when a demo key header was sent. SHA-256 hex prefix. Never the raw key."
          },
          "client_ref": {
            "type": "string",
            "maxLength": 128,
            "description": "Present when the adapter sent client_ref on create."
          },
          "callback_url": {
            "type": "string",
            "maxLength": 512,
            "format": "uri",
            "description": "Present when the adapter sent callback_url or notify_url on create. Liberty never HTTP-fetches or calls this URL."
          },
          "proof_note": {
            "type": "string",
            "maxLength": 400,
            "description": "Present when the agent sent proof_note on submit."
          },
          "release_note": {
            "type": "string",
            "maxLength": 400,
            "description": "Present when the payer sent release_note on release."
          },
          "dispute_reason": {
            "type": "string",
            "maxLength": 400,
            "description": "Present when the payer sent dispute_reason on dispute."
          }
        }
      },
      "ReceiptField": {
        "type": "object",
        "required": ["id", "source"],
        "properties": {
          "id": { "type": "string" },
          "source": { "type": "string" },
          "unit": { "type": "string" },
          "rate": { "type": "string" }
        }
      },
      "TransitionDiscovery": {
        "type": "object",
        "required": ["service", "mode", "money", "path", "methods", "auth", "persistence", "actions"],
        "properties": {
          "service": { "const": "liberty-agent-settlement" },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "path": { "const": "/api/v0/transition" },
          "methods": { "type": "array", "items": { "type": "string" } },
          "auth": { "$ref": "#/components/schemas/DemoAuthDiscovery" },
          "persistence": { "const": false },
          "actions": {
            "type": "array",
            "items": { "type": "string", "enum": ["create", "fund", "submit", "release", "dispute"] }
          },
          "note": { "type": "string" },
          "protocol": { "type": "string" },
          "dry_run": { "type": "boolean" },
          "quote": { "type": "string" },
          "commit": { "type": "string" },
          "verify": { "type": "string" },
          "simulate": { "type": "string" },
          "idempotency": { "$ref": "#/components/schemas/IdempotencyDiscovery" }
        }
      },
      "QuoteDiscovery": {
        "type": "object",
        "required": ["service", "mode", "money", "path", "methods", "auth", "persistence", "dry_run", "actions"],
        "properties": {
          "service": { "const": "liberty-agent-settlement" },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "path": { "const": "/api/v0/quote" },
          "methods": { "type": "array", "items": { "type": "string" } },
          "auth": { "$ref": "#/components/schemas/DemoAuthDiscovery" },
          "persistence": { "const": false },
          "dry_run": { "const": true },
          "actions": {
            "type": "array",
            "items": { "type": "string", "enum": ["create", "fund", "submit", "release", "dispute"] }
          },
          "note": { "type": "string" },
          "protocol": { "type": "string" },
          "quote": { "const": "/api/v0/quote" },
          "commit": { "const": "/api/v0/transition" },
          "verify": { "const": "/api/v0/verify" },
          "simulate": { "const": "/api/v0/simulate" },
          "idempotency": { "$ref": "#/components/schemas/IdempotencyDiscovery" }
        }
      },
      "VerifyDiscovery": {
        "type": "object",
        "required": ["service", "mode", "money", "path", "methods", "auth", "persistence", "dry_run", "actions"],
        "properties": {
          "service": { "const": "liberty-agent-settlement" },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "path": { "const": "/api/v0/verify" },
          "methods": { "type": "array", "items": { "type": "string" } },
          "auth": { "$ref": "#/components/schemas/DemoAuthDiscovery" },
          "persistence": { "const": false },
          "dry_run": { "const": true },
          "actions": {
            "type": "array",
            "items": { "type": "string", "enum": ["release", "dispute"] }
          },
          "note": { "type": "string" },
          "protocol": { "type": "string" },
          "quote": { "const": "/api/v0/quote" },
          "commit": { "const": "/api/v0/transition" },
          "verify": { "const": "/api/v0/verify" },
          "simulate": { "const": "/api/v0/simulate" }
        }
      },
      "SimulateDiscovery": {
        "type": "object",
        "required": ["service", "mode", "money", "path", "methods", "auth", "persistence", "actions"],
        "properties": {
          "service": { "const": "liberty-agent-settlement" },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "path": { "const": "/api/v0/simulate" },
          "methods": { "type": "array", "items": { "type": "string" } },
          "auth": { "$ref": "#/components/schemas/DemoAuthDiscovery" },
          "persistence": { "const": false },
          "dry_run": { "const": false },
          "actions": {
            "type": "array",
            "items": { "type": "string", "enum": ["create", "fund", "submit", "release", "dispute"] }
          },
          "terminals": {
            "type": "array",
            "items": { "type": "string", "enum": ["release", "dispute"] }
          },
          "note": { "type": "string" },
          "protocol": { "type": "string" },
          "quote": { "const": "/api/v0/quote" },
          "commit": { "const": "/api/v0/transition" },
          "verify": { "const": "/api/v0/verify" },
          "simulate": { "const": "/api/v0/simulate" },
          "idempotency": { "$ref": "#/components/schemas/IdempotencyDiscovery" }
        }
      },
      "SimulateRequest": {
        "type": "object",
        "required": ["title", "amount", "criteria", "payer_credits", "proof_url"],
        "properties": {
          "title": { "type": "string", "maxLength": 80 },
          "amount": { "type": "integer", "minimum": 1 },
          "criteria": { "type": "string" },
          "payer_credits": { "type": "integer", "minimum": 0 },
          "payerCredits": { "type": "integer", "minimum": 0 },
          "proof_url": { "type": "string" },
          "proofUrl": { "type": "string" },
          "proof_note": { "type": "string", "maxLength": 400, "description": "Optional. Accepted on the submit step. Lands on the job and later receipt." },
          "proofNote": { "type": "string", "maxLength": 400 },
          "terminal": { "type": "string", "enum": ["release", "dispute"], "default": "release" },
          "release_note": { "type": "string", "maxLength": 400, "description": "Optional. Accepted when terminal is release." },
          "releaseNote": { "type": "string", "maxLength": 400 },
          "dispute_reason": { "type": "string", "maxLength": 400, "description": "Optional. Accepted when terminal is dispute." },
          "disputeReason": { "type": "string", "maxLength": 400 },
          "client_ref": { "type": "string", "maxLength": 128, "description": "Optional adapter/correlation id. Lands on the job and receipt. Independent of Idempotency-Key." },
          "clientRef": { "type": "string", "maxLength": 128 },
          "callback_url": { "type": "string", "maxLength": 512, "format": "uri", "description": "Optional adapter-owned https URL. Lands on the job and receipt. Liberty never HTTP-fetches or calls it. notify_url is an alias." },
          "callbackUrl": { "type": "string", "maxLength": 512, "format": "uri" },
          "notify_url": { "type": "string", "maxLength": 512, "format": "uri" },
          "notifyUrl": { "type": "string", "maxLength": 512, "format": "uri" },
          "idempotency_key": { "$ref": "#/components/schemas/IdempotencyKey" },
          "idempotencyKey": { "$ref": "#/components/schemas/IdempotencyKey" }
        }
      },
      "SimulateStep": {
        "type": "object",
        "required": ["action", "job"],
        "properties": {
          "action": { "type": "string", "enum": ["create", "fund", "submit", "release", "dispute"] },
          "job": { "$ref": "#/components/schemas/Job" },
          "payer_credits": { "type": "integer", "minimum": 0 },
          "fee": { "type": "integer", "minimum": 0 },
          "agent_payout": { "type": "integer", "minimum": 0 },
          "agent_credits_delta": { "type": "integer", "minimum": 0 },
          "returned_to_payer": { "type": "integer", "minimum": 0 },
          "receipt": { "$ref": "#/components/schemas/Receipt" },
          "idempotency_key": { "$ref": "#/components/schemas/IdempotencyKey" },
          "idempotent": { "type": "boolean", "description": "True when create assigned job.id from the Idempotency-Key." }
        }
      },
      "SimulateSuccess": {
        "type": "object",
        "required": ["ok", "mode", "money", "steps", "job", "payer_credits"],
        "properties": {
          "ok": { "const": true },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "terminal": { "type": "string", "enum": ["release", "dispute"] },
          "steps": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/SimulateStep" }
          },
          "job": { "$ref": "#/components/schemas/Job" },
          "payer_credits": { "type": "integer", "minimum": 0 },
          "fee": { "type": "integer", "minimum": 0 },
          "agent_payout": { "type": "integer", "minimum": 0 },
          "agent_credits_delta": { "type": "integer", "minimum": 0, "description": "Credits to add to a client-held agent wallet. Same as agent_payout on release; 0 on dispute." },
          "returned_to_payer": { "type": "integer", "minimum": 0 },
          "receipt": { "$ref": "#/components/schemas/Receipt" },
          "key_id": {
            "type": "string",
            "pattern": "^k_[0-9a-f]{12}$",
            "description": "Present when a demo key header was sent."
          },
          "key_optional": { "type": "boolean", "description": "True when no demo key header was sent." },
          "auth": { "$ref": "#/components/schemas/DemoAuth" },
          "idempotency_key": { "$ref": "#/components/schemas/IdempotencyKey" },
          "idempotent": { "type": "boolean", "description": "True when create assigned job.id from the Idempotency-Key." }
        }
      },
      "VerifyMoney": {
        "type": "object",
        "properties": {
          "fee": { "type": "integer", "minimum": 0 },
          "agent_payout": { "type": "integer", "minimum": 0 },
          "returned_to_payer": { "type": "integer", "minimum": 0 }
        }
      },
      "VerifyRequest": {
        "oneOf": [
          {
            "type": "object",
            "required": ["receipt"],
            "properties": {
              "receipt": { "$ref": "#/components/schemas/Receipt" }
            }
          },
          { "$ref": "#/components/schemas/Receipt" },
          {
            "type": "object",
            "required": ["job"],
            "properties": {
              "job": { "$ref": "#/components/schemas/Job" },
              "action": { "type": "string", "enum": ["release", "dispute"] },
              "fee": { "type": "integer", "minimum": 0 },
              "agent_payout": { "type": "integer", "minimum": 0 },
              "returned_to_payer": { "type": "integer", "minimum": 0 }
            }
          }
        ]
      },
      "VerifySuccess": {
        "type": "object",
        "required": ["ok", "mode", "money", "valid", "verified", "expected", "received", "mismatches"],
        "properties": {
          "ok": { "const": true },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "valid": { "type": "boolean" },
          "verified": { "const": true },
          "expected": { "$ref": "#/components/schemas/VerifyMoney" },
          "received": { "$ref": "#/components/schemas/VerifyMoney" },
          "mismatches": {
            "type": "array",
            "items": { "type": "string" }
          },
          "action": { "type": "string", "enum": ["release", "dispute"] },
          "job_id": { "type": "string", "pattern": "^as_[0-9a-f]{10}$" },
          "key_id": {
            "type": "string",
            "pattern": "^k_[0-9a-f]{12}$",
            "description": "Present when a demo key header was sent."
          },
          "key_optional": { "type": "boolean", "description": "True when no demo key header was sent." },
          "auth": { "$ref": "#/components/schemas/DemoAuth" }
        }
      },
      "QuoteJob": {
        "type": "object",
        "description": "Same job fields as a commit. Create quotes omit id — no durable id is assigned until POST /api/v0/transition.",
        "required": ["title", "amount", "criteria", "status", "createdAt"],
        "properties": {
          "id": { "type": "string", "pattern": "^as_[0-9a-f]{10}$" },
          "title": { "type": "string", "maxLength": 80 },
          "amount": { "type": "integer", "minimum": 1 },
          "criteria": { "type": "string" },
          "proofUrl": { "type": "string" },
          "status": { "$ref": "#/components/schemas/JobStatus" },
          "createdAt": { "type": "string", "format": "date-time" },
          "fundedAt": { "type": ["string", "null"], "format": "date-time" },
          "submittedAt": { "type": ["string", "null"], "format": "date-time" },
          "resolvedAt": { "type": ["string", "null"], "format": "date-time" },
          "fee": { "type": "integer", "minimum": 0 },
          "agentPayout": { "type": "integer", "minimum": 0 },
          "clientRef": { "type": "string", "maxLength": 128 },
          "callbackUrl": { "type": "string", "maxLength": 512, "format": "uri" },
          "proofNote": { "type": "string", "maxLength": 400 },
          "releaseNote": { "type": "string", "maxLength": 400 },
          "disputeReason": { "type": "string", "maxLength": 400 }
        }
      },
      "QuoteSuccess": {
        "type": "object",
        "required": ["ok", "mode", "money", "quoted", "action", "job"],
        "properties": {
          "ok": { "const": true },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "quoted": { "const": true },
          "action": { "type": "string", "enum": ["create", "fund", "submit", "release", "dispute"] },
          "job": { "$ref": "#/components/schemas/QuoteJob" },
          "payer_credits": { "type": "integer", "minimum": 0 },
          "payer_credits_after": { "type": "integer", "minimum": 0 },
          "fee": { "type": "integer", "minimum": 0 },
          "agent_payout": { "type": "integer", "minimum": 0 },
          "agent_credits_delta": { "type": "integer", "minimum": 0, "description": "Credits to add to a client-held agent wallet. Same as agent_payout on release; 0 on dispute." },
          "returned_to_payer": { "type": "integer", "minimum": 0 },
          "receipt": { "$ref": "#/components/schemas/Receipt" },
          "key_id": {
            "type": "string",
            "pattern": "^k_[0-9a-f]{12}$",
            "description": "Present when a demo key header was sent."
          },
          "key_optional": { "type": "boolean", "description": "True when no demo key header was sent." },
          "auth": { "$ref": "#/components/schemas/DemoAuth" },
          "idempotency_key": { "$ref": "#/components/schemas/IdempotencyKey" }
        }
      },
      "TransitionRequestSchemaDocument": {
        "type": "object",
        "description": "Shape of GET /api/schemas/transition.json. JSON Schema 2020-12 for POST /api/v0/transition bodies.",
        "required": ["$schema", "$id", "title", "description", "oneOf"],
        "properties": {
          "$schema": { "const": "https://json-schema.org/draft/2020-12/schema" },
          "$id": { "const": "https://liberty-amber.vercel.app/api/schemas/transition.json" },
          "title": { "type": "string" },
          "description": { "type": "string" },
          "type": { "const": "object" },
          "oneOf": { "type": "array", "minItems": 5, "maxItems": 5 },
          "$defs": { "type": "object" }
        }
      },
      "TransitionRequest": {
        "description": "Same request shape as GET /api/schemas/transition.json (JSON Schema 2020-12). Client-held demo protocol; Liberty does not move real money.",
        "oneOf": [
          { "$ref": "#/components/schemas/CreateRequest" },
          { "$ref": "#/components/schemas/FundRequest" },
          { "$ref": "#/components/schemas/SubmitRequest" },
          { "$ref": "#/components/schemas/ReleaseRequest" },
          { "$ref": "#/components/schemas/DisputeRequest" }
        ]
      },
      "CreateRequest": {
        "type": "object",
        "required": ["action", "title", "amount", "criteria"],
        "properties": {
          "action": { "const": "create" },
          "title": { "type": "string", "maxLength": 80 },
          "amount": { "type": "integer", "minimum": 1 },
          "criteria": { "type": "string" },
          "client_ref": { "type": "string", "maxLength": 128, "description": "Optional adapter/correlation id. Lands on the job and later receipt. Independent of Idempotency-Key. Empty or whitespace-only is rejected." },
          "clientRef": { "type": "string", "maxLength": 128 },
          "callback_url": { "type": "string", "maxLength": 512, "format": "uri", "description": "Optional adapter-owned https URL. Lands on the job and later receipt. Liberty never HTTP-fetches or calls it. Empty or whitespace-only is rejected. notify_url is an alias." },
          "callbackUrl": { "type": "string", "maxLength": 512, "format": "uri" },
          "notify_url": { "type": "string", "maxLength": 512, "format": "uri" },
          "notifyUrl": { "type": "string", "maxLength": 512, "format": "uri" },
          "idempotency_key": { "$ref": "#/components/schemas/IdempotencyKey" },
          "idempotencyKey": { "$ref": "#/components/schemas/IdempotencyKey" }
        }
      },
      "FundRequest": {
        "type": "object",
        "required": ["action", "job", "payer_credits"],
        "properties": {
          "action": { "const": "fund" },
          "job": { "$ref": "#/components/schemas/Job" },
          "payer_credits": { "type": "integer", "minimum": 0 },
          "payerCredits": { "type": "integer", "minimum": 0 },
          "idempotency_key": { "$ref": "#/components/schemas/IdempotencyKey" },
          "idempotencyKey": { "$ref": "#/components/schemas/IdempotencyKey" }
        }
      },
      "SubmitRequest": {
        "type": "object",
        "required": ["action", "job", "proof_url"],
        "properties": {
          "action": { "const": "submit" },
          "job": { "$ref": "#/components/schemas/Job" },
          "proof_url": { "type": "string" },
          "proofUrl": { "type": "string" },
          "proof_note": { "type": "string", "maxLength": 400 },
          "proofNote": { "type": "string", "maxLength": 400 },
          "idempotency_key": { "$ref": "#/components/schemas/IdempotencyKey" },
          "idempotencyKey": { "$ref": "#/components/schemas/IdempotencyKey" }
        }
      },
      "ReleaseRequest": {
        "type": "object",
        "required": ["action", "job"],
        "properties": {
          "action": { "const": "release" },
          "job": { "$ref": "#/components/schemas/Job" },
          "release_note": { "type": "string", "maxLength": 400 },
          "releaseNote": { "type": "string", "maxLength": 400 },
          "idempotency_key": { "$ref": "#/components/schemas/IdempotencyKey" },
          "idempotencyKey": { "$ref": "#/components/schemas/IdempotencyKey" }
        }
      },
      "DisputeRequest": {
        "type": "object",
        "required": ["action", "job"],
        "properties": {
          "action": { "const": "dispute" },
          "job": { "$ref": "#/components/schemas/Job" },
          "payer_credits": { "type": "integer", "minimum": 0 },
          "dispute_reason": { "type": "string", "maxLength": 400 },
          "disputeReason": { "type": "string", "maxLength": 400 },
          "idempotency_key": { "$ref": "#/components/schemas/IdempotencyKey" },
          "idempotencyKey": { "$ref": "#/components/schemas/IdempotencyKey" }
        }
      },
      "TransitionSuccess": {
        "type": "object",
        "required": ["ok", "mode", "money", "action", "job"],
        "properties": {
          "ok": { "const": true },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "action": { "type": "string", "enum": ["create", "fund", "submit", "release", "dispute"] },
          "job": { "$ref": "#/components/schemas/Job" },
          "payer_credits": { "type": "integer", "minimum": 0 },
          "fee": { "type": "integer", "minimum": 0 },
          "agent_payout": { "type": "integer", "minimum": 0 },
          "agent_credits_delta": { "type": "integer", "minimum": 0, "description": "Credits to add to a client-held agent wallet. Same as agent_payout on release; 0 on dispute." },
          "returned_to_payer": { "type": "integer", "minimum": 0 },
          "receipt": { "$ref": "#/components/schemas/Receipt" },
          "key_id": {
            "type": "string",
            "pattern": "^k_[0-9a-f]{12}$",
            "description": "Present when a demo key header was sent."
          },
          "key_optional": { "type": "boolean", "description": "True when no demo key header was sent." },
          "auth": { "$ref": "#/components/schemas/DemoAuth" },
          "idempotency_key": { "$ref": "#/components/schemas/IdempotencyKey" },
          "idempotent": { "type": "boolean", "description": "True when create assigned job.id from the Idempotency-Key." }
        }
      },
      "IdempotencyKey": {
        "type": "string",
        "description": "Optional. Header Idempotency-Key or body idempotency_key. On create, SHA-256 of the key plus title/amount/criteria yields as_ + 10 hex. Quote echoes only. Liberty does not replay stored responses."
      },
      "IdempotencyDiscovery": {
        "type": "object",
        "properties": {
          "header": { "const": "Idempotency-Key" },
          "body": { "const": "idempotency_key" },
          "persistence": { "const": false },
          "replay": { "const": false },
          "note": { "type": "string" }
        }
      },
      "DemoAuth": {
        "type": "object",
        "required": ["required", "mode", "status"],
        "properties": {
          "required": { "const": false },
          "mode": { "const": "demo" },
          "status": { "type": "string", "enum": ["accepted", "key_optional"] },
          "key_id": { "type": "string", "pattern": "^k_[0-9a-f]{12}$" }
        }
      },
      "DemoAuthDiscovery": {
        "type": "object",
        "required": ["required", "mode", "headers", "missing"],
        "properties": {
          "required": { "const": false },
          "mode": { "const": "demo" },
          "headers": { "type": "array", "items": { "type": "string" } },
          "key_id": { "type": "string" },
          "missing": { "const": "key_optional" }
        }
      },
      "TransitionError": {
        "type": "object",
        "required": ["ok", "mode", "money", "error", "message"],
        "properties": {
          "ok": { "const": false },
          "mode": { "const": "demo" },
          "money": { "const": false },
          "key_id": { "type": "string", "pattern": "^k_[0-9a-f]{12}$" },
          "key_optional": { "type": "boolean" },
          "auth": { "$ref": "#/components/schemas/DemoAuth" },
          "error": {
            "type": "string",
            "enum": [
              "invalid_json",
              "invalid_action",
              "missing_field",
              "invalid_field",
              "illegal_transition",
              "insufficient_credits",
              "method_not_allowed"
            ]
          },
          "message": { "type": "string" },
          "action": { "type": "string" },
          "field": { "type": "string" },
          "from": { "type": "string" },
          "expected": { "type": "string" },
          "needed": { "type": "integer" },
          "payer_credits": { "type": "integer" },
          "actions": {
            "type": "array",
            "items": { "type": "string" }
          }
        }
      }
    }
  }
}
