{"openapi":"3.1.0","servers":[{"url":"/api"}],"security":[{"CookieSession":[]},{"BearerSession":[]}],"info":{"title":"Ledger API","version":"0.1.0","description":"# Ledger API — General Instructions\n\n## Purpose\n\n### Current limited-launch scope\n\nThe owner-approved initial production scope is the thirteen operations described\nbelow: email authentication and structured accounts, periods, entries and enrichment.\nOriginal statement-file upload/download, complete provenance/history and full personal\nbespoke-ledger recovery are not implemented. Preserve originals outside this service\nuntil that recovery workflow exists. The agreed v1 workflow and final offload promise\nremain the roadmap; this limited launch does not establish full bespoke parity.\n\nPublic `GET /` distributes thirteen native WebMCP tools (nine domain actions plus four\nemail authentication operations) when supported and the same\nDOM-independent client as `window.LedgerApi`. Prefer registered WebMCP tools, then\n`window.LedgerApi`, then direct `/api` requests. No UI interaction, navigation or DOM\nupdate is needed for ledger operations. The page contains static usage documentation.\n`window.LedgerApi.describe()` returns contract-derived descriptions and standalone input schemas.\nMethods accept named object arguments (path fields and body fields together);\n`listAccounts()` takes no arguments. Read the contract at `/api/openapi.json`:\nOpenAPI server `/api` plus path `/accounts` means `/api/accounts`. All nine business\noperations require identity.\n\nEach tier works independently. Browser/native callers use `requestLoginCode({email})`,\nthen `exchangeLoginCode({challengeId, code})` with the six-digit code provided by the\nuser, and `getSession({})` to verify identity. Use `logout({})` when finished.\nThe browser wrapper forces cookie mode and never returns a session token; it rejects\nunexpected token-bearing responses. Cookies are host-only, HttpOnly, Secure,\nSameSite=Strict, Path=/ and expire after 24 hours. Browser login and cookie mutations\nrequire the exact configured Origin. No bearer-bootstrap tools or helpers exist.\nCodes expire after ten minutes, allow three failed attempts, and are single-use.\nRequests have a 60-second cooldown, five-attempt fixed UTC-aligned hourly quota and\nIP caps. `resendAfter` is seconds, not a promise that the hourly quota is available.\n\nDirect HTTP uses `/api/auth/request` then `/api/auth/exchange` with explicit\n`sessionMode: \"token\"`; it returns `accessToken` without setting a cookie. Supply\nthat session in each protected request's Authorization Bearer header. Browser mode\nis `sessionMode: \"browser\"` and returns only verified identity and expiry.\nRegistration is not authentication. Verification creates/resolves a stable UUID,\nnever claims legacy accounts automatically. If delivery returns 503, do not invent a\ncode or seek a public outbox. Both browser interfaces share same-origin cookies.\nThe client does not retain or log codes; a harness may still record transient tool\narguments. Keep codes and raw tokens out of logs and unnecessary model context.\nNative callbacks return the API's JSON success value or `{error: {status, code,\nmessage, issues?}}`; fallback methods reject with structured `LedgerError` on failure.\nCancellation does not guarantee write rollback. There are no automatic client retries;\ninspect persisted state after uncertain writes before retrying.\n\nThis API provides a **durable, structured ledger** for organizing, analyzing, and keeping track of financial transactions.\n\n**Storage and structure are the provided features. Preparation and analysis are built on top as part of your agentic workflow.** Your agent extracts statements, researches merchants, helps classify purchases, and produces useful summaries. The service preserves the resulting ledger independently of your laptop or conversation history.\n\nThe initial scope is monthly credit and cash ledgers. Every account requires an\nexplicit `kind: \"credit\" | \"cash\"`; there is no default.\n\nCreate/mutate/delete entry batches accept at most **97 submitted entries/IDs**.\nDuring an owner migration, valid ledger writes (including account creation) return\nHTTP **409 `MAINTENANCE`**. After test-to-production cutover, the migrated owner's\ntest writes remain permanently blocked; use production after coordinator confirmation.\nDo not blindly retry writes. Test authentication and empty account listings remain\navailable; the source identity is retained. Other test owners are unaffected.\n\n## How the ledger works\n\nAn **account** contains entries grouped into **blocks**. Blocks provide the context and rules for their entries.\n\nThe primary working block is a **billing period**:\n\n- Transactions accumulate over time.\n- A **draft period** is a working draft (`status: \"draft\"`). Its entries can be added, corrected, enriched, or removed.\n- As information settles, the agent reviews the draft and proposes completion.\n- The user confirms that decision.\n- A **completed period** records user-accepted financial activity (`status: \"completed\"`) and rejects ordinary financial edits. Completed does not mean reconciled.\n\nPeriods use keys such as `2026-10`. A period key identifies a billing cycle; it does not imply that the statement covers the first through the last day of that calendar month.\n\nBank documents may omit exact coverage dates, opening balances, or closing balances. **Preserve missing information as unknown.** Do not infer statement coverage from the earliest and latest transaction dates.\n\n## Recommended agent workflow\n\n### 1. Establish the working context\n\nList the user’s accounts and select the intended ledger. Retrieve its data or the relevant period before preparing changes.\n\nUse the existing entries, categories, subaccounts, and notes as context. Do not assume an empty local workspace means the remote ledger is empty.\n\n### 2. Extract and validate the source\n\nWhen the user supplies a statement or transaction export:\n\n- Identify the account and target period.\n- Determine whether the document describes provisional activity or an officially settled statement.\n- Extract the entries faithfully, preserving amounts, signs, dates, and available merchant information.\n- Normalize the bank's debit/credit convention to the account kind below; do not\n  blindly copy a bank sign whose meaning differs. Preserve bank statement text in\n  `description`; use `note` for research and explanations.\n- Perform the balance and consistency checks that the document supports.\n- Surface discrepancies and missing information rather than inventing balancing entries.\n\nDistinct purchases can share the same date, merchant, and amount. Preserve their occurrence counts; do not deduplicate on those fields alone.\n\n### 3. Compare with the existing draft\n\nIdentify:\n- Entries already represented.\n- Newly reported activity.\n- Corrections to existing information.\n- Entries that may no longer belong in the draft.\n\nPreserve existing entry IDs when updating the same activity. Absence from a new file is a reason to investigate, not automatic authorization to delete: the file may be incomplete or cover a different scope.\n\n### 4. Help the user enrich the entries\n\nProactively parse and classify high-confidence entries, and propose useful\nsubaccounts, categories, and notes for approval. Do not wait for the user to design\nevery classification before doing useful preparation. Present confident proposals\nfirst, then resolve uncertain entries with focused questions; do not auto-commit.\n\nUse prior classifications, merchant information, and research where helpful. **Distinguish confident identifications from tentative guesses.** Ask the user about their experience when the descriptor does not establish what was purchased or whom it was for.\n\nRetain useful explanations in entry notes so later analysis does not depend on remembering the conversation.\n\n### 5. Obtain confirmation and persist changes\n\nPresent the proposed changes clearly. Incorporate the user’s corrections and obtain confirmation before submitting financial mutations.\n\n- Create a draft period when it does not already exist.\n- Use `mutatePeriodEntries` to explicitly create or update entries in an existing draft period.\n- Use `updatePeriodMetadata` to record or correct known statement dates and balances in a draft. Omit fields to preserve them; use `null` to clear an optional value back to unknown.\n- Delete entries only through an explicit, reviewed decision.\n- Use mutation responses as the authoritative confirmed persisted state. Routine\n  readback is unnecessary; read again for uncertainty, stale context, or a checkpoint.\n- Use full-value updates in `mutatePeriodEntries` for approved enrichment of completed\n  entries, preserving amountMinor, effectiveDate and description exactly.\n\nCreating an existing period produces a conflict. Retrieve and compare it with the intended submission; do not automatically overwrite, merge, or reopen it.\n\n### 6. Propose completion when justified\n\nKeep the period in draft while its financial contents remain unsettled. Creation,\ndeletion and statement metadata updates require draft status. Completed entries\nstill allow subaccount, category and note updates; bank facts stay locked.\n\nWhen the available evidence supports completion—for example, after reconciling the draft against an official final bank statement—explain the result and propose completing the period. Provisional activity and final statements describe bank-source evidence, not period lifecycle statuses; even a final statement initially enters a draft period.\n\n**The user authorizes completion.** The API records that decision and restricts subsequent financial editing. Completion does not imply that the service independently extracted or verified the statement.\n\n## Subaccounts and categories\n\n### Subaccounts: who or what is the balance attributed to?\n\nSubaccounts separate activity by responsibility or purpose within one ledger.\n\nExamples:\n- Business activity versus personal activity.\n- College expenses.\n- Japan trip 2026.\n- Money lent to a friend and their repayments.\n- Funds routed through this account for another person or a specific purpose.\n\nTheir purpose is to follow these groups **as if they were separate accounts**, while preserving the actual bank-account total.\n\nA useful subaccount balance requires consistent attribution of the relevant charges, payments, and internal allocations. Recording a payment to the bank does not, by itself, establish that a friend or business reimbursed the user.\n\nPropose partitions that distinguish responsibility, purpose, routed funds, and\nloans when they answer useful questions. These are attribution labels, not setup\nactions or instructions. Obtain approval; otherwise preserve existing attribution\nor explicit null rather than inventing a classification.\n\n### Categories: what is this?\n\nCategories provide a useful level of analytical detail: food, transport, subscriptions, gifts, and so on.\n\nThe right granularity depends on the user:\n- Snacks may be separate from meals.\n- Coffee may be separate from food.\n- A particular merchant may deserve its own category.\n\n**`STARBUCKS` is not inherently worse than `COFFEE`, `TREAT`, or `FOOD`.** What matters is whether the classification produces useful information when aggregated.\n\nPrefer existing categories when they express the intended meaning. Propose new ones when the distinction is useful, not simply because a merchant is unfamiliar.\n\n## Entry and mutation conventions\n\n- Amounts are signed integer minor units in the account currency. For USD, `1234` means $12.34.\n- For `credit`, positive amounts increase debt and negative amounts reduce debt.\n- For `cash`, positive amounts represent money held/inflows and negative amounts\n  represent outflows. The service stores the submitted signed amounts without\n  conversion or additional arithmetic; the agent normalizes bank meaning accordingly.\n- Effective dates use `YYYY-MM-DD`. Creation and update timestamps are server-managed.\n- Every entry belongs to a block and its account; loose entries are not supported.\n- New entries receive server-generated UUIDs. Creation inputs omit IDs; retain the returned IDs for later updates.\n- `mutatePeriodEntries` accepts explicit `{ operation: \"create\", values }` or `{ operation: \"update\", id, values }` rows. Updates require an existing target-period entry ID; unknown or foreign IDs are rejected, never inserted.\n- Both operations require complete editable entry values, including explicit `null` for unassigned classification or notes. Period metadata is separate from entry mutations.\n- `updatePeriodMetadata` accepts only statement coverage dates and opening/closing balances, returning complete period metadata. It does not edit entries, change status, or reconcile balances.\n- **Omitting an entry from a mutation batch does not delete it.** Deletion is explicit.\n- `createDraftPeriod` and `mutatePeriodEntries` return entries in submission order, allowing each result to be matched to its input. Subsequent reads have no guaranteed ordering.\n- Period mutation batches succeed or fail together.\n- Completed periods accept only nonempty update batches changing subaccount,\n  category or note. Full values remain required; changed amountMinor, effectiveDate\n  or description rejects the entire batch. Creates, deletes, metadata updates and\n  empty mutation/deletion batches are forbidden on completed periods.\n- Do not use deletion to represent a bank-issued refund or reversal. Preserve the original movement and record the corresponding subsequent movement.\n\n## Analyze what the evidence supports\n\nDistinguish questions that require different calculations:\n\n- **Spending:** purchases net of relevant refunds, not payments or internal redistributions.\n- **Outstanding debt:** a supported balance anchor plus subsequent activity.\n- **Subaccount responsibility:** consistently attributed activity and allocations.\n- **Cash withdrawals:** money obtained, not necessarily money spent.\n- **Stored-value top-ups:** money loaded, not necessarily consumed.\n\n**A sum of available entries is not automatically a complete account balance.** Missing periods, unsettled drafts, or unknown opening allocations may limit what can be concluded.\n\nState the scope and qualifications of a result. Completing a period establishes acceptance of that period’s contents, not reconciliation or completeness of the entire account history.\n\n## Why use this service?\n\n- **Durable cloud storage:** progress survives the loss of a laptop or local workspace.\n- **A bounded registry:** ownership, grouping, and editing follow explicit rules instead of accumulating ad hoc infrastructure.\n- **Flexible interpretation:** agents and users remain free to choose classifications and analyses that suit their needs.\n- **Discoverable operation:** these instructions and the API contract explain how to maintain the ledger, so a new agent session can continue without reconstructing the project’s conventions.\n\n**Keep the agent focused on understanding the transactions. Let the ledger service preserve their structure and state.**"},"x-identity-architecture":"Email authentication uses opaque bearer sessions or host-only cookies; cookie mutations and browser exchange require the exact configured Origin. Request/exchange and discovery are public. Lambda source configures Resend delivery through a linked secret. Local development requires an explicit delivery key or returns 503. Delivery failures return sanitized 503 responses; test compositions inject mocks.","x-v1-launch-gate":"Before launch verify durable storage, recovery, authenticated ownership isolation and mutation guarantees. DynamoDB test deployment requires independent review and real AWS verification. Request idempotency remains deferred.","components":{"securitySchemes":{"CookieSession":{"type":"apiKey","in":"cookie","name":"__Host-ledger-session"},"BearerSession":{"type":"http","scheme":"bearer","bearerFormat":"opaque session"}},"schemas":{},"parameters":{}},"paths":{"/auth/request":{"post":{"operationId":"requestLoginCode","security":[],"description":"Request a six-digit email login code. Email is trimmed/lowercased; plus and dots are preserved. Code expires in ten minutes and allows three failed attempts. Resend cooldown is 60 seconds; five request attempts per fixed UTC-aligned hour and IP caps apply. resendAfter is seconds. Delivery-unavailable returns 503; no code or account existence is disclosed. Sender: Ledger <login@auth.mzmz.cl>.","requestBody":{"required":true,"content":{"application/json":{"example":{"email":"person@example.com"},"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":254,"format":"email"}},"required":["email"],"additionalProperties":false}}}},"responses":{"200":{"description":"Authentication result","content":{"application/json":{"example":{"challengeId":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","expiresAt":"2026-11-04T12:10:00.000Z","resendAfter":60},"schema":{"type":"object","properties":{"challengeId":{"type":"string","pattern":"^[a-f0-9]{64}$"},"expiresAt":{"type":"string","format":"date-time"},"resendAfter":{"type":"integer","minimum":0}},"required":["challengeId","expiresAt","resendAfter"],"additionalProperties":false}}}},"400":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"415":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited; Retry-After is seconds","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/auth/exchange":{"post":{"operationId":"exchangeLoginCode","security":[],"description":"Exchange a one-use code for a 24-hour session. Browser clients always force sessionMode browser: exact configured Origin is required, a host-only HttpOnly Secure SameSite=Strict Path=/ __Host-ledger-session cookie is set, and JSON contains no token. Direct HTTP may explicitly choose token mode, returning accessToken without a cookie. Never repeat an uncertain successful exchange automatically. Email verification resolves a stable user UUID; it never claims legacy accounts.","requestBody":{"required":true,"content":{"application/json":{"example":{"challengeId":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","code":"123456","sessionMode":"browser"},"schema":{"type":"object","properties":{"challengeId":{"type":"string","pattern":"^[a-f0-9]{64}$"},"code":{"type":"string","pattern":"^\\d{6}$"},"sessionMode":{"type":"string","enum":["browser","token"]}},"required":["challengeId","code","sessionMode"],"additionalProperties":false}}}},"responses":{"200":{"description":"Authentication result","content":{"application/json":{"example":{"authenticated":true,"userId":"56baf155-e7ec-4f02-a337-bd1317f02c72","expiresAt":"2026-11-05T12:00:00.000Z"},"schema":{"anyOf":[{"type":"object","properties":{"authenticated":{"type":"boolean","enum":[true]},"userId":{"type":"string","format":"uuid"},"expiresAt":{"type":"string","format":"date-time"}},"required":["authenticated","userId","expiresAt"],"additionalProperties":false},{"type":"object","properties":{"authenticated":{"type":"boolean","enum":[true]},"userId":{"type":"string","format":"uuid"},"expiresAt":{"type":"string","format":"date-time"},"accessToken":{"type":"string","pattern":"^[A-Za-z0-9_-]{43}$"}},"required":["authenticated","userId","expiresAt","accessToken"],"additionalProperties":false}]}}}},"400":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"415":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited; Retry-After is seconds","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/auth/session":{"get":{"operationId":"getSession","security":[{"CookieSession":[]},{"BearerSession":[]}],"description":"Return verified session identity and expiry without a token. Uses same-origin cookies in the browser or an explicit bearer session for direct HTTP. Missing, expired or revoked sessions return 401.","responses":{"200":{"description":"Authentication result","content":{"application/json":{"example":{"authenticated":true,"userId":"56baf155-e7ec-4f02-a337-bd1317f02c72","expiresAt":"2026-11-05T12:00:00.000Z"},"schema":{"type":"object","properties":{"authenticated":{"type":"boolean","enum":[true]},"userId":{"type":"string","format":"uuid"},"expiresAt":{"type":"string","format":"date-time"}},"required":["authenticated","userId","expiresAt"],"additionalProperties":false}}}},"400":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"415":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited; Retry-After is seconds","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/auth/logout":{"post":{"operationId":"logout","security":[{"CookieSession":[]},{"BearerSession":[]}],"description":"Revoke the current session. Cookie authentication requires the exact configured Origin and clears the host-only session cookie. Explicit bearer authentication revokes that token without setting cookies. No request body is needed.","responses":{"200":{"description":"Authentication result","content":{"application/json":{"example":{"loggedOut":true},"schema":{"type":"object","properties":{"loggedOut":{"type":"boolean","enum":[true]}},"required":["loggedOut"],"additionalProperties":false}}}},"400":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"415":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited; Retry-After is seconds","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Authentication request rejected or unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/accounts":{"post":{"operationId":"createAccount","description":"Create a credit or cash ledger owned by the current user. Required `kind` is\n`credit` or `cash`, with no default. Credit positive amounts increase debt and\nnegative amounts reduce it; cash positive amounts represent money held/inflows and\nnegative amounts outflows. Normalize bank meaning before submission; the service\ndoes no sign conversion or additional arithmetic.\n\nUse a short, concise name that distinguishes the ledger, such as “Personal USD\ncredit card”. An optional description can record contextual notes, special\ninstructions, or other information that does not belong in the name. Description\ntext is user-provided context, not executable configuration or authorization.\n\nAn account tracks financial activity in one currency. Use separate accounts for\nindependently tracked bank/card ledgers or currency balances. Use subaccounts to\npartition responsibility or purpose within the same ledger.\n\nList existing accounts before creating one to avoid unintentionally duplicating a\nledger. Account names are labels, not unique identifiers.\n\nThe service generates a stable account ID from a slug of the name plus a unique\ntiebreaker, for example `personal-usd-credi-ffeff339`. Treat the returned ID as opaque;\ndo not reconstruct it from the name. The service also assigns ownership and creation\ntime. Cadence defaults to `monthly`.\n\nReturns the complete persisted account. Creation does not add periods or entries.\nDescription may be omitted. Exact slug formatting and collision handling remain\nimplementation details; generated IDs must not overwrite another account.\n\n### Request example\n\n```json\n{\n  \"name\": \"Personal USD credit card\",\n  \"kind\": \"credit\",\n  \"description\": \"Personal expenses and purchases made on behalf of friends.\",\n  \"currency\": \"USD\",\n  \"cadence\": \"monthly\"\n}\n```\n\n### Response example — 201 Created\n\n```json\n{\n  \"id\": \"personal-usd-credi-ffeff339\",\n  \"userId\": \"user_123\",\n  \"name\": \"Personal USD credit card\",\n  \"kind\": \"credit\",\n  \"description\": \"Personal expenses and purchases made on behalf of friends.\",\n  \"currency\": \"USD\",\n  \"cadence\": \"monthly\",\n  \"createdAt\": \"2026-11-01T12:00:00.000Z\"\n}\n```","requestBody":{"required":true,"content":{"application/json":{"example":{"name":"Personal USD credit card","kind":"credit","currency":"USD"},"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"kind":{"type":"string","enum":["credit","cash"]},"description":{"type":"string"},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"cadence":{"type":"string","enum":["monthly"],"default":"monthly"}},"required":["name","kind","currency"],"additionalProperties":false}}}},"responses":{"201":{"description":"Confirmed persisted result","content":{"application/json":{"example":{"id":"personal-usd-credi-ffeff339","userId":"user_123","name":"Personal USD credit card","kind":"credit","currency":"USD","cadence":"monthly","createdAt":"2026-11-01T12:00:00.000Z"},"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1},"userId":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"kind":{"type":"string","enum":["credit","cash"]},"description":{"type":"string"},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"cadence":{"type":"string","enum":["monthly"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","userId","name","kind","currency","cadence","createdAt"],"additionalProperties":false}}}},"400":{"description":"Invalid input or malformed supported JSON","content":{"application/json":{"example":{"error":{"code":"VALIDATION","message":"entries.0.values.amountMinor: Invalid input: expected number, received string","issues":[{"path":["entries",0,"values","amountMinor"],"message":"Invalid input: expected number, received string","code":"invalid_type"}]}},"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Authenticated identity required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cookie mutation requires the exact configured Origin","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Conflict or immutable completed period","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"415":{"description":"Missing or unsupported JSON Content-Type","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"500":{"description":"Unexpected internal failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Authentication temporarily unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"get":{"operationId":"listAccounts","description":"List all accounts owned by the current user.\n\nUse this operation at the beginning of a session to identify the intended ledger\nand recover its server-generated ID. Each account includes its full metadata,\nincluding its name, required credit/cash kind, currency, cadence, and optional description.\n\nRead the account description for relevant context and user preferences. If multiple\naccounts could fit the task, ask the user which one to use rather than guessing.\n\nReturns an empty list when the user has no accounts. No ordering is guaranteed.\n\nThis operation does not include blocks, entries, or calculated balances. Use\n`getAccountLedger` to retrieve the selected account’s financial data.\n\nNo request body or user-ID parameter. Ownership comes from the authenticated identity.\n\n### Response example — 200 OK\n\n```json\n[\n  {\n    \"id\": \"personal-usd-credi-ffeff339\",\n    \"userId\": \"user_123\",\n    \"name\": \"Personal USD credit card\",\n    \"kind\": \"credit\",\n    \"description\": \"Personal purchases, including occasional expenses for friends.\",\n    \"currency\": \"USD\",\n    \"cadence\": \"monthly\",\n    \"createdAt\": \"2026-11-01T12:00:00.000Z\"\n  }\n]\n```","responses":{"200":{"description":"Confirmed persisted result","content":{"application/json":{"example":[{"id":"personal-usd-credi-ffeff339","userId":"user_123","name":"Personal USD credit card","kind":"credit","currency":"USD","cadence":"monthly","createdAt":"2026-11-01T12:00:00.000Z"}],"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"userId":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"kind":{"type":"string","enum":["credit","cash"]},"description":{"type":"string"},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"cadence":{"type":"string","enum":["monthly"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","userId","name","kind","currency","cadence","createdAt"],"additionalProperties":false}}}}},"401":{"description":"Authenticated identity required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cookie mutation requires the exact configured Origin","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"500":{"description":"Unexpected internal failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Authentication temporarily unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/accounts/{account}":{"get":{"operationId":"getAccountLedger","description":"Retrieve an owned account together with all its blocks and entries.\nThe account includes its required credit/cash kind; interpret signs accordingly.\nUse confirmed mutation responses directly; read again when context is stale,\nuncertain, or an account-wide checkpoint is useful.\n\nEntries are returned as flat analytical rows, enriched with their block type and,\nfor period entries, the period key and current draft/completed status. These fields\nare derived from the owning block.\n\nThe `blocks` collection provides complete group metadata, including empty blocks\nand any recorded statement balances or coverage dates. Every returned entry\nreferences a returned block, and all entries belonging to each account block are\nincluded.\n\nBlock metadata and derived entry fields reflect the same consistent read. No\nordering is guaranteed; sort locally as needed.\n\nThis operation returns recorded data, not calculated balances or a guarantee of\nhistorical completeness. Assess coverage and balance evidence before presenting\nresults as complete spending or current debt.\n\nUse `getPeriod` when only one billing period is needed.\n\n### Response shape and projection\n\n```ts\n{\n  account: Account,\n  blocks: Block[],\n  entries: EnrichedEntry[]\n}\n```\n\nPeriod entries include derived `blockType: \"period\"`, `periodKey`, and\n`periodStatus: \"draft\" | \"completed\"`. Rebalance entries include\n`blockType: \"rebalance\"` without period fields. These are response-only fields,\nnot stored entry attributes or accepted mutation inputs. The derived `periodKey`\nis the owning period block's ID.\n\nAn existing account with no activity returns empty block and entry arrays. An\nunknown or unowned account returns 404.","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"account","in":"path"}],"responses":{"200":{"description":"Confirmed persisted result","content":{"application/json":{"example":{"account":{"id":"personal-usd-credi-ffeff339","userId":"user_123","name":"Personal USD credit card","kind":"credit","currency":"USD","cadence":"monthly","createdAt":"2026-11-01T12:00:00.000Z"},"blocks":[{"id":"2026-10","accountId":"personal-usd-credi-ffeff339","type":"period","status":"draft","createdAt":"2026-11-01T12:00:00.000Z","updatedAt":"2026-11-01T12:00:00.000Z"}],"entries":[{"amountMinor":1250,"effectiveDate":"2026-10-12","description":"Coffee shop","subaccount":"P_KOREA_2026","category":"CAFÉ","note":null,"id":"8e4e163d-f604-42ad-a07a-f84f68449ebe","accountId":"personal-usd-credi-ffeff339","blockId":"2026-10","createdAt":"2026-11-01T12:00:00.000Z","updatedAt":"2026-11-01T12:00:00.000Z","blockType":"period","periodKey":"2026-10","periodStatus":"draft"}]},"schema":{"type":"object","properties":{"account":{"type":"object","properties":{"id":{"type":"string","minLength":1},"userId":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"kind":{"type":"string","enum":["credit","cash"]},"description":{"type":"string"},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"cadence":{"type":"string","enum":["monthly"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","userId","name","kind","currency","cadence","createdAt"],"additionalProperties":false},"blocks":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","pattern":"^(?!0000)\\d{4}-(0[1-9]|1[0-2])$"},"accountId":{"type":"string","minLength":1},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"type":{"type":"string","enum":["period"]},"status":{"type":"string","enum":["draft","completed"]},"startsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"endsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"openingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"closingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","accountId","createdAt","updatedAt","type","status"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"type":{"type":"string","enum":["rebalance"]},"note":{"type":"string"}},"required":["id","accountId","createdAt","updatedAt","type"],"additionalProperties":false}]}},"entries":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"blockId":{"type":"string","minLength":1},"amountMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"effectiveDate":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"description":{"type":"string"},"subaccount":{"type":["string","null"]},"category":{"type":["string","null"]},"note":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"blockType":{"type":"string","enum":["period"]},"periodKey":{"type":"string","pattern":"^(?!0000)\\d{4}-(0[1-9]|1[0-2])$"},"periodStatus":{"type":"string","enum":["draft","completed"]}},"required":["id","accountId","blockId","amountMinor","effectiveDate","description","subaccount","category","note","createdAt","updatedAt","blockType","periodKey","periodStatus"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"blockId":{"type":"string","minLength":1},"amountMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"effectiveDate":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"description":{"type":"string"},"subaccount":{"type":["string","null"]},"category":{"type":["string","null"]},"note":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"blockType":{"type":"string","enum":["rebalance"]}},"required":["id","accountId","blockId","amountMinor","effectiveDate","description","subaccount","category","note","createdAt","updatedAt","blockType"],"additionalProperties":false}]}}},"required":["account","blocks","entries"],"additionalProperties":false}}}},"400":{"description":"Invalid input or malformed supported JSON","content":{"application/json":{"example":{"error":{"code":"VALIDATION","message":"entries.0.values.amountMinor: Invalid input: expected number, received string","issues":[{"path":["entries",0,"values","amountMinor"],"message":"Invalid input: expected number, received string","code":"invalid_type"}]}},"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Authenticated identity required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cookie mutation requires the exact configured Origin","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Target missing or not owned by the current user","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"500":{"description":"Unexpected internal failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Authentication temporarily unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/accounts/{account}/periods/{periodKey}":{"post":{"operationId":"createDraftPeriod","description":"Create a draft billing period with its initial entries.\n\nUse this operation when introducing a period that is not already present in the\naccount. Supply its monthly key, such as `2026-10`, and the complete initial entry\ncollection. The collection may be empty.\n\nSupply each entry’s complete editable values without an ID. The service generates\nentry UUIDs, assigns ownership and block membership, and creates timestamps. The\nperiod block’s ID is its period key; uniqueness is scoped by account. There is no\nseparate generated period ID or duplicated stored key.\nNormalize signs to the account kind and keep bank statement text in description.\nProactively prepare confident classifications and useful subaccounts for approval,\nthen resolve uncertainties. Use note for explanatory enrichment.\n\nOptionally supply statement coverage dates and opening/closing balances when\nknown. Missing metadata does not prevent creation. Do not infer coverage from\ntransaction dates or invent balancing values.\n\nCreation is atomic: the period and all submitted entries are created together,\nor nothing changes.\n\nIf the period already exists—draft or completed—the operation fails with a conflict.\nRetrieve it with `getPeriod` and compare its contents with the intended submission\nbefore proposing further changes. This operation never merges, replaces, or\nreopens an existing period.\n\nReturns the created period metadata and its confirmed persisted entries, including\ntheir generated IDs, in the same order as the submitted entries. Match results to\ninputs by position and preserve those IDs for subsequent updates. This response\nordering does not guarantee ordering on later reads.\n\nA period always starts draft, even when its entries were extracted from an official\nstatement. Completion is a separate, user-confirmed action.\n\n### Request example\n\n```json\n{\n  \"entries\": [\n    {\n      \"amountMinor\": 1250,\n      \"effectiveDate\": \"2026-10-12\",\n      \"description\": \"Coffee shop\",\n      \"subaccount\": \"P_KOREA_2026\",\n      \"category\": \"CAFÉ\",\n      \"note\": null\n    }\n  ],\n  \"metadata\": {\n    \"startsOn\": \"2026-09-23\"\n  }\n}\n```\n\n### Response shape — 201 Created\n\n```ts\n{\n  period: PeriodBlock, // id: periodKey, status: \"draft\"\n  entries: Entry[]    // includes server-generated entry IDs\n}\n```","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"account","in":"path"},{"schema":{"type":"string","pattern":"^(?!0000)\\d{4}-(0[1-9]|1[0-2])$"},"required":true,"name":"periodKey","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"entries":[{"amountMinor":1250,"effectiveDate":"2026-10-12","description":"Coffee shop","subaccount":"P_KOREA_2026","category":"CAFÉ","note":null}],"metadata":{"startsOn":"2026-09-23"}},"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"amountMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"effectiveDate":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"description":{"type":"string"},"subaccount":{"type":["string","null"]},"category":{"type":["string","null"]},"note":{"type":["string","null"]}},"required":["amountMinor","effectiveDate","description","subaccount","category","note"],"additionalProperties":false},"maxItems":97},"metadata":{"type":"object","properties":{"startsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"endsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"openingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"closingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"additionalProperties":false}},"required":["entries"],"additionalProperties":false}}}},"responses":{"201":{"description":"Confirmed persisted result","content":{"application/json":{"example":{"period":{"id":"2026-10","accountId":"personal-usd-credi-ffeff339","type":"period","status":"draft","createdAt":"2026-11-01T12:00:00.000Z","updatedAt":"2026-11-01T12:00:00.000Z"},"entries":[{"amountMinor":1250,"effectiveDate":"2026-10-12","description":"Coffee shop","subaccount":"P_KOREA_2026","category":"CAFÉ","note":null,"id":"8e4e163d-f604-42ad-a07a-f84f68449ebe","accountId":"personal-usd-credi-ffeff339","blockId":"2026-10","createdAt":"2026-11-01T12:00:00.000Z","updatedAt":"2026-11-01T12:00:00.000Z"}]},"schema":{"type":"object","properties":{"period":{"type":"object","properties":{"id":{"type":"string","pattern":"^(?!0000)\\d{4}-(0[1-9]|1[0-2])$"},"accountId":{"type":"string","minLength":1},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"type":{"type":"string","enum":["period"]},"status":{"type":"string","enum":["draft","completed"]},"startsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"endsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"openingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"closingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","accountId","createdAt","updatedAt","type","status"],"additionalProperties":false},"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"blockId":{"type":"string","minLength":1},"amountMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"effectiveDate":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"description":{"type":"string"},"subaccount":{"type":["string","null"]},"category":{"type":["string","null"]},"note":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","accountId","blockId","amountMinor","effectiveDate","description","subaccount","category","note","createdAt","updatedAt"],"additionalProperties":false}}},"required":["period","entries"],"additionalProperties":false}}}},"400":{"description":"Invalid input or malformed supported JSON","content":{"application/json":{"example":{"error":{"code":"VALIDATION","message":"entries.0.values.amountMinor: Invalid input: expected number, received string","issues":[{"path":["entries",0,"values","amountMinor"],"message":"Invalid input: expected number, received string","code":"invalid_type"}]}},"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Authenticated identity required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cookie mutation requires the exact configured Origin","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Target missing or not owned by the current user","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Conflict or immutable completed period","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"415":{"description":"Missing or unsupported JSON Content-Type","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"500":{"description":"Unexpected internal failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Authentication temporarily unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"get":{"operationId":"getPeriod","description":"Retrieve a billing period and all its entries from an owned account.\n\nUse this operation to inspect the current draft, compare it with a new statement,\nor recover entry IDs before preparing updates or deletions.\n\nThe period key identifies the period within the account—for example, `2026-10`.\nThe response includes its draft/completed status, available statement metadata, and\nits complete entry collection.\n\nAn existing empty period returns an empty entry list. A missing period does not\nget created automatically.\n\nEntries have no guaranteed ordering; sort locally as needed. Period metadata and\nentries reflect the same consistent read.\n\nDraft periods accept entry mutations and metadata updates. Completed periods allow\nonly subaccount/category/note updates through full-value mutation rows; bank facts\nand statement metadata stay locked. Routine readback after confirmed mutations is\nunnecessary unless uncertainty, staleness or a checkpoint calls for it. The response\ndoes not itself establish reconciliation or complete historical coverage.\n\n### Response shape — 200 OK\n\n```ts\n{\n  period: PeriodBlock,\n  entries: Entry[]\n}\n```\n\nAn unknown account, an unowned account, or a missing period returns 404. Entries\nare plain stored-entry representations; their shared context is in `period`.\nAccount-wide ledger responses include the row enrichment described in `getAccountLedger`.","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"account","in":"path"},{"schema":{"type":"string","pattern":"^(?!0000)\\d{4}-(0[1-9]|1[0-2])$"},"required":true,"name":"periodKey","in":"path"}],"responses":{"200":{"description":"Confirmed persisted result","content":{"application/json":{"example":{"period":{"id":"2026-10","accountId":"personal-usd-credi-ffeff339","type":"period","status":"draft","createdAt":"2026-11-01T12:00:00.000Z","updatedAt":"2026-11-01T12:00:00.000Z"},"entries":[{"amountMinor":1250,"effectiveDate":"2026-10-12","description":"Coffee shop","subaccount":"P_KOREA_2026","category":"CAFÉ","note":null,"id":"8e4e163d-f604-42ad-a07a-f84f68449ebe","accountId":"personal-usd-credi-ffeff339","blockId":"2026-10","createdAt":"2026-11-01T12:00:00.000Z","updatedAt":"2026-11-01T12:00:00.000Z"}]},"schema":{"type":"object","properties":{"period":{"type":"object","properties":{"id":{"type":"string","pattern":"^(?!0000)\\d{4}-(0[1-9]|1[0-2])$"},"accountId":{"type":"string","minLength":1},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"type":{"type":"string","enum":["period"]},"status":{"type":"string","enum":["draft","completed"]},"startsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"endsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"openingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"closingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","accountId","createdAt","updatedAt","type","status"],"additionalProperties":false},"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"blockId":{"type":"string","minLength":1},"amountMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"effectiveDate":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"description":{"type":"string"},"subaccount":{"type":["string","null"]},"category":{"type":["string","null"]},"note":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","accountId","blockId","amountMinor","effectiveDate","description","subaccount","category","note","createdAt","updatedAt"],"additionalProperties":false}}},"required":["period","entries"],"additionalProperties":false}}}},"400":{"description":"Invalid input or malformed supported JSON","content":{"application/json":{"example":{"error":{"code":"VALIDATION","message":"entries.0.values.amountMinor: Invalid input: expected number, received string","issues":[{"path":["entries",0,"values","amountMinor"],"message":"Invalid input: expected number, received string","code":"invalid_type"}]}},"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Authenticated identity required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cookie mutation requires the exact configured Origin","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Target missing or not owned by the current user","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"500":{"description":"Unexpected internal failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Authentication temporarily unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"patch":{"operationId":"updatePeriodMetadata","description":"Update known statement metadata on an existing draft billing period. Use this\noperation when evidence provides previously missing dates or balances, or when the\nuser approves correcting the recorded statement metadata. Review the source and\nobtain confirmation before changing financial facts.\n\nThe request is a partial object containing only these optional fields:\n\n- `startsOn`: real calendar date (`YYYY-MM-DD`) or `null`.\n- `endsOn`: real calendar date (`YYYY-MM-DD`) or `null`.\n- `openingBalanceMinor`: signed safe-integer minor units or `null`.\n- `closingBalanceMinor`: signed safe-integer minor units or `null`.\n\nOmitting a field preserves its stored value. Explicit `null` clears it: the optional\nattribute is absent from the resulting entity/JSON, rather than stored as null.\nZero is a known balance, distinct from missing information. Do not infer coverage\nfrom transaction dates or invent balances. No reconciliation, range continuity or\nindependent evidence verification is performed.\n\nIdentity, account membership, type, status, creation/update timestamps and entries\ncannot be supplied. This operation edits no entries and never changes their\ntimestamps. It cannot complete or reopen a period. Use `mutatePeriodEntries` for\nentry changes and `completePeriod` for user-confirmed acceptance.\n\nThe update is atomic, including validation and server timestamp generation. A\nfailure leaves metadata and entries unchanged. Success advances the period's\nserver-managed `updatedAt` and returns **complete persisted PeriodBlock metadata**,\nincluding unchanged fields, identity, status and timestamps. An empty object is\nvalid, preserves all statement fields and advances `updatedAt`.\nUse this confirmed result directly; readback is normally unnecessary. Balances use\nthe account kind's sign convention; the service does not convert them.\n\n### Request example\n\n```json\n{\n  \"endsOn\": \"2026-10-22\",\n  \"openingBalanceMinor\": 0,\n  \"closingBalanceMinor\": null\n}\n```\n\nThis preserves `startsOn`, records the closing coverage date and zero opening\nbalance, and removes any recorded closing balance.\n\n### Response shape — 200 OK\n\n```ts\nPeriodBlock // complete metadata, status: \"draft\"; cleared attributes omitted\n```\n\nAn unknown/unowned account or missing period returns 404. Completed periods reject\nall metadata updates with 409, including empty patches. Invalid/unknown fields\nreturn 400. A supported JSON Content-Type is required; missing/unsupported media\nreturns 415. No period is created implicitly and no entry collection is returned.","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"account","in":"path"},{"schema":{"type":"string","pattern":"^(?!0000)\\d{4}-(0[1-9]|1[0-2])$"},"required":true,"name":"periodKey","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"endsOn":"2026-10-22","openingBalanceMinor":0,"closingBalanceMinor":null},"schema":{"type":"object","properties":{"startsOn":{"type":["string","null"],"format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"endsOn":{"type":["string","null"],"format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"openingBalanceMinor":{"type":["integer","null"],"minimum":-9007199254740991,"maximum":9007199254740991},"closingBalanceMinor":{"type":["integer","null"],"minimum":-9007199254740991,"maximum":9007199254740991}},"additionalProperties":false}}}},"responses":{"200":{"description":"Confirmed persisted result","content":{"application/json":{"example":{"id":"2026-10","accountId":"personal-usd-credi-ffeff339","type":"period","status":"draft","createdAt":"2026-11-01T12:00:00.000Z","updatedAt":"2026-11-01T12:00:00.000Z","endsOn":"2026-10-22","openingBalanceMinor":0},"schema":{"type":"object","properties":{"id":{"type":"string","pattern":"^(?!0000)\\d{4}-(0[1-9]|1[0-2])$"},"accountId":{"type":"string","minLength":1},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"type":{"type":"string","enum":["period"]},"status":{"type":"string","enum":["draft","completed"]},"startsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"endsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"openingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"closingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","accountId","createdAt","updatedAt","type","status"],"additionalProperties":false}}}},"400":{"description":"Invalid input or malformed supported JSON","content":{"application/json":{"example":{"error":{"code":"VALIDATION","message":"entries.0.values.amountMinor: Invalid input: expected number, received string","issues":[{"path":["entries",0,"values","amountMinor"],"message":"Invalid input: expected number, received string","code":"invalid_type"}]}},"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Authenticated identity required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cookie mutation requires the exact configured Origin","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Target missing or not owned by the current user","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Conflict or immutable completed period","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"415":{"description":"Missing or unsupported JSON Content-Type","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"500":{"description":"Unexpected internal failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Authentication temporarily unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/accounts/{account}/periods/{periodKey}/entries":{"post":{"operationId":"mutatePeriodEntries","description":"Create or update a batch of entries within an existing draft period, or enrich\nexisting completed-period entries. Each row\nexplicitly declares `operation: \"create\"` or `operation: \"update\"`.\n\nFor creation, supply complete editable values without an entry ID. The service\ngenerates a UUID. For updating, supply an existing entry ID and complete editable\nvalues. The ID must identify an entry in the targeted period; unknown or foreign\nIDs are rejected. An update without an ID is invalid and never becomes a creation.\n\nThis operation is not a partial-field patch. Include all editable values, using\nexplicit `null` for an unassigned subaccount, category, or note. Ownership, block\nmembership, and timestamps are managed by the service. This operation changes entry\nvalues, not statement metadata; existing coverage dates and balances are preserved.\n\nOmitted entries remain unchanged. Use `deletePeriodEntries` for explicit removal.\nDuplicate update IDs within the batch are rejected. Distinct create operations\nwith identical purchase details remain distinct entries.\n\nThe entire batch succeeds or fails together. A missing period is not created\nautomatically. Completed periods accept only nonempty update-only batches changing\nsubaccount, category and note. All editable values are still required. Normalized\namountMinor, effectiveDate and description must equal stored bank facts, checked\nafter update ownership checks. Any mismatch or create row rejects the whole batch.\nEmpty completed-period batches are rejected. Successful enrichment advances entry\nand period updatedAt, preserves createdAt and keeps status completed. Use note,\nnot description, for explanations; there is no separate enrichment endpoint.\n\nReturns current period metadata and the confirmed persisted entries affected by\nthis batch, including generated IDs, in the same order as the submitted operations.\nEach result corresponds to the input at that position, including mixed create/update\nbatches. Unaffected entries are not included. Later reads have no guaranteed ordering.\nThese confirmed values are authoritative; routine readback is unnecessary.\n\nAfter an uncertain network result, inspect the period before resubmitting create\noperations: repeating them may create duplicates. Request-level idempotency is a\nseparate capability; this operation provides no retry guarantee.\n\n### Request shape\n\n```ts\ntype EntryMutation =\n  | { operation: \"create\"; values: PeriodEntryInput }\n  | { operation: \"update\"; id: string; values: PeriodEntryInput }\n\ntype MutatePeriodEntriesInput = { entries: EntryMutation[] }\n```\n\nBoth value schemas derive from the foundational Entry schema and contain complete\neditable fields, without identity, ownership, block membership, or timestamps.\nCreate rows cannot supply an entry ID; update rows require one.\n\n### Response shape — 200 OK\n\n```ts\n{\n  period: PeriodBlock,\n  entries: Entry[] // affected entries only, in submission order\n}\n```","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"account","in":"path"},{"schema":{"type":"string","pattern":"^(?!0000)\\d{4}-(0[1-9]|1[0-2])$"},"required":true,"name":"periodKey","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"entries":[{"operation":"create","values":{"amountMinor":1250,"effectiveDate":"2026-10-12","description":"Coffee shop","subaccount":"P_KOREA_2026","category":"CAFÉ","note":null}},{"operation":"update","id":"8e4e163d-f604-42ad-a07a-f84f68449ebe","values":{"amountMinor":1250,"effectiveDate":"2026-10-12","description":"Coffee shop","subaccount":"P_KOREA_2026","category":"CAFÉ","note":null}}]},"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"operation":{"type":"string","enum":["create"]},"values":{"type":"object","properties":{"amountMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"effectiveDate":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"description":{"type":"string"},"subaccount":{"type":["string","null"]},"category":{"type":["string","null"]},"note":{"type":["string","null"]}},"required":["amountMinor","effectiveDate","description","subaccount","category","note"],"additionalProperties":false}},"required":["operation","values"],"additionalProperties":false},{"type":"object","properties":{"operation":{"type":"string","enum":["update"]},"id":{"type":"string","minLength":1},"values":{"type":"object","properties":{"amountMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"effectiveDate":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"description":{"type":"string"},"subaccount":{"type":["string","null"]},"category":{"type":["string","null"]},"note":{"type":["string","null"]}},"required":["amountMinor","effectiveDate","description","subaccount","category","note"],"additionalProperties":false}},"required":["operation","id","values"],"additionalProperties":false}]},"maxItems":97}},"required":["entries"],"additionalProperties":false}}}},"responses":{"200":{"description":"Confirmed persisted result","content":{"application/json":{"example":{"period":{"id":"2026-10","accountId":"personal-usd-credi-ffeff339","type":"period","status":"draft","createdAt":"2026-11-01T12:00:00.000Z","updatedAt":"2026-11-01T12:00:00.000Z"},"entries":[{"amountMinor":1250,"effectiveDate":"2026-10-12","description":"Coffee shop","subaccount":"P_KOREA_2026","category":"CAFÉ","note":null,"id":"4154f836-8786-446f-92c7-2a0f794d4442","accountId":"personal-usd-credi-ffeff339","blockId":"2026-10","createdAt":"2026-11-01T12:00:00.000Z","updatedAt":"2026-11-01T12:00:00.000Z"},{"amountMinor":1250,"effectiveDate":"2026-10-12","description":"Coffee shop","subaccount":"P_KOREA_2026","category":"CAFÉ","note":null,"id":"8e4e163d-f604-42ad-a07a-f84f68449ebe","accountId":"personal-usd-credi-ffeff339","blockId":"2026-10","createdAt":"2026-11-01T12:00:00.000Z","updatedAt":"2026-11-01T12:00:00.000Z"}]},"schema":{"type":"object","properties":{"period":{"type":"object","properties":{"id":{"type":"string","pattern":"^(?!0000)\\d{4}-(0[1-9]|1[0-2])$"},"accountId":{"type":"string","minLength":1},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"type":{"type":"string","enum":["period"]},"status":{"type":"string","enum":["draft","completed"]},"startsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"endsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"openingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"closingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","accountId","createdAt","updatedAt","type","status"],"additionalProperties":false},"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"accountId":{"type":"string","minLength":1},"blockId":{"type":"string","minLength":1},"amountMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"effectiveDate":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"description":{"type":"string"},"subaccount":{"type":["string","null"]},"category":{"type":["string","null"]},"note":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","accountId","blockId","amountMinor","effectiveDate","description","subaccount","category","note","createdAt","updatedAt"],"additionalProperties":false}}},"required":["period","entries"],"additionalProperties":false}}}},"400":{"description":"Invalid input or malformed supported JSON","content":{"application/json":{"example":{"error":{"code":"VALIDATION","message":"entries.0.values.amountMinor: Invalid input: expected number, received string","issues":[{"path":["entries",0,"values","amountMinor"],"message":"Invalid input: expected number, received string","code":"invalid_type"}]}},"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Authenticated identity required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cookie mutation requires the exact configured Origin","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Target missing or not owned by the current user","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Conflict or immutable completed period","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"415":{"description":"Missing or unsupported JSON Content-Type","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"500":{"description":"Unexpected internal failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Authentication temporarily unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/accounts/{account}/periods/{periodKey}/entries/delete":{"post":{"operationId":"deletePeriodEntries","description":"Delete an explicitly identified set of entries from an existing draft period.\n\nUse this operation to remove entries that, after review, should no longer be part\nof the draft. Do not use deletion to represent a bank-issued refund or reversal;\nrecord that subsequent movement separately.\n\nSupply the entry IDs obtained from ledger reads or mutation responses. Every ID\nmust belong to the targeted period. Duplicate, unknown, or foreign IDs reject the\nentire request.\nUse confirmed mutation responses for IDs without a redundant read unless uncertain.\n\nThe operation is atomic: all specified entries are deleted, or nothing changes.\nOmitted entries remain untouched.\n\nCompleted periods reject deletion, including an empty batch. Deleting the last entry leaves an empty draft\nperiod; it does not delete the period itself.\n\nReturns the resulting period metadata and the deleted entry IDs. Deletion is\ncurrently permanent; no restoration operation is provided.\n\n### Request example\n\n```json\n{\n  \"entryIds\": [\"entry-id-1\", \"entry-id-2\"]\n}\n```\n\n### Response shape — 200 OK\n\n```ts\n{\n  period: PeriodBlock,\n  deletedEntryIds: string[]\n}\n```","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"account","in":"path"},{"schema":{"type":"string","pattern":"^(?!0000)\\d{4}-(0[1-9]|1[0-2])$"},"required":true,"name":"periodKey","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"entryIds":["8e4e163d-f604-42ad-a07a-f84f68449ebe"]},"schema":{"type":"object","properties":{"entryIds":{"type":"array","items":{"type":"string","minLength":1},"maxItems":97}},"required":["entryIds"],"additionalProperties":false}}}},"responses":{"200":{"description":"Confirmed persisted result","content":{"application/json":{"example":{"period":{"id":"2026-10","accountId":"personal-usd-credi-ffeff339","type":"period","status":"draft","createdAt":"2026-11-01T12:00:00.000Z","updatedAt":"2026-11-01T12:00:00.000Z"},"deletedEntryIds":["8e4e163d-f604-42ad-a07a-f84f68449ebe"]},"schema":{"type":"object","properties":{"period":{"type":"object","properties":{"id":{"type":"string","pattern":"^(?!0000)\\d{4}-(0[1-9]|1[0-2])$"},"accountId":{"type":"string","minLength":1},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"type":{"type":"string","enum":["period"]},"status":{"type":"string","enum":["draft","completed"]},"startsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"endsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"openingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"closingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","accountId","createdAt","updatedAt","type","status"],"additionalProperties":false},"deletedEntryIds":{"type":"array","items":{"type":"string","minLength":1}}},"required":["period","deletedEntryIds"],"additionalProperties":false}}}},"400":{"description":"Invalid input or malformed supported JSON","content":{"application/json":{"example":{"error":{"code":"VALIDATION","message":"entries.0.values.amountMinor: Invalid input: expected number, received string","issues":[{"path":["entries",0,"values","amountMinor"],"message":"Invalid input: expected number, received string","code":"invalid_type"}]}},"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Authenticated identity required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cookie mutation requires the exact configured Origin","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Target missing or not owned by the current user","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Conflict or immutable completed period","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"415":{"description":"Missing or unsupported JSON Content-Type","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"500":{"description":"Unexpected internal failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Authentication temporarily unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/accounts/{account}/periods/{periodKey}/complete":{"post":{"operationId":"completePeriod","description":"Complete the stored draft billing period after the user confirms acceptance of\nits contents. No request body is required or used; this operation does not accept\na replacement entry collection or statement metadata.\n\nReview the persisted draft against the available evidence, explain discrepancies\nor missing information, and obtain the user's confirmation before calling this\noperation. An official final statement is evidence for that review, not a separate\nlifecycle status.\n\nCompletion atomically changes the period from `draft` to `completed` and advances\nthe period's `updatedAt`. It locks amountMinor, effectiveDate and description,\ncreation, deletion and statement metadata. Subaccount/category/note enrichment\nremains allowed through full-value `mutatePeriodEntries` updates. Entries are not rewritten:\ntheir values, IDs, `createdAt`, and `updatedAt` remain unchanged.\n\nStatement coverage dates and opening/closing balances are optional and are not\nrequired for completion. The service records user acceptance; it does not\nindependently extract or verify bank evidence, reconcile balances, or establish\ncontinuity or completeness of account history.\n\n### Response shape — 200 OK\n\n```ts\nPeriodBlock // status: \"completed\"; existing identity and statement metadata retained\n```\n\nAn unknown or unowned account, or a missing period, returns 404. Completing an\nalready completed period returns 409 Conflict. There is no reopening operation.","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"account","in":"path"},{"schema":{"type":"string","pattern":"^(?!0000)\\d{4}-(0[1-9]|1[0-2])$"},"required":true,"name":"periodKey","in":"path"}],"responses":{"200":{"description":"Confirmed persisted result","content":{"application/json":{"example":{"id":"2026-10","accountId":"personal-usd-credi-ffeff339","type":"period","status":"completed","createdAt":"2026-11-01T12:00:00.000Z","updatedAt":"2026-11-01T12:00:00.000Z"},"schema":{"type":"object","properties":{"id":{"type":"string","pattern":"^(?!0000)\\d{4}-(0[1-9]|1[0-2])$"},"accountId":{"type":"string","minLength":1},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"type":{"type":"string","enum":["period"]},"status":{"type":"string","enum":["draft","completed"]},"startsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"endsOn":{"type":"string","format":"date","pattern":"^(?!0000)\\d{4}-\\d{2}-\\d{2}$"},"openingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"closingBalanceMinor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","accountId","createdAt","updatedAt","type","status"],"additionalProperties":false}}}},"400":{"description":"Invalid input or malformed supported JSON","content":{"application/json":{"example":{"error":{"code":"VALIDATION","message":"entries.0.values.amountMinor: Invalid input: expected number, received string","issues":[{"path":["entries",0,"values","amountMinor"],"message":"Invalid input: expected number, received string","code":"invalid_type"}]}},"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Authenticated identity required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cookie mutation requires the exact configured Origin","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Target missing or not owned by the current user","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Conflict or immutable completed period","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"500":{"description":"Unexpected internal failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Authentication temporarily unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION","UNAUTHENTICATED","CSRF_REJECTED","AUTH_UNAVAILABLE","NOT_FOUND","REFERENCE","CONFLICT","IMMUTABLE","MAINTENANCE","UNSUPPORTED_MEDIA_TYPE","INTERNAL"]},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object","properties":{"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"message":{"type":"string"},"code":{"type":"string"}},"required":["path","message","code"],"additionalProperties":false},"description":"Safe existing validation issues with field paths and zero-based batch indices; no rejected inputs. Lock violations may also include issues."}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}}},"webhooks":{}}