{"openapi":"3.1.0","info":{"title":"journalize","contact":{"name":"Journalize","email":"hello@journalize.dev"},"version":"0.1.0"},"paths":{"/register":{"post":{"summary":"Register","description":"No request body, no auth dependency — deliberately the one endpoint in\nthis service nothing else requires being authenticated to reach. Free:\ngenerating a keypair and storing a public key costs us nothing worth\nmetering, and there is no \"resource\" to price via x402 for an action\nthat produces the very identity x402 pricing would otherwise apply to.","operationId":"register_register_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterResponse"}}}}}}},"/journal/directives":{"post":{"summary":"Submit Directive","operationId":"submit_directive_journal_directives_post","parameters":[{"name":"X-Public-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Public-Key"}},{"name":"X-Nonce","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Nonce"}},{"name":"X-Timestamp","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Timestamp"}},{"name":"X-Signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Signature"}},{"name":"X-PAYMENT","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Payment"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DirectiveSubmitRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DirectiveWriteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"List Directives","operationId":"list_directives_journal_directives_get","parameters":[{"name":"account","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account"}},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Since"}},{"name":"until","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Until"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}},{"name":"X-Public-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Public-Key"}},{"name":"X-Nonce","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Nonce"}},{"name":"X-Timestamp","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Timestamp"}},{"name":"X-Signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Signature"}},{"name":"X-PAYMENT","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Payment"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DirectiveListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/journal/directives/validate":{"post":{"summary":"Validate Directive","description":"Free dry-run — no payment dependency at all. Still goes through\nrequire_auth (identity/replay protection is not a billing concern), but\nnever touches payments.py.\n\nUnlike every paid route (which now lets an anonymous request through\nto see the 402 challenge, for x402 discovery — see payment_required()'s\ndocstring), this route has no such path: it validates against a\nSPECIFIC user's ledger history, so there's no meaningful way to\n\"validate anonymously.\" An anonymous request here gets a real 401,\nexplicitly, rather than silently proceeding with no identity to\nvalidate against.\n\nConsumes the nonce immediately, explicitly, rather than deferring —\nunlike paid routes, this endpoint has no 402-then-retry concept at\nall, so there's no reason to delay (see auth.consume_nonce()'s\ndocstring for why paid routes defer this and why this one doesn't\nneed to).","operationId":"validate_directive_journal_directives_validate_post","parameters":[{"name":"X-Public-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Public-Key"}},{"name":"X-Nonce","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Nonce"}},{"name":"X-Timestamp","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Timestamp"}},{"name":"X-Signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Signature"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DirectiveValidateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DirectiveWriteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/journal/directives/batch":{"post":{"summary":"Submit Batch","operationId":"submit_batch_journal_directives_batch_post","parameters":[{"name":"X-Public-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Public-Key"}},{"name":"X-Nonce","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Nonce"}},{"name":"X-Timestamp","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Timestamp"}},{"name":"X-Signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Signature"}},{"name":"X-PAYMENT","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Payment"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DirectiveBatchRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DirectiveBatchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/accounts":{"get":{"summary":"List Accounts","operationId":"list_accounts_accounts_get","parameters":[{"name":"X-Public-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Public-Key"}},{"name":"X-Nonce","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Nonce"}},{"name":"X-Timestamp","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Timestamp"}},{"name":"X-Signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Signature"}},{"name":"X-PAYMENT","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Payment"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountsListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/accounts/balance":{"get":{"summary":"Get Account Balance","operationId":"get_account_balance_accounts_balance_get","parameters":[{"name":"account","in":"query","required":true,"schema":{"type":"string","title":"Account"}},{"name":"X-Public-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Public-Key"}},{"name":"X-Nonce","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Nonce"}},{"name":"X-Timestamp","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Timestamp"}},{"name":"X-Signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Signature"}},{"name":"X-PAYMENT","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Payment"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountBalanceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/export":{"get":{"summary":"Export Ledger","operationId":"export_ledger_export_get","parameters":[{"name":"X-Public-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Public-Key"}},{"name":"X-Nonce","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Nonce"}},{"name":"X-Timestamp","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Timestamp"}},{"name":"X-Signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Signature"}},{"name":"X-PAYMENT","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Payment"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/balance-sheet":{"get":{"summary":"Get Balance Sheet","description":"No query params — a balance sheet is a point-in-time snapshot of full\nhistory, not a period. reports.get_balance_sheet() may read from\nrealized_balances_cache (§5: \"often servable from cache\") or recompute\non a miss; either way this route settles at the same fixed price\nregardless of which path served the request — cache-hit vs. cache-miss\ncost difference is an internal optimization, not something exposed as a\nprice difference (same \"one fixed price per route\" rule as everywhere\nelse in payments.py).\n\nallow_free_read=True shares free_reports_remaining with the other\nthree report-tier endpoints (export, income-statement, trial-balance)\n— one combined pool of 2, not 2 each. See\nauth.FREE_ALLOWANCE_COLUMNS.","operationId":"get_balance_sheet_reports_balance_sheet_get","parameters":[{"name":"X-Public-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Public-Key"}},{"name":"X-Nonce","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Nonce"}},{"name":"X-Timestamp","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Timestamp"}},{"name":"X-Signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Signature"}},{"name":"X-PAYMENT","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Payment"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BalanceSheetResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/income-statement":{"get":{"summary":"Get Income Statement","description":"Both since/until omitted -> whole history (reports._clamp_to_period\nfills the gap from the actual entry date range, never an arbitrary\nsentinel — see reports.py). Structural validation of the range itself\n(until not before since) happens via schemas.ReportPeriodQuery before\nany work runs, same pattern as journal.py's list_directives route.","operationId":"get_income_statement_reports_income_statement_get","parameters":[{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Since"}},{"name":"until","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Until"}},{"name":"X-Public-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Public-Key"}},{"name":"X-Nonce","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Nonce"}},{"name":"X-Timestamp","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Timestamp"}},{"name":"X-Signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Signature"}},{"name":"X-PAYMENT","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Payment"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncomeStatementResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/trial-balance":{"get":{"summary":"Get Trial Balance","description":"Same cost shape and same clamp mechanism as income-statement — §6:\n\"both are Beancount's own report functions over the same\nbooked/realized entries.\" Kept as its own route (not a query-param\nvariant of income-statement) so it's individually priced, audited, and\nlisted as its own resource for x402 directory discovery, even though\nthe underlying compute path in reports.py is structurally identical.","operationId":"get_trial_balance_reports_trial_balance_get","parameters":[{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Since"}},{"name":"until","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Until"}},{"name":"X-Public-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Public-Key"}},{"name":"X-Nonce","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Nonce"}},{"name":"X-Timestamp","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Timestamp"}},{"name":"X-Signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Signature"}},{"name":"X-PAYMENT","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Payment"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrialBalanceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/":{"get":{"summary":"Home","operationId":"home__get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/terms":{"get":{"summary":"Terms","operationId":"terms_terms_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/privacy":{"get":{"summary":"Privacy","operationId":"privacy_privacy_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/llms.txt":{"get":{"summary":"Llms Txt","operationId":"llms_txt_llms_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/SKILL.md":{"get":{"summary":"Skill Md","operationId":"skill_md_SKILL_md_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/robots.txt":{"get":{"summary":"Robots Txt","operationId":"robots_txt_robots_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/.well-known/402index-verify.txt":{"get":{"summary":"Index402 Verify","description":"Domain-ownership proof for 402index.io's directory listing (see\nhttps://402index.io/verify) — must contain ONLY the verification hash\nthey issued, no extra whitespace or content. Read from disk rather\nthan inlined here so a future re-claim/rotation is a file swap, not a\ncode change, matching the security.txt/robots.txt pattern above.","operationId":"index402_verify__well_known_402index_verify_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/.well-known/security.txt":{"get":{"summary":"Security Txt","description":"RFC 9116 canonical location — the only one search/security tooling\nactually checks by spec. The bare /security.txt route below exists\nonly for older crawlers that predate the .well-known convention.","operationId":"security_txt__well_known_security_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/security.txt":{"get":{"summary":"Security Txt Bare","operationId":"security_txt_bare_security_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/health":{"get":{"summary":"Health","description":"§6: 'CapRover healthcheck target' — free, unauthenticated, no DB\naccess. Deliberately the only route in this service that doesn't touch\nauth.py, payments.py, or the database at all.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AccountBalanceDoc":{"properties":{"account":{"type":"string","title":"Account"},"balance":{"items":{"$ref":"#/components/schemas/InventoryPosition"},"type":"array","title":"Balance"}},"type":"object","required":["account","balance"],"title":"AccountBalanceDoc","description":"Doc shape for GET /accounts/balance — a single account's name plus\nits own balance list, not the full list (reports.get_account_balance)."},"AccountBalanceResponse":{"properties":{"accepted":{"type":"boolean","title":"Accepted"},"doc":{"anyOf":[{"$ref":"#/components/schemas/AccountBalanceDoc"},{"type":"null"}]},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"}},"type":"object","required":["accepted"],"title":"AccountBalanceResponse"},"AccountInfo":{"properties":{"name":{"type":"string","title":"Name"},"currencies":{"items":{"type":"string"},"type":"array","title":"Currencies"},"booking_method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Booking Method"}},"type":"object","required":["name"],"title":"AccountInfo","description":"GET /accounts — from cached `open` directives, no booking needed\nper §6. `booking_method` is None when the `open` directive didn't\nspecify one (Beancount defaults apply; we don't second-guess that\ndefault here)."},"AccountsListResponse":{"properties":{"accounts":{"items":{"$ref":"#/components/schemas/AccountInfo"},"type":"array","title":"Accounts"},"free_accounts_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Free Accounts Remaining"}},"type":"object","required":["accounts"],"title":"AccountsListResponse"},"BalanceSheetResponse":{"properties":{"accepted":{"type":"boolean","title":"Accepted"},"doc":{"anyOf":[{"items":{"$ref":"#/components/schemas/RealAccountEntry"},"type":"array"},{"type":"null"}],"title":"Doc"},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"},"free_reports_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Free Reports Remaining"}},"type":"object","required":["accepted"],"title":"BalanceSheetResponse","description":"Mirrors reports.ReportResult for GET /reports/balance-sheet.\naccepted=True with a non-empty errors list is a valid, billable\nresponse (§7) — e.g. missing price directives — not a failure."},"Cost":{"properties":{"number":{"type":"string","title":"Number"},"currency":{"type":"string","title":"Currency"},"date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"}},"type":"object","required":["number","currency"],"title":"Cost"},"DirectiveBatchRequest":{"properties":{"directives":{"items":{"type":"string"},"type":"array","maxItems":1000,"minItems":1,"title":"Directives"}},"type":"object","required":["directives"],"title":"DirectiveBatchRequest","description":"POST /journal/directives/batch body. Cap matches\nledger.MAX_BATCH_SIZE — enforced here too so an oversized batch is\nrejected before payment is even attempted (ARCHITECTURE.md §7:\nmalformed requests never reach the payment step)."},"DirectiveBatchResponse":{"properties":{"accepted":{"type":"boolean","title":"Accepted"},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"},"directive_ids":{"items":{"type":"integer"},"type":"array","title":"Directive Ids"}},"type":"object","required":["accepted"],"title":"DirectiveBatchResponse","description":"Mirrors ledger.BatchResult field-for-field."},"DirectiveListItem":{"properties":{"id":{"type":"integer","title":"Id"},"date":{"type":"string","title":"Date"},"text":{"type":"string","title":"Text"}},"type":"object","required":["id","date","text"],"title":"DirectiveListItem"},"DirectiveListResponse":{"properties":{"directives":{"items":{"$ref":"#/components/schemas/DirectiveListItem"},"type":"array","title":"Directives"},"free_directives_list_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Free Directives List Remaining"}},"type":"object","required":["directives"],"title":"DirectiveListResponse"},"DirectiveSubmitRequest":{"properties":{"text":{"type":"string","maxLength":10000,"minLength":1,"title":"Text"}},"type":"object","required":["text"],"title":"DirectiveSubmitRequest","description":"POST /journal/directives body. Exactly one directive's literal\nBeancount text — multiplicity and syntax validity are load_string()'s\njob (ledger.submit_directive), not this model's."},"DirectiveValidateRequest":{"properties":{"text":{"type":"string","maxLength":10000,"minLength":1,"title":"Text"}},"type":"object","required":["text"],"title":"DirectiveValidateRequest","description":"POST /journal/directives/validate body — identical shape to a real\nsubmission, since it's the same check minus persistence and payment."},"DirectiveWriteResponse":{"properties":{"accepted":{"type":"boolean","title":"Accepted"},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"},"directive_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Directive Id"},"date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date"},"free_writes_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Free Writes Remaining"}},"type":"object","required":["accepted"],"title":"DirectiveWriteResponse","description":"Mirrors ledger.SubmitResult field-for-field, plus one addition\nbelow that ISN'T part of that mirror."},"ExportDoc":{"properties":{"beancount_text":{"type":"string","title":"Beancount Text"}},"type":"object","required":["beancount_text"],"title":"ExportDoc"},"ExportResponse":{"properties":{"accepted":{"type":"boolean","title":"Accepted"},"doc":{"anyOf":[{"$ref":"#/components/schemas/ExportDoc"},{"type":"null"}]},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"},"free_reports_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Free Reports Remaining"}},"type":"object","required":["accepted"],"title":"ExportResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"IncomeStatementResponse":{"properties":{"accepted":{"type":"boolean","title":"Accepted"},"doc":{"anyOf":[{"items":{"$ref":"#/components/schemas/RealAccountEntry"},"type":"array"},{"type":"null"}],"title":"Doc"},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"},"free_reports_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Free Reports Remaining"}},"type":"object","required":["accepted"],"title":"IncomeStatementResponse"},"InventoryPosition":{"properties":{"number":{"type":"string","title":"Number"},"currency":{"type":"string","title":"Currency"},"cost":{"anyOf":[{"$ref":"#/components/schemas/Cost"},{"type":"null"}]}},"type":"object","required":["number","currency"],"title":"InventoryPosition"},"RealAccountEntry":{"properties":{"account":{"type":"string","title":"Account"},"parent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent"},"balance":{"items":{"$ref":"#/components/schemas/InventoryPosition"},"type":"array","title":"Balance"}},"type":"object","required":["account"],"title":"RealAccountEntry","description":"One entry in the flat adjacency list reports._serialize_real_account()\nnow emits — was a recursive nested tree (RealAccountNode, containing a\ndict of RealAccountNode) until a real, confirmed problem: that shape\nrequires a genuinely self-referential OpenAPI schema, which x402scan's\nown API scanner (reading /openapi.json as its primary source) choked\non with \"Maximum call stack size exceeded\" — confirmed directly, not\nguessed: a naive \"fully substitute every $ref\" resolver hits actual\nunbounded recursion against a self-referential schema, since there's\nno way to inline a genuine cycle into a finite structure.\n\n`parent` is the immediate parent's full account name (None for a\ntop-level account like \"Assets\" or \"Expenses\") — an explicit\nadjacency-list pointer, even though it's technically redundant with\n`account` itself (Beancount account names are colon-separated paths,\nso the parent is always \"drop the last segment\"). Included anyway so\na consumer doesn't have to parse that convention themselves just to\nreconstruct the tree.\n\n`number` fields inside `balance` stay strings end-to-end (see module\ndocstring) — never re-parsed into a JSON float anywhere on the\nresponse path."},"RegisterResponse":{"properties":{"public_key":{"type":"string","title":"Public Key"},"private_key":{"type":"string","title":"Private Key","description":"Shown once. Not recoverable — losing it means losing access."}},"type":"object","required":["public_key","private_key"],"title":"RegisterResponse","description":"No RegisterRequest — registration takes no body, it just needs the call\nto happen. Response hands back both halves of the freshly generated\nEd25519 keypair exactly once (auth.register_user never persists the\nprivate key), matching \"we don't use session tokens... when an agent\nregisters we give them a private key.\""},"TrialBalanceResponse":{"properties":{"accepted":{"type":"boolean","title":"Accepted"},"doc":{"anyOf":[{"items":{"$ref":"#/components/schemas/RealAccountEntry"},"type":"array"},{"type":"null"}],"title":"Doc"},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"},"free_reports_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Free Reports Remaining"}},"type":"object","required":["accepted"],"title":"TrialBalanceResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}