{"openapi":"3.1.0","info":{"title":"Median API","version":"0.1.0","description":"Production-grade Node.js + Express API starter template","license":{"name":"Proprietary"}},"servers":[{"url":"/api/v1"}],"security":[],"x-median-quarantined-authorities":{"decision":"ADR-0001-model-a","runtimeStatus":"unmounted","description":"Migrations 267-272 modeled legal entities as separate company tenants. These paths are not runtime API authority while their preserved accounting math is re-keyed to legal entities inside one company workspace.\n","paths":["/companies/{companyId}/consolidation-groups","/companies/{companyId}/consolidation-groups/{groupId}/versions/{groupVersionId}/report-rollups","/companies/{companyId}/consolidation-groups/{groupId}/versions/{groupVersionId}/report-rollups/{rollupId}","/companies/{companyId}/consolidation-groups/{groupId}/versions/{groupVersionId}/translation-adjustments","/companies/{companyId}/consolidation-groups/{groupId}/versions/{groupVersionId}/translation-adjustments/{adjustmentId}"]},"x-median-demo-parity-customer-surface":{"runtimeStatus":"mounted-lifecycle-only","description":"v2 customer-app capabilities available to JWT-authenticated members of any active or test company — the v2 app is the product, not a rollout cohort, so no allowlist applies to the markerless path. Production customer calls omit X-Median-App-Surface. Test-company calls may carry X-Median-App-Surface: qa to select the QA bundle; that marker branch alone still requires membership in CUSTOMER_APP_DEMO_PARITY_COMPANY_IDS. An API key, unknown marker, malformed company id, inactive company, missing gate dependency, or failed company lookup receives the standard hidden-resource 404 contract. The held surfaces riding these prefixes (AR/AP, Forecast, Insights) carry their own additional allowlist gate — see x-median-forecast-hold and x-median-ar-ap-hold.\n","headerContract":"#/components/parameters/demoParityCustomerAppSurface","routePrefixes":["/companies/{companyId}/ar","/companies/{companyId}/ap","/companies/{companyId}/customers","/companies/{companyId}/vendors","/companies/{companyId}/contracts","/companies/{companyId}/receivables","/companies/{companyId}/entities","/companies/{companyId}/currencies","/companies/{companyId}/reporting-scopes","/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/rollups","/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/translation-adjustments","/companies/{companyId}/presentation-report-snapshots","/companies/{companyId}/reporting-trial-balances","/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/trial-balances","/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany","/companies/{companyId}/weekly-email","/companies/{companyId}/forecast","/companies/{companyId}/books","/companies/{companyId}/sub-ledgers"]},"x-median-forecast-hold":{"runtimeStatus":"mounted-only-with-server-gate","description":"Forecast is held. Beyond the lifecycle-only customer surface above, every operation under the prefix below also requires the company to appear in the held-surface allowlist CUSTOMER_APP_DEMO_PARITY_COMPANY_IDS — the one operator-set list that opens AR/AP, Forecast and Insights (the legacy CUSTOMER_APP_FORECAST_COMPANY_IDS variable is no longer consulted). It is empty by default, so the v2 rollout alone never exposes Forecast. A company off the list receives the same hidden-resource 404 contract as one for which the surface does not exist. The auth-context featureFlags key `forecast` mirrors this verdict for the customer app shell.\n","featureFlag":"forecast","routePrefixes":["/companies/{companyId}/forecast"]},"x-median-ar-ap-hold":{"runtimeStatus":"mounted-only-with-server-gate","description":"Receivables/Payables are held behind TWO required authorities. Beyond the lifecycle-only customer surface above, every operation under the prefixes below requires the company to appear in the held-surface allowlist CUSTOMER_APP_DEMO_PARITY_COMPANY_IDS (requireDemoParityAllowlistedCompany) AND to satisfy the company_subledger_flags conversion chain (requireArApItemsEnabled — the same authority the public /pay page, aging and the accountant portal consult); failing either answers the opaque 404. The auth-context featureFlags key `arApItems` mirrors exactly that conjunction, resolved server-side, so the customer shell hides the Receivables/Payables nav and pages instead of offering menu entries these routes 404. Default is FALSE for every company while the list is empty or the conversion has not run.\n","featureFlag":"arApItems","routePrefixes":["/companies/{companyId}/ar","/companies/{companyId}/ap","/companies/{companyId}/customers","/companies/{companyId}/vendors","/companies/{companyId}/contracts","/companies/{companyId}/receivables"]},"x-median-demo-parity-qa-only":{"runtimeStatus":"mounted-only-with-server-gate","description":"Strict test-company-only routes. Every interactive call requires X-Median-App-Surface: qa in addition to JWT authentication, the server allowlist, and persisted client_status=test. A copied header, API key, active company, missing gate dependency, or failed company lookup receives the standard hidden-resource 404 contract.\n","headerContract":"#/components/parameters/qaAppSurface","routePrefixes":["/companies/{companyId}/gl-accounts/{id}/monetary-classification","/companies/{companyId}/fx-account-roles","/companies/{companyId}/gl-periods/{periodId}/fx-revaluation","/accountant/companies/{customerId}/gl-accounts/{id}/monetary-classification","/accountant/companies/{customerId}/fx-account-roles","/accountant/companies/{customerId}/gl-periods/{periodId}/fx-revaluation","/accountant/companies/{customerId}/ar/{id}","/accountant/companies/{customerId}/ap/{id}"]},"x-median-onboarding-v3-surface":{"runtimeStatus":"promoted","promotionFlag":"ONBOARDING_V3_QA_ONLY=false","description":"Promoted. The deployment this contract describes runs ONBOARDING_V3_QA_ONLY=false, so none of the onboarding-v3 auth, pricing, or setup paths below requires X-Median-App-Surface: qa. An unmarked request is served and reaches ordinary authentication, so an unauthenticated call now answers 401 rather than the hidden-resource 404. Mounting is still conditional: with ONBOARDING_V3_ENABLED false every path below returns the hidden-resource 404 before body parsing or authentication. The header stays defined and is still honoured, because a deployment left at ONBOARDING_V3_QA_ONLY=true keeps requiring it on every path below and 404s unmarked traffic; setting that flag back to true is the rollback. On either setting the header is a pre-company bundle marker, never tenant authorization.\n","headerContract":"#/components/parameters/onboardingV3QaSurface","routePaths":["/auth/otp/start","/auth/otp/verify","/auth/passkeys/register/options","/auth/passkeys/register/verify","/auth/passkeys/assert/options","/auth/passkeys/assert/verify","/onboarding/v3/quote","/onboarding/v3/offer/resolve","/onboarding/v3/flow","/onboarding/v3/setup-intent","/onboarding/v3/subscribe","/onboarding/v3/checkout-session","/onboarding/v3/checkout-session/complete","/onboarding/v3/setup-state","/onboarding/v3/delegate-invites","/onboarding/v3/delegate-invites/{inviteId}","/onboarding/v3/delegate/resolve","/onboarding/v3/delegate","/onboarding/v3/task-context","/onboarding/v3/delegate/task-context","/onboarding/v3/banks/plaid/link-token","/onboarding/v3/banks/plaid/exchange","/onboarding/v3/banks/commit","/onboarding/v3/documents/google-workspace/auth-url","/onboarding/v3/documents/google-workspace/callback","/onboarding/v3/books/quickbooks/auth-url","/onboarding/v3/books/quickbooks/callback","/onboarding/v3/books/xero/auth-url","/onboarding/v3/books/xero/callback","/onboarding/v3/welcome-call","/onboarding/v3/welcome-call/embed","/onboarding/v3/books-progress","/onboarding/v3/books/open","/companies/{companyId}/onboarding/v3/questions","/companies/{companyId}/onboarding/v3/questions/{questionId}/answer","/companies/{companyId}/onboarding/v3/review-items"]},"paths":{"/internal/engineering-kpis/access":{"get":{"operationId":"getEngineeringKpiAccess","summary":"Check current human staff access to engineering KPIs","description":"Uses the immutable staff user-ID allowlist and a fresh accountant profile. No email fallback. Returns no metric values.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current capability","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["canReadCompanyKpis"],"properties":{"canReadCompanyKpis":{"type":"boolean"}}}}}}}},"401":{"description":"Missing or expired authentication"},"403":{"description":"API-key authentication is excluded"}}}},"/internal/engineering-kpis":{"get":{"operationId":"getEngineeringKpis","summary":"Read the published engineering KPI tables","description":"Staff-only read of issue2977. Exactly nine engineering metrics for the supplied24-hour,7-day and30-day periods. Values preserve published rounding; exact windows, cohorts and detailed coverage are unavailable. No query parameters or producer writes. Responses are private and no-store.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Engineering snapshot, possibly stale or partial","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["contractVersion","sourceUrl","sourceAsOf","sourceUpdatedAt","metadataStatus","periods","refreshStatus","isStale"],"properties":{"contractVersion":{"type":"string","enum":["github-issue-tables-v1"]},"sourceUrl":{"type":"string","format":"uri"},"sourceAsOf":{"type":"string","format":"date-time"},"sourceUpdatedAt":{"type":"string","format":"date-time"},"metadataStatus":{"type":"string","enum":["unavailable"]},"refreshStatus":{"type":"string","enum":["ok","failed"]},"isStale":{"type":"boolean"},"periods":{"type":"array","minItems":3,"maxItems":3,"items":{"type":"object","required":["id","label","metrics"],"properties":{"id":{"type":"string","enum":["daily","weekly","monthly"]},"label":{"type":"string"},"metrics":{"type":"array","minItems":9,"maxItems":9,"items":{"type":"object","required":["id","label","unit","displayValue","status","sampleN"],"properties":{"id":{"type":"string","enum":["issues_completed","net_issue_count_change","open_issue_average_age","issue_average_age_at_completion","code_efficiency","code_effectiveness","open_pr_count","oldest_open_pr_age","pr_open_to_close"]},"label":{"type":"string"},"unit":{"type":"string","enum":["count","days","ratio"]},"displayValue":{"type":["string","null"]},"status":{"type":"string","enum":["observed","partial","unknown"]},"sampleN":{"type":"integer","minimum":0}}}}}}}}}}}}}},"401":{"description":"Missing or expired authentication"},"403":{"description":"Current staff capability required; API/service principals excluded"},"422":{"description":"Unsupported query parameters"},"503":{"description":"Source unconfigured or unavailable with no last-good snapshot"}}}},"/health":{"get":{"operationId":"getHealth","summary":"Health check","tags":["Health"],"responses":{"200":{"description":"Service is healthy","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"uptime":{"type":"number"},"commit":{"type":["string","null"],"description":"Git SHA of the running build (from RENDER_GIT_COMMIT; null outside Render)"}}}}}}}}}}},"/reference-data/currencies":{"get":{"operationId":"listCurrencyReferenceData","summary":"List server-owned ISO 4217 currency and capability authority","tags":["Reference Data"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current and historical currency reference with explicit vertical capabilities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrencyReferenceResponse"}}}},"401":{"description":"Missing or invalid auth token"}}}},"/webhooks/inbound-email":{"post":{"operationId":"ingestInboundEmail","summary":"Accept a signed SendGrid Inbound Parse delivery","description":"Provider-only document intake, mounted only when ONBOARDING_V3_INBOUND_EMAIL_ENABLED is true. This route has no bearer session. The provider signs the timestamp bytes followed by the exact raw multipart bytes; Median verifies that signature before parsing, resolving the single company alias recipient, scanning attachments, and writing documents. Provider retries are idempotent by immutable delivery identity.","tags":["Webhooks"],"security":[],"parameters":[{"name":"X-Twilio-Email-Event-Webhook-Timestamp","in":"header","required":true,"description":"Ten-digit Unix timestamp included in the signed payload and checked for staleness.","schema":{"type":"string","pattern":"^\\d{10}$"}},{"name":"X-Twilio-Email-Event-Webhook-Signature","in":"header","required":true,"description":"Base64-encoded ECDSA P-256 signature over the timestamp followed by the exact raw body.","schema":{"type":"string","minLength":4,"maxLength":256,"pattern":"^[A-Za-z0-9+/]+={0,2}$"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","additionalProperties":true,"description":"Standard SendGrid Inbound Parse text fields plus dynamically named attachment file parts are accepted. `envelope` and `headers` are required, `headers` must contain exactly one Message-ID, and at least one binary file part such as `attachment1` is required. Every text field is limited to 262144 bytes; body, attachment-size, attachment-count, field, and part ceilings are configured server-side.","required":["envelope","headers"],"properties":{"envelope":{"type":"string","maxLength":262144,"description":"JSON string with a non-empty `from` string and a `to` string array containing exactly one Median inbound alias."},"headers":{"type":"string","maxLength":262144,"description":"Raw message headers containing exactly one Message-ID header."},"from":{"type":"string","maxLength":262144,"description":"Provider-supplied display sender; routing authority comes from `envelope`."},"to":{"type":"string","maxLength":262144},"subject":{"type":"string","maxLength":262144},"text":{"type":"string","maxLength":262144},"html":{"type":"string","maxLength":262144},"attachments":{"type":"string","maxLength":262144,"description":"Provider-supplied attachment count; file parts remain authoritative."},"attachment-info":{"type":"string","maxLength":262144,"description":"Provider-supplied attachment metadata JSON."},"attachment1":{"type":"string","format":"binary","description":"Representative attachment file part; additional valid file-part names are accepted."}}}}}},"responses":{"200":{"description":"Inbound attachments accepted for durable document intake","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboundEmailIngestApiResponse"}}}},"400":{"$ref":"#/components/responses/InboundEmailBadRequest"},"401":{"$ref":"#/components/responses/InboundEmailUnauthorized"},"404":{"$ref":"#/components/responses/InboundEmailNotFound"},"413":{"$ref":"#/components/responses/InboundEmailPayloadTooLarge"},"415":{"$ref":"#/components/responses/InboundEmailUnsupportedMedia"},"422":{"$ref":"#/components/responses/InboundEmailUnprocessableEntity"},"503":{"$ref":"#/components/responses/InboundEmailServiceUnavailable"}}}},"/webhooks/slack/events":{"post":{"operationId":"ingestSlackEvent","summary":"Accept a signed Slack Events API delivery","description":"Inbound half of the bidirectional Slack thread mirror, mounted only when SLACK_SIGNING_SECRET is set. This route has no bearer session. Slack signs the exact raw request bytes, so the route parses the body as raw and verifies the HMAC before any JSON decoding. Deliveries are acked immediately and processed asynchronously, because Slack retries anything not acked within three seconds; retries are idempotent on (channel, message timestamp). Messages authored by the Median bot are ignored, which is what stops the mirror from echoing forever.","tags":["Webhooks"],"security":[],"parameters":[{"name":"X-Slack-Request-Timestamp","in":"header","required":true,"description":"Unix timestamp included in the signature base string; rejected beyond five minutes of skew.","schema":{"type":"string","pattern":"^\\d{9,11}$"}},{"name":"X-Slack-Signature","in":"header","required":true,"description":"Hex HMAC-SHA256 over \"v0:{timestamp}:{raw body}\", keyed with the app signing secret.","schema":{"type":"string","pattern":"^v0=[a-f0-9]{64}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["url_verification","event_callback"],"description":"url_verification is the one-time Request URL handshake."},"challenge":{"type":"string","description":"Echoed back verbatim during the url_verification handshake."},"team_id":{"type":"string","description":"Slack workspace ID; joined with the channel to resolve the Median company."},"event":{"type":"object","additionalProperties":true,"description":"The Slack event. Only `message` events are acted on; app_mention would arrive as a duplicate delivery of the same message.","properties":{"type":{"type":"string"},"subtype":{"type":"string"},"channel":{"type":"string"},"user":{"type":"string"},"bot_id":{"type":"string"},"text":{"type":"string"},"ts":{"type":"string"},"thread_ts":{"type":"string","description":"Present on replies; equals the parent message ts, which is how a Slack thread maps to a Median thread."}}}}}}}},"responses":{"200":{"description":"Delivery accepted. Returns the challenge during url_verification, otherwise an empty body. Always returned once the signature is valid, including when downstream processing fails, so Slack does not retry.","content":{"application/json":{"schema":{"type":"object","properties":{"challenge":{"type":"string"}}}}}},"400":{"description":"Body was not valid JSON"},"401":{"description":"Missing, stale, or invalid Slack signature"}}}},"/webhooks/github/secret-scanning":{"post":{"operationId":"receiveGithubSecretScanningAlert","summary":"Revoke service keys that GitHub secret scanning reports as leaked","description":"GitHub secret-scanning partner callback (#1147). Mounted only when GITHUB_SECRET_SCANNING_ALERTS_ENABLED=true; otherwise 404. There is no bearer session. GitHub signs the exact raw request bytes with an ECDSA P-256 key named in Github-Public-Key-Identifier; the key is fetched from https://api.github.com/meta/public_keys/secret_scanning and the signature is verified before the body is parsed. Only a token that parses as the `mdn_svc_v1_` service format (checksum included) and matches its stored hash exactly is revoked; every other token is labelled false_positive and nothing changes. Repeat deliveries are idempotent. Token values are never logged or echoed; the response carries SHA-256 hashes.","tags":["Webhooks"],"security":[],"parameters":[{"name":"Github-Public-Key-Identifier","in":"header","required":true,"description":"Identifier of the GitHub signing key.","schema":{"type":"string"}},{"name":"Github-Public-Key-Signature","in":"header","required":true,"description":"Base64 DER ECDSA (SHA-256) signature over the raw body.","schema":{"type":"string"}}],"requestBody":{"required":true,"description":"At most 64kb and 100 alerts.","content":{"application/json":{"schema":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"object","required":["token","type"],"properties":{"token":{"type":"string","maxLength":512},"type":{"type":"string","maxLength":100},"url":{"type":"string","maxLength":2048},"source":{"type":"string","maxLength":100}}}}}}},"responses":{"200":{"description":"Token analysis, one entry per distinct token (GitHub partner response format).","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["token_hash","token_type","label"],"properties":{"token_hash":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Hex SHA-256 of the reported token."},"token_type":{"type":"string"},"label":{"type":"string","enum":["true_positive","false_positive"]}}}}}}},"401":{"description":"Missing signature, unknown signing key, or invalid signature"},"404":{"description":"The callback is not enabled"},"413":{"description":"Body larger than 64kb"},"422":{"description":"Body is not a valid alert array"},"503":{"description":"GitHub signing keys could not be fetched and none is cached; GitHub retries"}}}},"/users/me":{"get":{"operationId":"getMe","summary":"Get the current authenticated user's profile","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current user's profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Missing or invalid auth token"}}}},"/users/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getUser","summary":"Get user by ID (self-only)","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Missing or invalid auth token"},"403":{"description":"Cannot view another user's profile"}}}},"/auth/register":{"post":{"operationId":"register","summary":"Register a new user account","tags":["Auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterInput"}}}},"responses":{"201":{"description":"User registered and tokens issued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"409":{"description":"Email already registered","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Validation error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/auth/login":{"post":{"operationId":"login","summary":"Authenticate with email and password","tags":["Auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginInput"}}}},"responses":{"200":{"description":"Authentication successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"401":{"description":"Invalid credentials","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Validation error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/auth/otp/start":{"post":{"operationId":"startPasswordlessOtp","summary":"Start a passwordless email-code ceremony","description":"Available only while ONBOARDING_V3_ENABLED is true. Signin remains enumeration resistant. Signup explicitly returns existingAccount=true for an existing Median account without issuing or delivering a code.\n","tags":["Auth"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordlessOtpStartInput"}}}},"responses":{"200":{"description":"Request accepted; signup may explicitly report an existing account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordlessOtpStartResponse"}}}},"400":{"$ref":"#/components/responses/PasswordlessInvalidJson"},"403":{"$ref":"#/components/responses/PasswordlessRecaptchaForbidden"},"404":{"$ref":"#/components/responses/OnboardingV3Hidden"},"413":{"$ref":"#/components/responses/PasswordlessPayloadTooLarge"},"415":{"$ref":"#/components/responses/PasswordlessUnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"429":{"$ref":"#/components/responses/PasswordlessRateLimited"}}}},"/auth/otp/verify":{"post":{"operationId":"verifyPasswordlessOtp","summary":"Verify a passwordless email code and issue a session","tags":["Auth"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordlessOtpVerifyInput"}}}},"responses":{"200":{"description":"Code verified and session issued","headers":{"Set-Cookie":{"schema":{"type":"string"},"description":"HttpOnly refresh-token cookie and a separate five-minute SameSite=Strict passkey enrollment grant cookie.\n"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordlessSessionResponse"}}}},"400":{"$ref":"#/components/responses/PasswordlessInvalidJson"},"401":{"$ref":"#/components/responses/PasswordlessUnauthorized"},"403":{"$ref":"#/components/responses/PasswordlessRecaptchaForbidden"},"404":{"$ref":"#/components/responses/OnboardingV3Hidden"},"409":{"description":"The signup email became an existing account after code issuance (PASSWORDLESS_ACCOUNT_EXISTS); no session is issued.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"$ref":"#/components/responses/PasswordlessPayloadTooLarge"},"415":{"$ref":"#/components/responses/PasswordlessUnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"429":{"$ref":"#/components/responses/PasswordlessRateLimited"}}}},"/auth/passkeys/register/options":{"post":{"operationId":"beginPasskeyRegistration","summary":"Begin passkey registration for the authenticated user","description":"Requires the exact access token, active HttpOnly refresh session, and separate short-lived one-shot enrollment grant issued by a successful email OTP verification for new or active registration. A completed response can be recovered with the same exact bearer and active refresh session only when they match its recent, unrevoked enrollment record. Logout revokes every registration binding.\n","tags":["Auth"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[],"refreshSessionCookie":[],"passkeyEnrollmentGrantCookie":[]},{"bearerAuth":[],"refreshSessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmptyPasskeyOptionsInput"}}}},"responses":{"200":{"description":"Browser registration options and an HttpOnly ceremony cookie. A retry can recover the same live ceremony or report that the passkey registration already completed.\n","headers":{"Set-Cookie":{"schema":{"type":"string"},"description":"A normal response sets the HttpOnly WebAuthn ceremony-binding cookie; the Strict enrollment grant is retained until successful verification or expiry. A completed-response recovery clears stale ceremony and enrollment cookies.\n"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasskeyRegistrationOptionsResponse"}}}},"400":{"$ref":"#/components/responses/PasswordlessInvalidJson"},"401":{"$ref":"#/components/responses/PasswordlessUnauthorized"},"404":{"$ref":"#/components/responses/OnboardingV3Hidden"},"413":{"$ref":"#/components/responses/PasswordlessPayloadTooLarge"},"415":{"$ref":"#/components/responses/PasswordlessUnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"429":{"$ref":"#/components/responses/PasswordlessRateLimited"}}}},"/auth/passkeys/register/verify":{"post":{"operationId":"finishPasskeyRegistration","summary":"Verify and persist a passkey for the authenticated user","tags":["Auth"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[],"refreshSessionCookie":[],"webAuthnCeremonyCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasskeyRegistrationVerifyInput"}}}},"responses":{"200":{"description":"Passkey registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasskeyRegistrationResponse"}}}},"400":{"$ref":"#/components/responses/PasswordlessInvalidJson"},"401":{"$ref":"#/components/responses/PasswordlessUnauthorized"},"404":{"$ref":"#/components/responses/OnboardingV3Hidden"},"409":{"description":"Credential identifier is already registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"$ref":"#/components/responses/PasswordlessPayloadTooLarge"},"415":{"$ref":"#/components/responses/PasswordlessUnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"429":{"$ref":"#/components/responses/PasswordlessRateLimited"}}}},"/auth/passkeys/assert/options":{"post":{"operationId":"beginPasskeyAuthentication","summary":"Begin discoverable passkey authentication","description":"Does not accept an email or other account identifier.","tags":["Auth"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasskeyAssertionOptionsInput"}}}},"responses":{"200":{"description":"Browser assertion options and one-shot HttpOnly ceremony cookie","headers":{"Set-Cookie":{"schema":{"type":"string"},"description":"HttpOnly WebAuthn ceremony-binding cookie"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasskeyOptionsResponse"}}}},"400":{"$ref":"#/components/responses/PasswordlessInvalidJson"},"401":{"$ref":"#/components/responses/PasswordlessUnauthorized"},"403":{"$ref":"#/components/responses/PasswordlessRecaptchaForbidden"},"404":{"$ref":"#/components/responses/OnboardingV3Hidden"},"413":{"$ref":"#/components/responses/PasswordlessPayloadTooLarge"},"415":{"$ref":"#/components/responses/PasswordlessUnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"429":{"$ref":"#/components/responses/PasswordlessRateLimited"}}}},"/auth/passkeys/assert/verify":{"post":{"operationId":"finishPasskeyAuthentication","summary":"Verify a discoverable passkey assertion and issue a session","tags":["Auth"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"webAuthnCeremonyCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasskeyAssertionVerifyInput"}}}},"responses":{"200":{"description":"Assertion verified and session issued","headers":{"Set-Cookie":{"schema":{"type":"string"},"description":"HttpOnly refresh-token cookie"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordlessSessionResponse"}}}},"400":{"$ref":"#/components/responses/PasswordlessInvalidJson"},"401":{"$ref":"#/components/responses/PasswordlessUnauthorized"},"403":{"$ref":"#/components/responses/PasswordlessRecaptchaForbidden"},"404":{"$ref":"#/components/responses/OnboardingV3Hidden"},"413":{"$ref":"#/components/responses/PasswordlessPayloadTooLarge"},"415":{"$ref":"#/components/responses/PasswordlessUnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"429":{"$ref":"#/components/responses/PasswordlessRateLimited"}}}},"/onboarding/v3/quote":{"post":{"operationId":"quoteOnboardingV3Pricing","summary":"Resolve the server-authoritative onboarding v3 price tier","description":"Hidden with the standard 404 contract while onboarding v3 is disabled.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3QuoteRequest"}}}},"responses":{"200":{"description":"Resolved fixed-price or sales-led tier","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3QuoteApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3PricingPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/onboarding/v3/offer/resolve":{"post":{"operationId":"resolveOnboardingV3Offer","summary":"Resolve an active custom offer from its opaque capability","description":"The bearer capability is carried in the JSON body so it cannot enter request paths, proxy access logs, metric labels, or fetch breadcrumbs. Malformed, unknown, expired, void, redeemed, and invalid-value tokens all return the same standard 404 contract.\n","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3OfferResolveRequest"}}}},"responses":{"200":{"description":"Active custom-offer price and trial","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3OfferApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3PricingPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/onboarding/v3/flow":{"get":{"operationId":"getOnboardingV3Flow","summary":"Read or create the authenticated user's durable onboarding flow","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Durable server-authoritative onboarding state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3FlowApiResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"patch":{"operationId":"patchOnboardingV3Flow","summary":"Advance the authenticated flow to the price questions","description":"Browser economics, tenant IDs, user IDs, and provider IDs are rejected.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3FlowPatch"}}}},"responses":{"200":{"description":"Updated flow","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3FlowApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3PricingPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/onboarding/v3/setup-intent":{"post":{"operationId":"createOnboardingV3SetupIntent","summary":"Create or resume the flow-bound Stripe test SetupIntent","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3EmptyBody"}}}},"responses":{"200":{"description":"Test publishable key and Payment Element client secret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3SetupIntentApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3PricingPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/subscribe":{"post":{"operationId":"subscribeOnboardingV3","summary":"Create or reconcile the flow-bound Stripe test subscription","description":"Request body is empty; all economics and provider IDs come from durable server state.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3EmptyBody"}}}},"responses":{"200":{"description":"Completed flow or a minimal invoice action secret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3SubscribeApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3PricingPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/checkout-session":{"post":{"operationId":"createOnboardingV3CheckoutSession","summary":"Start a hosted Stripe Checkout purchase for the server-quoted subscription","description":"Subscription-mode Checkout with promotion codes enabled. Request body is empty; economics come from durable server state and the return URLs are server-built for the surface the request arrived from. A flow that has already paid answers 409 ONBOARDING_ALREADY_PAID and opens no session; the client reloads the flow.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3EmptyBody"}}}},"responses":{"200":{"description":"Hosted Checkout URL to redirect the customer to","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3CheckoutSessionApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3PricingPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/checkout-session/complete":{"post":{"operationId":"completeOnboardingV3CheckoutSession","summary":"Finalize the flow after returning from hosted Stripe Checkout","description":"Validates the returned session against the flow's durable billing authority, stamps the provisioned company onto the Checkout-created subscription, and completes the flow like subscribe. Replaying the return on a paid flow is an idempotent 200. A session from another signup, or one that expired, answers 409 ONBOARDING_CHECKOUT_SESSION_STALE with nothing adopted; the client drops its return marker and offers checkout again. 503 is reserved for Stripe being unavailable or returning state that fails provider authority checks.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3CheckoutComplete"}}}},"responses":{"200":{"description":"Completed flow","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3SubscribeApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3PricingPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/setup-state":{"get":{"operationId":"getOnboardingV3SetupState","summary":"Read the authenticated company's server-authoritative setup state","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Durable setup tasks, data slices, and deferred questions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3SetupStateApiResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"}}},"patch":{"operationId":"patchOnboardingV3SetupState","summary":"Deep-merge one authenticated setup task slice","description":"The server is the sole setup-state authority. Completing Business Basics updates company identity and the primary legal entity in the same database transaction as this setup-state write.\n","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3SetupPatch"}}}},"responses":{"200":{"description":"Authoritative state after the task-scoped merge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3SetupStateApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/onboarding/v3/history/checkpoint":{"patch":{"operationId":"checkpointOnboardingV3History","summary":"Replace the authenticated owner's validated partial History draft","description":"Persists only server-authoritative, uncovered institution decisions and leaves the History task incomplete. Stable institution identifiers and uploaded statement evidence are revalidated against tenant-scoped source truth. Final completion still uses the setup-state authority path.\n","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3HistoryCheckpoint"}}}},"responses":{"200":{"description":"Normal owner setup state after replacing data.history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3SetupStateApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/onboarding/v3/delegate-invites":{"post":{"operationId":"createOnboardingV3DelegateInvite","summary":"Email a time-limited setup checklist capability to a delegate","description":"A newly minted raw 256-bit capability is returned once inside delegateUrl and sent by email; only its SHA-256 digest is stored. Retrying the same identity while its server-owned checklist remains live reuses that invite, sends no second email, and omits delegateUrl. A pending invite is inert until delivery succeeds; failed replacement delivery revokes only that pending invite and preserves the prior active checklist and assignments. QA delivery is SendGrid sandbox-only (or recipient-allowlisted); live delivery requires the separate promotion-time environment flip.\n","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3DelegateInviteCreate"}}}},"responses":{"200":{"description":"Matching live delegate capability reused without another email","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3DelegateInviteApiResponse"}}}},"201":{"description":"Delegate capability minted and email accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3DelegateInviteApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"429":{"$ref":"#/components/responses/PasswordlessRateLimited"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/delegate-invites/{inviteId}":{"delete":{"operationId":"revokeOnboardingV3DelegateInvite","summary":"Revoke a company-owned delegate capability","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"},{"name":"inviteId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Capability revoked and unfinished matching owners cleared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3DelegateRevokedApiResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/onboarding/v3/delegate/resolve":{"post":{"operationId":"resolveOnboardingV3Delegate","summary":"Resolve a live delegate capability to its exact task subset","description":"This endpoint has no app session. The raw capability stays in a focused JSON body so it cannot enter request paths, proxy logs, or metric labels. Unknown, expired, revoked, and malformed capabilities share one 404 shape.\n","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3DelegateResolve"}}}},"responses":{"200":{"description":"Filtered setup-state subset without invite identity or recipient metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3DelegateViewApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"429":{"description":"Rate limited by source address"}}}},"/onboarding/v3/delegate":{"patch":{"operationId":"patchOnboardingV3Delegate","summary":"Deep-merge one task authorized by a delegate capability","description":"This endpoint has no app session. The task must remain in the capability's current server-owned assignment subset. Unknown and out-of-subset writes share one 404 response. Path-bearing delegate capabilities are intentionally absent.\n","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3DelegatePatch"}}}},"responses":{"200":{"description":"Filtered authoritative state after the delegated write","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3DelegateViewApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"429":{"description":"Rate limited by source address"}}}},"/companies/{companyId}/integrations/quickbooks/auth-url":{"parameters":[{"name":"companyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"createQuickBooksLedgerAuthorization","summary":"Start the QuickBooks source-ledger authorization (no migration) (#2560)","tags":["Integrations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"redirectUri":{"type":"string","format":"uri","maxLength":2048}},"required":["redirectUri"],"additionalProperties":false}}}},"responses":{"200":{"description":"Intuit authorization URL carrying the signed state","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"authorizationUrl":{"type":"string","format":"uri"}},"required":["authorizationUrl"]}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"QuickBooks is not configured"}}}},"/companies/{companyId}/integrations/quickbooks/callback":{"parameters":[{"name":"companyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"completeQuickBooksLedgerAuthorization","summary":"Complete the QuickBooks source-ledger authorization and verify the realm (#2560)","tags":["Integrations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","maxLength":4096},"state":{"type":"string","maxLength":4096},"realmId":{"type":"string","pattern":"^[0-9]{1,32}$"},"redirectUri":{"type":"string","format":"uri","maxLength":2048}},"required":["code","state","realmId","redirectUri"],"additionalProperties":false}}}},"responses":{"201":{"description":"Connection status after verification","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksLedgerStatus"}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/integrations/quickbooks/connection":{"parameters":[{"name":"companyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getQuickBooksLedgerConnection","summary":"QuickBooks source-ledger connection status (realm masked) (#2560)","tags":["Integrations"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Connection status","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksLedgerStatus"}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/integrations/quickbooks/source-sync":{"parameters":[{"name":"companyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getQuickBooksSourceSync","summary":"Read realm-bound QBO source inventory status; no GL posting","tags":["Integrations"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Source-read status and counts from one completed inventory; not GL reconciliation","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksSourceStatus"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"The verified QuickBooks connection is unavailable or changed"},"503":{"description":"Source sync or the provider is unavailable"}}},"post":{"operationId":"retryQuickBooksSourceSync","summary":"Queue a fresh read of the verified QBO realm; no GL posting","tags":["Integrations"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Queued source-read status","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksSourceStatus"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"The verified QuickBooks connection is unavailable or changed"},"503":{"description":"Source sync or the provider is unavailable"}}}},"/companies/{companyId}/integrations/quickbooks/source-preview":{"parameters":[{"name":"companyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getQuickBooksSourcePreview","summary":"Read a bounded preview of imported QBO source objects; no Median posting","tags":["Integrations"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Up to 25 realm-bound source identities from one completed run","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","maxItems":25,"items":{"$ref":"#/components/schemas/QuickBooksSourcePreviewItem"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"The verified QuickBooks connection is unavailable or changed"},"503":{"description":"Source sync or the provider is unavailable"}}}},"/companies/{companyId}/integrations/quickbooks/status":{"parameters":[{"name":"companyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getQuickBooksCustomerStatus","summary":"Customer QuickBooks status - read state, coverage, books state and gaps (#2642)","description":"Reports reading QuickBooks and posting into Median's books separately. A completed read never means the books are posted. QuickBooks' bank-feed \"For review\" queue is not available through Intuit's API and is never reported as read. No amounts.","tags":["Integrations"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Customer-facing QuickBooks status","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksCustomerStatus"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"The verified QuickBooks connection is unavailable or changed"},"503":{"description":"QuickBooks status or the provider is unavailable"}}}},"/onboarding/v3/prepared-profile/requests/{requestId}/submit":{"parameters":[{"name":"requestId","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9-]{2,40}$"}}],"post":{"operationId":"submitOnboardingV3PreparedRequest","summary":"Mark a prepared engagement request as sent by the customer (#2560)","description":"Customer-controlled state only. Accountant verification, task selection, price and verified access are never writable from this endpoint.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":300}},"additionalProperties":false}}}},"responses":{"200":{"description":"Updated prepared engagement view","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/PreparedOnboardingProfileView"}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/onboarding/v3/task-context":{"get":{"operationId":"getOnboardingV3TaskContext","summary":"Read server-derived provider setup context for the authenticated owner","description":"Returns live bank-account classifications, non-personal history coverage, provisioned inbound-email authority, and current Google Workspace state. It never treats setup JSON as provider authority.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current server-derived provider setup context","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3OwnerTaskContextApiResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/onboarding/v3/delegate/task-context":{"post":{"operationId":"getOnboardingV3DelegateTaskContext","summary":"Resolve only delegate-safe provider guidance","description":"This endpoint has no app session. The raw capability remains in the JSON body. Bank connections and institution history are owner-only; delegates receive at most forwarding, invitation, and later-path guidance.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3DelegateTaskContextRequest"}}}},"responses":{"200":{"description":"Capability-scoped context without company, account, or institution identifiers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3DelegateTaskContextApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"429":{"description":"Rate limited by source address"}}}},"/onboarding/v3/banks/plaid/link-token":{"post":{"operationId":"createOnboardingV3PlaidLinkToken","summary":"Create owner-bound Plaid Link authority in sandbox","description":"Available only when Plaid is configured for sandbox. Company and legal entity authority are derived from the authenticated onboarding flow.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3PlaidLinkTokenRequest"}}}},"responses":{"200":{"description":"Sandbox Link token and owner-bound callback authority","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3PlaidLinkTokenApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/banks/plaid/exchange":{"post":{"operationId":"exchangeOnboardingV3PlaidPublicToken","summary":"Exchange a sandbox Plaid token while holding initial sync","description":"Creates real account rows but leaves the connection held until every account is classified as business or personal.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3PlaidExchangeRequest"}}}},"responses":{"201":{"description":"Held integration and unclassified account projection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3PlaidExchangeApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/banks/commit":{"post":{"operationId":"commitOnboardingV3PlaidConnection","summary":"Commit exact personal-account classifications and release one sync","description":"The account set must exactly match the live held integration. Identical replays are idempotent; changed replays remain locked.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3PlaidCommitRequest"}}}},"responses":{"200":{"description":"Committed account projection and initial sync job, if newly released","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3PlaidCommitApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/documents/google-workspace/auth-url":{"post":{"operationId":"createOnboardingV3GoogleWorkspaceAuthorization","summary":"Create owner-bound Google Workspace authorization","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3GoogleAuthorizationRequest"}}}},"responses":{"200":{"description":"Provider authorization URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3GoogleAuthorizationApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/documents/google-workspace/callback":{"post":{"operationId":"completeOnboardingV3GoogleWorkspaceAuthorization","summary":"Complete owner-bound Google Workspace authorization","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3GoogleCallbackRequest"}}}},"responses":{"201":{"description":"Connected integration and ingestion sync job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3GoogleCallbackApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/books/quickbooks/auth-url":{"post":{"operationId":"createOnboardingV3QuickBooksAuthorization","summary":"Create an owner-bound QuickBooks authorization","description":"Creates a durable, one-use Existing Books authorization bound to the authenticated owner, selected legal entity, provider environment, and exact redirect URI. QA traffic is restricted to QuickBooks sandbox.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3BooksAuthorizationRequest"}}}},"responses":{"200":{"description":"Provider authorization URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3BooksAuthorizationApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/books/quickbooks/callback":{"post":{"operationId":"completeOnboardingV3QuickBooksAuthorization","summary":"Complete an owner-bound QuickBooks authorization","description":"Consumes the exact one-use authorization, verifies the returned realm through QuickBooks CompanyInfo, checkpoints encrypted credentials, and creates authoritative account mappings without importing entries.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3QuickBooksCallbackRequest"}}}},"responses":{"201":{"description":"Durable Existing Books migration job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3BooksMigrationApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/books/xero/auth-url":{"post":{"operationId":"createOnboardingV3XeroAuthorization","summary":"Create an owner-bound Xero authorization","description":"Creates a durable, one-use Existing Books authorization bound to the authenticated owner, selected legal entity, provider environment, and exact redirect URI.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3BooksAuthorizationRequest"}}}},"responses":{"200":{"description":"Provider authorization URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3BooksAuthorizationApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/books/xero/callback":{"post":{"operationId":"completeOnboardingV3XeroAuthorization","summary":"Complete an owner-bound Xero authorization","description":"Consumes the exact one-use authorization and accepts exactly one newly authorized organisation whose tenant ID is on the server allowlist. Caller-selected tenant IDs are never accepted.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3XeroCallbackRequest"}}}},"responses":{"201":{"description":"Durable Existing Books migration job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3BooksMigrationApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/welcome-call":{"get":{"operationId":"getOnboardingV3WelcomeCall","summary":"Read real welcome-call availability or the active booking","description":"Reads the authenticated QA owner's server-authoritative call state. Availability contains at most three real provider slots on each of the next five weekdays. No slot is synthesized when provider scheduling is unavailable.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"},{"name":"timeZone","in":"query","required":true,"description":"IANA time zone used to group provider availability by local weekday.","schema":{"type":"string","minLength":1,"maxLength":100}},{"name":"reschedule","in":"query","required":false,"schema":{"type":"string","enum":["true","false"],"default":"false"}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current welcome-call state and provider-backed availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3WelcomeCallApiResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}},"post":{"operationId":"bookOnboardingV3WelcomeCall","summary":"Book or reschedule the authenticated QA owner's welcome call","description":"The requested start must still be present in provider availability. The server owns attendee identity, one-active-call authority, and the durable provider booking identity.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3WelcomeCallBooking"}}}},"responses":{"200":{"description":"Existing booking returned or active booking rescheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3WelcomeCallApiResponse"}}}},"201":{"description":"Welcome call booked and durably linked to the provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3WelcomeCallApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/welcome-call/embed":{"post":{"operationId":"recordOnboardingV3EmbeddedWelcomeCall","summary":"Submit hosted-calendar callback evidence for verification","description":"Treats browser callback fields only as correlation evidence, never booking authority. The server persists a pending record and verifies it against Cal.com. It returns verifying with no public call unless server-side Cal verification succeeds; only then does it return booked.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3WelcomeCallEmbeddedBooking"}}}},"responses":{"200":{"description":"Verifying while evidence is pending, or booked after the server has verified it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3WelcomeCallApiResponse"},"examples":{"verifying":{"summary":"Callback evidence persisted pending server verification","value":{"success":true,"data":{"state":"verifying","schedulingMode":"embed","fullCalendarUrl":"https://cal.com/median/onboarding","slots":[],"call":null}}},"verified":{"summary":"Cal.com verification established provider authority","value":{"success":true,"data":{"state":"booked","schedulingMode":"embed","fullCalendarUrl":null,"slots":[],"call":{"id":"d3000000-0000-4000-8000-000000000113","scheduledAt":"2026-07-27T15:00:00.000Z","durationMinutes":20,"status":"scheduled"}}}}}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/onboarding/v3/books-progress":{"get":{"operationId":"getOnboardingV3BooksProgress","summary":"Read server-calculated onboarding work meters and books state","description":"Each meter is calculated from accounting source authority. A failed source query returns an explicit unavailable metric instead of a fabricated zero. Financial metrics remain veiled until the existing company metrics gate is enabled.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current work meters and Building Your Books state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3BooksProgressApiResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/onboarding/v3/books/open":{"post":{"operationId":"openOnboardingV3Books","summary":"Advance the authenticated onboarding flow from setup to books","description":"The empty request cannot choose a company or lifecycle stage. The server resolves the flow-owned QA company and performs an idempotent setup-to-books transition.","tags":["Onboarding"],"parameters":[{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3EmptyBody"}}}},"responses":{"200":{"description":"Authoritative books stage","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3BooksOpenApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/companies/{companyId}/integrations/slack/thread-sync":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"setSlackThreadSync","summary":"Turn the bidirectional Slack thread mirror on or off","description":"When enabled, Median thread messages are posted into the connected Slack channel and replies in that Slack thread are written back as thread messages. Requires a channel to already be selected, since inbound events are routed by workspace plus channel. Enabling also suppresses the daily digest for this company, which would otherwise repeat the same messages.","tags":["Slack"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean"},"inboundMode":{"type":"string","enum":["mention_or_reply","all"],"description":"mention_or_reply (default) only opens a new Median thread when the bot is mentioned; replies inside an existing mirrored thread always sync. `all` treats every top-level channel message as a new thread, which is only sensible on a channel dedicated to Median."}}}}}},"responses":{"200":{"description":"Updated thread sync state","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"threadSyncEnabled":{"type":"boolean"},"inboundMode":{"type":"string","enum":["mention_or_reply","all"]}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/companies/{companyId}/onboarding/v3/questions":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"get":{"operationId":"listOnboardingV3Questions","summary":"List the founder's persisted onboarding question inbox","description":"Returns record-only questions for the authenticated company member. Answers create accountant follow-up work and never mutate the ledger.","tags":["Onboarding"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Questions and persisted completion summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3QuestionsInboxApiResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/companies/{companyId}/onboarding/v3/questions/{questionId}/answer":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/onboardingV3QaSurface"},{"name":"questionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"answerOnboardingV3Question","summary":"Record one founder answer or skip disposition","description":"Atomically records exactly one choice, text answer, or skip and creates an accountant action. It performs no transaction categorization or other ledger mutation. #2019: a text answer to the deferred Business Basics \"Fiscal year end\" question must read as a real month-day (\"06-30\", \"6/30\", \"June 30\"); otherwise 422 and nothing is recorded. A valid one is written to companies.fiscal_year_end as MM-DD. Chips and skips never write it.","tags":["Onboarding"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3QuestionAnswer"}}}},"responses":{"200":{"description":"Persisted question with its record-only answer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3QuestionApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/companies/{companyId}/onboarding/v3/review-items":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/onboardingV3QaSurface"}],"get":{"operationId":"listOnboardingV3ReviewItems","summary":"List accountant-authored onboarding review findings","tags":["Onboarding"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Persisted review items in accountant-controlled sort order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3ReviewItemsApiResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/onboarding-questions":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"listAccountantOnboardingQuestions","summary":"List onboarding questions for an assigned customer","tags":["Accountant Portal","Onboarding"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Questions and founder completion summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3QuestionsInboxApiResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"post":{"operationId":"createAccountantOnboardingQuestion","summary":"Create a record-only onboarding question for an assigned customer","description":"Plaintext EIN values are rejected. EIN collection remains inside the encrypted Business Basics authority.","tags":["Accountant Portal","Onboarding"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3QuestionCreate"}}}},"responses":{"201":{"description":"Persisted accountant question","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3QuestionApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/accountant/companies/{customerId}/onboarding-review-items":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"listAccountantOnboardingReviewItems","summary":"List onboarding review findings for an assigned customer","tags":["Accountant Portal","Onboarding"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Persisted review items in display order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3ReviewItemsApiResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"post":{"operationId":"createAccountantOnboardingReviewItem","summary":"Create an onboarding review finding for an assigned customer","tags":["Accountant Portal","Onboarding"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3ReviewItemCreate"}}}},"responses":{"201":{"description":"Persisted review item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3ReviewItemApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/accountant/companies/{customerId}/onboarding-review-items/{itemId}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"updateAccountantOnboardingReviewItem","summary":"Update an onboarding review finding for an assigned customer","tags":["Accountant Portal","Onboarding"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3ReviewItemUpdate"}}}},"responses":{"200":{"description":"Updated review item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingV3ReviewItemApiResponse"}}}},"400":{"$ref":"#/components/responses/OnboardingV3InvalidJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"413":{"$ref":"#/components/responses/OnboardingV3SetupPayloadTooLarge"},"415":{"$ref":"#/components/responses/OnboardingV3UnsupportedBodyEncoding"},"422":{"$ref":"#/components/responses/ValidationProblem"}}},"delete":{"operationId":"deleteAccountantOnboardingReviewItem","summary":"Delete an onboarding review finding for an assigned customer","tags":["Accountant Portal","Onboarding"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Onboarding review item deleted"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/auth/password/forgot":{"post":{"operationId":"requestPasswordReset","summary":"Request a password reset email","tags":["Auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordResetRequestInput"}}}},"responses":{"200":{"description":"Generic accepted response for existing and non-existing accounts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordResetRequestResponse"}}}},"422":{"description":"Validation error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"429":{"description":"Too many password reset requests","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/auth/password/reset":{"post":{"operationId":"resetPassword","summary":"Reset password with a single-use email token","tags":["Auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordResetInput"}}}},"responses":{"204":{"description":"Password reset and active sessions revoked"},"409":{"description":"Reset token is invalid, expired, or already used","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Validation error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"429":{"description":"Too many password reset attempts","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/auth/invites/preview":{"post":{"operationId":"previewInvite","summary":"Preview a token-bound invite and select its required authentication path","tags":["Auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteTokenInput"}}}},"responses":{"200":{"description":"Invite display data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitePreviewResponse"}}}},"404":{"description":"Invite not found"},"422":{"description":"Validation error"}}}},"/auth/invites/accept":{"post":{"operationId":"acceptInvite","summary":"Accept an invite for the authenticated user","tags":["Auth"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteTokenInput"}}}},"responses":{"200":{"description":"Invite accepted and active company context returned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteAcceptResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Invite expired, revoked, or already accepted"},"422":{"description":"Validation error"}}}},"/auth/invites/signup":{"post":{"operationId":"signupWithInvite","summary":"Create an account from an invite and accept it atomically","tags":["Auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteSignupInput"}}}},"responses":{"201":{"description":"Account created, invite accepted, and tokens issued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"409":{"description":"Existing account, expired invite, revoked invite, or replayed invite"},"422":{"description":"Validation error"}}}},"/auth/context":{"get":{"operationId":"getAuthContext","summary":"Get customer-app routing and company membership context","tags":["Auth"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"companyId","required":false,"schema":{"type":"string","format":"uuid"},"description":"Preferred active company context for users with multiple memberships."}],"responses":{"200":{"description":"Auth context","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserContextResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/auth/refresh":{"post":{"operationId":"refreshTokens","summary":"Exchange a refresh token for a new token pair","tags":["Auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshInput"}}}},"responses":{"200":{"description":"New token pair issued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenPairResponse"}}}},"401":{"description":"Refresh token invalid, expired, or revoked","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Validation error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/auth/logout":{"post":{"operationId":"logout","summary":"Revoke refresh token and end session","tags":["Auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogoutInput"}}}},"responses":{"204":{"description":"Session revoked"},"422":{"description":"Validation error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/companies/{companyId}":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getCompany","summary":"Get a company by ID","tags":["Companies"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Company details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Company not found"}}},"patch":{"operationId":"updateCompany","summary":"Update a company's profile","description":"Partial edit of the company profile: only the keys sent are written, and an empty string is treated as \"not sent\". Text fields are plain text; HTML markup is rejected with 422. `fiscalYearEnd` is the one field an explicit `null` clears (back to \"not confirmed\", #2736); a February year end has one stored spelling, so `02-29` is stored and returned as `02-28`, meaning the last day of February; setting it to a date withdraws the open deferred onboarding fiscal-year question. Every change is recorded in the audit log with its previous and new value. Accountant-only state (`clientStatus`, `metricsEnabled`, view-only access confirmation) is ignored here and has its own accountant routes. API-key credentials are refused with 403.\n","tags":["Companies"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCompanyInput"}}}},"responses":{"200":{"description":"The updated company","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Company not found"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/ar":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"listArItems","summary":"List AR (invoice) items","description":"DARK — 404s unless company_subledger_flags.ar_ap_items_enabled is true.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string"}},{"name":"customerId","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of AR items"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"AR/AP items not enabled for this company"}}},"post":{"operationId":"createArItem","summary":"Create a manual AR item","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"AR item created"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"AR/AP items not enabled for this company"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/ar/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"getArItem","summary":"Get an AR item (includes availableTransitions)","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"AR item detail with availableTransitions"},"404":{"description":"Not found or AR/AP not enabled"}}},"patch":{"operationId":"patchArItem","summary":"Edit non-status fields of an AR item","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"AR item updated"},"404":{"description":"Not found or AR/AP not enabled"},"409":{"description":"Stripe-source item is status-locked"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/ar/{id}/issue":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"post":{"operationId":"issueArItem","summary":"Issue an AR item (draft → open)","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"AR item issued"},"404":{"description":"Not found or AR/AP not enabled"},"409":{"description":"Stripe-source item is status-locked"},"422":{"description":"Illegal transition"}}}},"/companies/{companyId}/ar/{id}/document":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"post":{"operationId":"attachArDocument","summary":"Attach a document to an AR item","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Document attached"},"404":{"description":"Not found or AR/AP not enabled"}}},"delete":{"operationId":"detachArDocument","summary":"Detach the document from an AR item","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Document detached"},"404":{"description":"Not found or AR/AP not enabled"}}}},"/companies/{companyId}/ar/{id}/send":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"post":{"operationId":"sendArItem","summary":"Send an invoice (draft → open, mints the payment token; idempotent)","description":"DARK — 404s unless ar_ap_items_enabled. First send transitions a draft to open through the FSM and mints a unique non-guessable payment_token; re-sends are idempotent (token and sentAt stable). Requires a positive total and a counterparty. Email dispatch is a separate sub-issue.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Invoice sent (item with lines and availableTransitions)"},"404":{"description":"Not found or AR/AP not enabled"},"409":{"description":"Stripe-source item is status-locked"},"422":{"description":"Non-positive total, missing counterparty, or illegal transition"}}}},"/companies/{companyId}/ar/{id}/resend-email":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"post":{"operationId":"resendArInvoiceEmail","summary":"Resend the invoice email (already-sent invoices; same payment token)","description":"DARK — 404s unless ar_ap_items_enabled. Re-dispatches the invoice email for an already-sent invoice, reusing the same payment token and refreshing email_sent_at on success. Unlike send, a provider failure surfaces to the caller (this endpoint IS the retry path). Only open and partially_paid invoices may be re-emailed.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Email re-dispatched (item with lines and availableTransitions)"},"404":{"description":"Not found or AR/AP not enabled"},"409":{"description":"Stripe-source item is status-locked"},"422":{"description":"Never sent, no longer collectible (not open/partially_paid), no recipient email on file, or email delivery not configured.\n"}}}},"/companies/{companyId}/ar/{id}/email-preview":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"previewArInvoiceEmail","summary":"Server-rendered invoice email preview (nothing sent)","description":"DARK — 404s unless ar_ap_items_enabled. Returns the exact email the send/resend path dispatches as { to, subject, html } — same recipient resolution, same template — without sending anything, without an FSM transition, and without stamping email_sent_at. `to` is null when the counterparty has no email on file (the preview still renders). Drafts are refused: a draft has no send contract yet.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Rendered email preview: { to, subject, html }"},"404":{"description":"Not found or AR/AP not enabled"},"422":{"description":"Draft or never-sent invoice, or email delivery not configured on this deployment.\n"}}}},"/companies/{companyId}/ar/compose":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"post":{"operationId":"composeArInvoice","summary":"Create an invoice from the composer (server-owned totals)","description":"DARK — 404s unless ar_ap_items_enabled. Line items carry revenue category, quantity, unit price, tax bps, and a per-line service period; every line subtotal/tax/total and the item amount_cents are recomputed server-side (client totals are rejected by the strict schema). dueDate derives from terms when not supplied; status \"sent\" composes and sends in one call.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Invoice created (item with lines and availableTransitions)"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"AR/AP items not enabled for this company"},"422":{"description":"Validation error (including client-supplied totals)"}}}},"/companies/{companyId}/ar/drafts/from-document":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"post":{"operationId":"createArDraftFromDocument","summary":"Create a DRAFT invoice from an uploaded invoice document's extraction","description":"DARK — 404s unless ar_ap_items_enabled. Body {documentId}. Turns the document's latest extraction (documents pipeline evidence) into a draft through the composer aggregate; the draft references the source document (document_id + sourceMetadata.documentId). Fields are never guessed: a missing/incomplete extraction (wrong document type, unassigned document, no extraction row, failed extraction, missing amount/customer/issue date, or a document already linked to a receivable) is a 422 whose error.extensions.reasons lists every applicable gap. Extraction line items become composer lines only when they reconcile exactly to the invoice total; otherwise a single line carries the known total. Never auto-posts — issue/send stay explicit.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["documentId"],"additionalProperties":false,"properties":{"documentId":{"type":"string","format":"uuid"}}}}}},"responses":{"201":{"description":"Draft created: { success, data: { draftInvoiceId } }"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Document not found or AR/AP items not enabled"},"422":{"description":"Extraction missing/incomplete or document ineligible; error.extensions.reasons enumerates every applicable reason.\n"}}}},"/companies/{companyId}/ar/{id}/composed":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"getComposedArInvoice","summary":"Get an invoice with its composer lines","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Invoice detail with lines"},"404":{"description":"Not found or AR/AP not enabled"}}},"patch":{"operationId":"updateComposedArInvoice","summary":"Re-compose a draft invoice (lines replace wholesale, totals recompute)","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Invoice updated"},"404":{"description":"Not found or AR/AP not enabled"},"409":{"description":"Stripe-source item is status-locked"},"422":{"description":"Validation error or not a draft"}}}},"/companies/{companyId}/ar/{id}/status":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"post":{"operationId":"updateArItemStatus","summary":"Drawer lifecycle action (mark paid / void / uncollectible), FSM-enforced","description":"Transitions to 'paid' also record an ar_item_payments row for the outstanding amount (paid_at = today) and settle amountPaidCents, so the pipeline's collected-by-month reflects manual mark-paid flows.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Status updated (with availableTransitions)"},"404":{"description":"Not found or AR/AP not enabled"},"409":{"description":"Stripe-source item is status-locked"},"422":{"description":"Illegal transition"}}}},"/companies/{companyId}/ar/{id}/match-transaction":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"post":{"operationId":"matchArTransaction","summary":"Match a bank deposit to the invoice (marks fully paid)","description":"DARK — 404s unless ar_ap_items_enabled. Body {transactionId}. The transaction must belong to the company (company-scoped lookup; a cross-tenant id is a 404). Writes an ar_item_payments row for the item's OUTSTANDING amount (paid_at = the transaction's occurred_on), bumps amountPaidCents to the total, and transitions to 'paid' through the FSM — the Stripe-source lock and legal-transition guards hold exactly as for the drawer actions.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["transactionId"],"properties":{"transactionId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Invoice marked paid (item with availableTransitions)"},"404":{"description":"Item or transaction not found, or AR/AP not enabled"},"409":{"description":"Stripe-source item is status-locked"},"422":{"description":"Already fully paid or illegal transition (e.g. draft)"}}}},"/companies/{companyId}/ar/{id}/payments":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"listArInvoicePayments","summary":"List the invoice's card-collection payments (charge-rail subledger)","description":"DARK — 404s unless ar_ap_items_enabled. Reads the invoice_payments card-collection subledger (AR Stripe charge rail): succeeded/failed card charges recorded by the payment_intent.* settlement webhook and the ach/pending \"payer says the transfer is on the way\" soft signal. Distinct from ar_item_payments (bank-match collections). Rows are {id, method(card|ach), status(pending|succeeded|failed), amountCents, feeCents, paidAt, createdAt}, oldest first; Stripe PaymentIntent ids are deliberately never returned. The item lookup is company-scoped (a cross-tenant id is a 404).\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Payment rows for the invoice (may be empty)"},"404":{"description":"Not found or AR/AP not enabled"}}}},"/companies/{companyId}/contracts":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"listContracts","summary":"List contracts with funding rollups (attention-first)","description":"DARK — 404s unless ar_ap_items_enabled. Each contract carries a derived `funding` rollup {contractedCents, invoicedToDateCents, remainingCents, pctInvoiced, isFullyInvoiced} computed from its non-void AR items (linkage sourceMetadata.contractId); invariant invoicedToDate + remaining = contracted. Sorted attention-first (remaining > 0 or status overdue), then by contracted value. The envelope also carries totalContractedCents and activeContractCount (active = not cancelled/completed), plus currency and minorUnitExponent. Funding rollups carry the same non-null currency authority. Mixed, invalid, missing, or non-two-decimal source currencies fail with MONETARY_AGGREGATE_CURRENCY_UNAVAILABLE (422).\n","tags":["Receivables"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["new","on_track","overdue","completed","cancelled"]}},{"name":"customerId","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{ contracts: [contract + funding], totalContractedCents, activeContractCount, currency, minorUnitExponent }"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"AR/AP items not enabled for this company"},"422":{"description":"Validation error or unavailable homogeneous two-decimal currency authority"}}},"post":{"operationId":"createContract","summary":"Create a contract (the contract-to-cash funding target)","description":"DARK — 404s unless ar_ap_items_enabled. customerId (when given) must belong to the company — validated via the company-scoped customer lookup; customerName denormalizes from the master record when omitted. invoiced_to_date is never stored; funding derives on read.\n","tags":["Receivables"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Contract created (with funding rollup)"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Customer not found or AR/AP not enabled"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/contracts/{contractId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"contractId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"getContract","summary":"Contract detail with funding and its invoices","tags":["Receivables"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Contract + funding + invoices (AR items linked via sourceMetadata.contractId)"},"404":{"description":"Not found or AR/AP not enabled"}}},"patch":{"operationId":"patchContract","summary":"Edit contract header/status fields (CRUD-lite)","tags":["Receivables"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Contract updated (with funding rollup)"},"404":{"description":"Not found or AR/AP not enabled"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/receivables/summary":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"getReceivablesSummary","summary":"Receivables summary cards (overdue / dueSoon / current / outstanding)","description":"DARK — 404s unless ar_ap_items_enabled. Each figure is {amountCents, count} over OUTSTANDING balances (amount - paid) of items whose status is not paid/void/uncollectible. overdue = past due; dueSoon = due within 7 days; current = outstanding - overdue (identity holds for both amount and count). The aggregate carries currency and minorUnitExponent; an empty zero-value aggregate carries null/null rather than a guessed currency.\n","tags":["Receivables"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"{ overdue, dueSoon, current, outstanding, currency, minorUnitExponent }; figures are { amountCents, count }"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"AR/AP items not enabled for this company"},"422":{"description":"MONETARY_AGGREGATE_CURRENCY_UNAVAILABLE for mixed, invalid, missing, or non-two-decimal currency authority"}}}},"/companies/{companyId}/receivables/pipeline":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"getReceivablesPipeline","summary":"Contract-to-cash pipeline (last / this / next month)","description":"DARK — 404s unless ar_ap_items_enabled. months[3] each {key: YYYY-MM, label, contractedCents (active contracts' billable that month from cadence + per_invoice_cents), invoicedCents (non-void AR items issued that month), collectedCents (ar_item_payments in the month)}; plus totals across the three months, activeContractCount and totalContractedCents. The envelope carries currency and minorUnitExponent (null/null only when every returned monetary aggregate is empty).\n","tags":["Receivables"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"{ months[3], totals, activeContractCount, totalContractedCents, currency, minorUnitExponent }"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"AR/AP items not enabled for this company"},"422":{"description":"MONETARY_AGGREGATE_CURRENCY_UNAVAILABLE for mixed, invalid, missing, or non-two-decimal currency authority"}}}},"/companies/{companyId}/receivables/pipeline/periods":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"listReceivablesPipelinePeriods","summary":"Period-explorer months (default 11 back through 1 ahead)","tags":["Receivables"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"from","in":"query","schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"}},{"name":"to","in":"query","schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"}}],"responses":{"200":{"description":"{ from, to, periods: [{ key, label, monthIdx (0-based), year, isCurrent, isFuture, contractedCents, invoicedCents, collectedCents, contractCount }], currency, minorUnitExponent }"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"AR/AP items not enabled for this company"},"422":{"description":"Invalid range or unavailable homogeneous two-decimal currency authority"}}}},"/companies/{companyId}/receivables/pipeline/periods/{periodKey}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"periodKey","in":"path","required":true,"schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"getReceivablesPipelinePeriod","summary":"One period's contract rollup + invoices","description":"DARK — 404s unless ar_ap_items_enabled. Returns { period, contractRollup: { rows: [{ contract, funding }], remainingCents, openCount }, invoices }. Rows are the contracts billable in the month with their OVERALL funding rollups; invoices are the AR items issued in the month (any status — the explorer filters).\n","tags":["Receivables"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"{ period, contractRollup, invoices, currency, minorUnitExponent }"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"AR/AP items not enabled for this company"},"422":{"description":"Invalid period key or unavailable homogeneous two-decimal currency authority"}}}},"/companies/{companyId}/receivables/aging":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"getReceivablesAging","summary":"Interactive AR aging (buckets shared with /reports/ar-aging)","description":"DARK — 404s unless ar_ap_items_enabled. Buckets by due date with the SAME computeBucket boundaries (0/30/60/90 days past due) as the aging report so the two surfaces cannot drift. Amounts are outstanding cents. Items carry invoiceId, invoiceNumber, customerName, dueDate, daysOverdue, totalCents, outstandingCents, amountPaidCents, bucket, source. The aggregate and each item carry currency authority; an empty zero-value aggregate carries currency/minorUnitExponent as null/null.\n","tags":["Receivables"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"asOfDate","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"{ asOfDate, grandTotalCents, buckets[5]: { id, label, amountCents, count }, items, currency, minorUnitExponent, unlinkedAccountantEntries? }","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":true,"properties":{"unlinkedAccountantEntries":{"$ref":"#/components/schemas/UnlinkedAccountantEntries"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"AR/AP items not enabled for this company"},"422":{"description":"Invalid asOfDate or unavailable homogeneous two-decimal currency authority"}}}},"/companies/{companyId}/receivables/payment-settings":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getReceivablesPaymentSettings","summary":"Receivables payment settings (enabled methods + live Stripe Connect status)","description":"Wave 3b (#1153/#1154) + AR charge rail. DARK — 404s unless ar_ap_items_enabled. Returns the merchant-configurable collection methods (card via Stripe Connect, bank transfer / ACH-wire) plus the LIVE Stripe Connect onboarding status derived from stripe_connections — never a stored connected flag. Shape: { available, feeMode: absorb|pass, methods: { card: { enabled, connected, rail: \"stripe_connect\" }, bankTransfer: { enabled, detailsStatus: not_provided|pending|provided, instructions } }, bankAccount: { accountHolderName, bankName, routingNumber, accountNumber, accountType, swiftBic, wireInstructions }, stripeConnect: { status, connected, accountId (masked ****1234 or null), livemode, lastSyncAt }, updatedAt }. The bankAccount block is the structured receiving-account detail; the sensitive fields (routingNumber, accountNumber, swiftBic) are ALWAYS masked to ****1234 on read — clear values never leave the API on this surface. The public pay page offers bank transfer only when bankTransfer.enabled AND the four payer-required bankAccount fields (holder, bank, routing, account) are present.\n","tags":["Receivables"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"ReceivablesPaymentSettingsView"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"AR/AP items not enabled for this company"}}},"post":{"operationId":"updateReceivablesPaymentSettings","summary":"Update enabled payment methods and bank-transfer details","description":"Wave 3b (#1153/#1154) + AR charge rail. DARK — 404s unless ar_ap_items_enabled. Member role required. Merge-patch: send only the fields being changed; a provided null clears a clearable field. Enabling card is refused with 422 STRIPE_CONNECT_NOT_CONNECTED unless a Stripe account is actually linked, and with 422 STRIPE_ACCOUNT_CANNOT_CHARGE when the linked account's charges_enabled capability is not active (both fail-closed). bankTransfer.detailsStatus is derived: \"provided\" when instructions are present, else \"not_provided\". bankAccount fields are stored clear (the public pay page serves them to the payer) but ALWAYS masked ****1234 on the returned view. Returns the updated ReceivablesPaymentSettingsView (see GET for the shape incl. feeMode + bankAccount).\n","tags":["Receivables"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"card":{"type":"object","additionalProperties":false,"required":["enabled"],"properties":{"enabled":{"type":"boolean"}}},"feeMode":{"type":"string","enum":["absorb","pass"],"description":"Stored merchant preference for the card processing fee. Display/informational for now: the charge path FORCE-ABSORBS (the payer is charged the principal only) until pass-mode surcharge accounting ships.\n"},"bankTransfer":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"instructions":{"type":["string","null"],"maxLength":2000}}},"bankAccount":{"type":"object","additionalProperties":false,"description":"Structured receiving-account details, merged per-field onto the stored row (null clears a field). The public pay page requires accountHolderName + bankName + routingNumber + accountNumber before offering bank transfer.\n","properties":{"accountHolderName":{"type":["string","null"],"maxLength":200},"bankName":{"type":["string","null"],"maxLength":200},"routingNumber":{"type":["string","null"],"maxLength":64},"accountNumber":{"type":["string","null"],"maxLength":64},"accountType":{"type":["string","null"],"enum":["checking","savings",null]},"swiftBic":{"type":["string","null"],"maxLength":64},"wireInstructions":{"type":["string","null"],"maxLength":2000}}}}}}}},"responses":{"200":{"description":"Updated ReceivablesPaymentSettingsView (feeMode + masked bankAccount included)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"AR/AP items not enabled for this company"},"422":{"description":"STRIPE_CONNECT_NOT_CONNECTED (card enabled without a linked Stripe account), STRIPE_ACCOUNT_CANNOT_CHARGE (linked account cannot charge), or invalid body"}}}},"/companies/{companyId}/receivables/payment-settings/stripe-charge":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"delete":{"operationId":"disableReceivablesStripeChargeRail","summary":"Stop accepting card payments (scoped charge-rail unlink)","description":"AR charge rail (D8 / audit #24). DARK — 404s unless ar_ap_items_enabled. Member role required. Turns the card charge rail OFF WITHOUT severing the Stripe integration: clears card_payments_enabled on receivables_payment_settings only. The stripe_connections row — and the transaction archive it anchors — is NEVER deleted or nulled (that would CASCADE the archive away). Bank transfer, the structured bank details, and feeMode are all preserved. Idempotent (a company with card already off is a no-op). Returns the updated ReceivablesPaymentSettingsView (same shape as GET payment-settings), with methods.card.enabled = false and stripeConnect still reporting the intact linkage.\n","tags":["Receivables"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Updated ReceivablesPaymentSettingsView (card disabled; Stripe connection untouched)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"AR/AP items not enabled for this company"}}}},"/companies/{companyId}/receivables/stripe-connect/onboarding-link":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"createReceivablesStripeConnectOnboardingLink","summary":"Hosted Stripe Connect onboarding link for receivables collection","description":"Wave 3b (#1153/#1154). DARK — 404s unless ar_ap_items_enabled. Member role required. Reuses the existing Stripe App install-link plumbing (no hand-rolled Stripe); webhook/callback completion of that flow flips stripe_connections.status, which the next GET payment-settings reflects. Returns { onboardingUrl }. Responds 503 STRIPE_INSTALL_NOT_CONFIGURED when the Stripe install flow is not configured for the environment.\n","tags":["Receivables"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"entityId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"{ onboardingUrl }"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"AR/AP items not enabled for this company"},"503":{"description":"STRIPE_INSTALL_NOT_CONFIGURED — Stripe install flow not configured"}}}},"/public/invoices/{token}":{"parameters":[{"name":"token","in":"path","required":true,"description":"The 192-bit URL-safe payment token minted at invoice send. It is the SOLE capability handle — these routes are unauthenticated and not company-scoped by URL; the server derives the company scope and dark gate from the token.\n","schema":{"type":"string"}}],"get":{"operationId":"getPublicInvoiceByToken","summary":"Public pay-page view for an invoice payment token (unauthenticated)","description":"AR charge rail (Stage 2). UNAUTHENTICATED; rate-limited per-IP and per-token. Resolves the token to the pay-page view: { merchant: { name, supportEmail? }, invoice: { number, issueDate, dueDate, terms, currency, subtotalCents, taxCents, totalCents, amountPaidCents, amountDueCents, status: open|partially_paid|paid, lines }, methods: { card: { available, feeMode, feeCents, amountToChargeCents }, bankTransfer: { available, details } } }. bankTransfer.details is the FULL (unmasked) structured bank block — the payer needs it to push an ACH/wire — and is non-null only when bank transfer is enabled AND the payer-required fields (holder, bank, routing, account) are all present. UNIFORM-404 SEMANTICS: an unknown/blank token, a draft/void/uncollectible invoice, a closed AR/AP surface, or a non-allowlisted/non-active company ALL return the same 404 shape so the endpoint never leaks whether a token, company, or invoice exists.\n","tags":["Public"],"security":[],"responses":{"200":{"description":"PublicInvoiceView (see description for shape)"},"404":{"description":"Uniform not-found — identical for every rejection branch (no enumeration oracle)"},"429":{"description":"Rate limited (per-IP or per-token)"}}}},"/public/invoices/{token}/payment-intent":{"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"createPublicInvoicePaymentIntent","summary":"Create a TEST-mode Stripe PaymentIntent for the invoice (unauthenticated)","description":"AR charge rail (Stage 3 — TEST MODE ONLY). UNAUTHENTICATED; rate-limited per-IP and per-token. The request body is EMPTY and ignored: the amount is SERVER-authoritative (outstanding = amount − paid; force-absorb means the payer is charged the principal only), and no caller-supplied field reaches the intent — the idempotency key is a pure function of (token, outstanding), so one pay link yields at most ONE PaymentIntent. (The payer's card receipt is set browser-side at confirm time via Stripe's `receipt_email`.) Returns { clientSecret, publishableKey (TEST), connectedAccountId, amountChargedCents } for Stripe.js; the card is tokenized in-browser and PAN/CVC never reach this API. Marks nothing paid — settlement is the signature-verified Stage-4 webhook. Same uniform-404 token gate as the GET.\n","tags":["Public"],"security":[],"responses":{"200":{"description":"{ clientSecret, publishableKey, connectedAccountId, amountChargedCents }"},"404":{"description":"Uniform not-found (same semantics as GET)"},"409":{"description":"INVOICE_NOT_PAYABLE — already paid or no outstanding balance"},"422":{"description":"STRIPE_ACCOUNT_CANNOT_CHARGE — card rail unavailable (disabled toggle or the connected account cannot charge right now)"},"429":{"description":"Rate limited (per-IP or per-token)"},"503":{"description":"Card charging is not configured on this deployment"}}}},"/public/invoices/{token}/bank-transfer-initiated":{"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"acknowledgePublicInvoiceBankTransfer","summary":"Payer soft signal that a bank transfer was sent (unauthenticated)","description":"AR charge rail (Stage 5). UNAUTHENTICATED; rate-limited per-IP and per-token. Records ONE durable ach/pending invoice_payments row (amount = outstanding at signal time; repeated clicks are a no-op) so the merchant can see the claim. It NEVER marks the invoice paid and NEVER changes lifecycle status — the merchant reconciles the real deposit. The response is identical whether or not a row was written. Same uniform-404 token gate as the GET.\n","tags":["Public"],"security":[],"responses":{"200":{"description":"{ acknowledged: true }"},"404":{"description":"Uniform not-found (same semantics as GET)"},"429":{"description":"Rate limited (per-IP or per-token)"}}}},"/companies/{companyId}/ap":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"listApItems","summary":"List AP (bill) items","description":"DARK — 404s unless company_subledger_flags.ar_ap_items_enabled is true. Every item includes ledgerStatus (posted|unposted) and ledgerStatusReason. Unposted intake is not a booked AP liability and must be excluded from financial summary and recognition totals.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string"}},{"name":"vendorId","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of AP items"},"404":{"description":"AR/AP items not enabled for this company"}}},"post":{"operationId":"createApItem","summary":"Create a manual AP item","description":"Creates real AP intake. The response is ledgerStatus=unposted until a posting flow links a currently posted journal entry; unposted intake is not a booked liability.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"AP item created"},"404":{"description":"AR/AP items not enabled for this company"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/ap/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"getApItem","summary":"Get an AP item (includes availableTransitions and ledger authority)","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"AP item detail with availableTransitions"},"404":{"description":"Not found or AR/AP not enabled"}}},"patch":{"operationId":"patchApItem","summary":"Edit non-status fields of an AP item","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"AP item updated"},"404":{"description":"Not found or AR/AP not enabled"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/ap/{id}/document":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"post":{"operationId":"attachApDocument","summary":"Attach a document to an AP item","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Document attached"},"404":{"description":"Not found or AR/AP not enabled"}}},"delete":{"operationId":"detachApDocument","summary":"Detach the document from an AP item","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Document detached"},"404":{"description":"Not found or AR/AP not enabled"}}}},"/companies/{companyId}/ap/{id}/transitions":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"post":{"operationId":"transitionApItem","summary":"Apply a customer workflow transition to an AP item","description":"DARK — 404s unless company_subledger_flags.ar_ap_items_enabled is true. Workflow-only customer state machine (Wave 2, Option A); no money moves and no journal entry is posted. `scheduled` records a payment-intent date (requires scheduledPayDate); `unscheduled` cancels that intent; `recorded_paid` is a fail-closed reflection of an already-applied bank match that covers the bill (requires matchedTransactionId) and never touches the reconciled transaction. The response echoes the updated item plus its recomputed availableTransitions.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["to"],"properties":{"to":{"type":"string","enum":["scheduled","unscheduled","recorded_paid","void"]},"scheduledPayDate":{"type":"string","format":"date","description":"Required when to=scheduled (YYYY-MM-DD)."},"matchedTransactionId":{"type":"string","format":"uuid","description":"Required when to=recorded_paid."},"reason":{"type":["string","null"],"maxLength":2000,"description":"Optional reason; recorded on void (terminal cancellation) and recorded_paid.\n"}}}}}},"responses":{"200":{"description":"Transition applied; returns the AP item (with availableTransitions). `void` is a terminal cancellation delegating to the FSM void edge (open/partially_paid/paid → void); no money moves and the customer is offered no re-open target.\n"},"403":{"description":"Insufficient role for this company/entity"},"404":{"description":"Not found, or AR/AP not enabled for this company"},"409":{"description":"AP_ITEM_STATE_CHANGED — the item moved to a different state before the transition could be applied (optimistic-concurrency conflict).\n"},"422":{"description":"Validation or business-rule failure — VALIDATION_ERROR, BUSINESS_RULE_VIOLATION, ILLEGAL_AP_TRANSITION, or ILLEGAL_AP_PAY_STATE_TRANSITION.\n"}}}},"/companies/{companyId}/ap/transitions/batch":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"post":{"operationId":"batchTransitionApItems","summary":"Apply customer workflow transitions to multiple AP items","description":"DARK — 404s unless company_subledger_flags.ar_ap_items_enabled is true. Per-item atomic batch of the single-item transition (1..100 items, no duplicate itemIds). Returns 200 even on mixed outcomes — each entry in `results` carries its own `ok` flag and one item's failure never aborts a sibling. Envelope-level failures (auth, validation, entity authority) still surface as non-200.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["transitions"],"properties":{"transitions":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"object","additionalProperties":false,"required":["itemId","to"],"properties":{"itemId":{"type":"string","format":"uuid"},"to":{"type":"string","enum":["scheduled","unscheduled","recorded_paid","void"]},"scheduledPayDate":{"type":"string","format":"date","description":"Required when to=scheduled (YYYY-MM-DD)."},"matchedTransactionId":{"type":"string","format":"uuid","description":"Required when to=recorded_paid."},"reason":{"type":["string","null"],"maxLength":2000}}}}}}}}},"responses":{"200":{"description":"Batch processed; returns { results: [...] } where each entry is { itemId, ok: true, item } (item includes availableTransitions) or { itemId, ok: false, error: { code, message } }.\n"},"403":{"description":"Insufficient role for this company/entity"},"404":{"description":"AR/AP not enabled for this company"},"422":{"description":"Validation error on the batch envelope (VALIDATION_ERROR)"}}}},"/companies/{companyId}/ap/recognition/timeline":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"apRecognitionTimeline","summary":"Forward expense recognition by month across posted AP items","description":"DARK — 404s unless company_subledger_flags.ar_ap_items_enabled is true. Server-authoritative aggregation of the company's posted AP recognition by month; unposted intake is excluded (not a booked liability). Returns [{ offset, label, amountCents }] where offset 0 is the current month, negatives are past, positives are scheduled. Window defaults to 1 month back / 6 ahead (monthsBack / monthsAhead, each 0..24).\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"monthsBack","in":"query","schema":{"type":"integer","minimum":0,"maximum":24}},{"name":"monthsAhead","in":"query","schema":{"type":"integer","minimum":0,"maximum":24}}],"responses":{"200":{"description":"Forward-expense-by-month points"},"404":{"description":"AR/AP items not enabled for this company"}}}},"/companies/{companyId}/ap/{id}/match-candidates":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"listApMatchCandidates","summary":"List unreconciled bank-transaction candidates for a bill","description":"DARK — 404s unless company_subledger_flags.ar_ap_items_enabled is true. Reuses the shared document match ranker to score already-ingested, unreconciled bank transactions by amount / date-window / vendor against this bill's linked document. Entity-scoped; an item with no linked document (or nothing matchable yet) returns an honest empty array.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"query","in":"query","schema":{"type":"string","maxLength":200}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":25}}],"responses":{"200":{"description":"Ranked candidate transactions (possibly empty)"},"404":{"description":"Not found or AR/AP not enabled"}}}},"/companies/{companyId}/ap/{id}/match":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"post":{"operationId":"matchApItem","summary":"Match a bank transaction to a bill and reflect its pay state","description":"DARK — 404s unless company_subledger_flags.ar_ap_items_enabled is true. Creates the applied document_match through the production bill-payment apply path (idempotent, reconciliation-lock safe — never touches a reconciled transaction/JE), then reflects the AP pay state via the existing fail-closed recompute. A covering match settles the bill to paid; a partial one leaves it partially_paid. Re-POST of the same pair converges to the same state rather than a conflict.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["transactionId"],"properties":{"transactionId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"AP item after the match (with availableTransitions)"},"403":{"description":"Insufficient role for this company/entity"},"404":{"description":"Not found or AR/AP not enabled"},"422":{"description":"Validation or business-rule failure"}}}},"/companies/{companyId}/ap/{id}/match-coverage":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"getApMatchCoverage","summary":"Aggregate applied bank-match coverage for a bill","description":"DARK — 404s unless company_subledger_flags.ar_ap_items_enabled is true. Server-authoritative evidence the record-paid control gates on: `coveredCents` is the SUM of every applied document_match allocation against this bill's linked document, counted once per transaction, so a bill settled by several partial payments reports `fullyCovered: true`. Fails closed to zero coverage when the bill has no linked document. Deliberately served here rather than from the documents match-proposal read, which is gated by the unrelated intelligence-home flag.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"{ amountCents, coveredCents, fullyCovered, matches: [{ transactionId, amountCents }] }\n"},"404":{"description":"Not found or AR/AP not enabled"}}}},"/companies/{companyId}/ap/{id}/recognition":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"getApItemRecognition","summary":"Server-authoritative recognition for one AP item","description":"DARK — 404s unless company_subledger_flags.ar_ap_items_enabled is true. Returns { treatment, monthlyCents, recognizedToDateCents, remainingCents, totalCents, schedule[{ month, amountCents, posted }] }. Treatment and the monthly split are derived from the item's service period; posted flags and recognized-to-date come strictly from the ledger (posted amortization runs, else the item's ledger-posted authority) — never client-computed.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Recognition summary with per-month posted schedule"},"404":{"description":"Not found or AR/AP not enabled"}}}},"/companies/{companyId}/customers":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"listCustomers","summary":"List customers","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of customers"},"404":{"description":"AR/AP items not enabled for this company"}}},"post":{"operationId":"createCustomer","summary":"Create a customer","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Customer created"},"404":{"description":"AR/AP items not enabled for this company"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/customers/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"getCustomer","summary":"Get a customer","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Customer detail"},"404":{"description":"Not found or AR/AP not enabled"}}},"patch":{"operationId":"updateCustomer","summary":"Update a customer","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Customer updated"},"404":{"description":"Not found or AR/AP not enabled"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteCustomer","summary":"Soft-delete a customer (is_active=false)","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Customer deactivated"},"404":{"description":"Not found or AR/AP not enabled"}}}},"/companies/{companyId}/vendors":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"listVendors","summary":"List vendors (bare records; rollups live on the detail read)","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of vendors (no rollup fields)"},"404":{"description":"AR/AP items not enabled for this company"}}},"post":{"operationId":"createVendor","summary":"Create a vendor","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Vendor created"},"404":{"description":"AR/AP items not enabled for this company"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/vendors/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"getVendor","summary":"Get a vendor (with bills + outstanding/billCount/lifetimeSpend rollup)","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Vendor detail with bills and server-computed rollup"},"404":{"description":"Not found or AR/AP not enabled"}}},"patch":{"operationId":"updateVendor","summary":"Update a vendor","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Vendor updated"},"404":{"description":"Not found or AR/AP not enabled"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteVendor","summary":"Soft-delete a vendor (is_active=false)","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Vendor deactivated"},"404":{"description":"Not found or AR/AP not enabled"}}}},"/accountant/companies/{customerId}/ar/{id}/status":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/qaAppSurface"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"accountantUpdateArStatus","summary":"Change an AR item's lifecycle status (FSM-enforced)","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Status changed"},"404":{"description":"Not found or AR/AP not enabled"},"409":{"description":"Stripe-source item is status-locked"},"422":{"description":"Illegal transition"}}}},"/accountant/companies/{customerId}/ar/{id}/deferral":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/qaAppSurface"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"accountantGenerateArDeferral","summary":"Generate/regenerate an AR deferred-revenue schedule","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Schedule generated"},"404":{"description":"Not found or AR/AP not enabled"},"422":{"description":"Validation error"}}}},"/accountant/companies/{customerId}/ap/{id}/status":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/qaAppSurface"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"accountantUpdateApStatus","summary":"Change an AP item's lifecycle status (FSM-enforced)","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Status changed"},"404":{"description":"Not found or AR/AP not enabled"},"422":{"description":"Illegal transition"}}}},"/accountant/companies/{customerId}/ap/{id}/deferral":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/qaAppSurface"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"accountantGenerateApDeferral","summary":"Generate/regenerate an AP prepaid-amortization schedule","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Schedule generated"},"404":{"description":"Not found or AR/AP not enabled"},"422":{"description":"Validation error"}}}},"/accountant/companies/{customerId}/ap/{id}/schedule-payment":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/qaAppSurface"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"accountantScheduleApPayment","summary":"Record an accountant-approved AP payment intent","description":"Persists a future payment date and pay-state only. This endpoint does not move money or call a payment provider; bank matching remains the source of truth for payment settlement.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["scheduledPayDate"],"properties":{"scheduledPayDate":{"type":"string","format":"date"}}}}}},"responses":{"200":{"description":"Payment intent scheduled"},"404":{"description":"Not found or AR/AP not enabled"},"422":{"description":"Invalid date or terminal AP item"}}},"delete":{"operationId":"accountantCancelApPayment","summary":"Cancel an unexecuted AP payment intent","tags":["AR/AP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Payment intent canceled"},"404":{"description":"Not found or AR/AP not enabled"},"422":{"description":"Payment intent cannot be canceled"}}}},"/accountant/companies/{customerId}/close-blockers/{blockerId}/resolve":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"blockerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"accountantResolveCloseBlocker","summary":"Resolve a close blocker with server-verified evidence","description":"Marks a close_blockers row resolved. Warn-severity blockers accept a plain acknowledgement. Block-severity blockers resolve only when the server re-verifies the evidence itself (#1911): an applied/rejected transfer match for the pair, both legs categorized to Transfer Clearing (1080) netting to zero, an explicit `not_a_transfer` disposition (persisted as a rejected transfer match so the audit never re-raises the pair), or a live clearing balance of exactly zero. Block-severity resolves require notes of at least 10 trimmed characters and record the resolving user. A `clearing_residual` blocker (GL integrity I23) resolves only as an acknowledgement (J-358): notes of at least 10 trimmed characters as the reason and a `reviewAfter` date later than today. I23 re-surfaces it on that date and opens a new blocker when the residual changes. Other kinds reject `reviewAfter`.\n","tags":["Month-End Close"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"notes":{"type":"string","maxLength":2000},"disposition":{"type":"string","enum":["not_a_transfer"]},"reviewAfter":{"type":"string","format":"date","description":"Acknowledgement review date (clearing_residual only)."}}}}}},"responses":{"200":{"description":"Blocker resolved"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Close blocker not found"},"422":{"description":"Notes missing/too short, review date missing/past or not allowed for the kind, or the evidence check failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/month-end-close/batch-lock":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"accountantBatchLockMonthEndClose","summary":"Close consecutive GL periods in sequence (batch month-end lock)","description":"Closes each supplied period in order — the same closing-entry and retained-earnings effect as the single gl-periods close, applied per period. Aborts on the first failure (including any unresolved block-severity close blocker) and returns the per-period status so the caller can see which period broke. Signed-in accountants only: the service API key cannot use the batch lock (#2411); it closes one period at a time through the single gl-periods close.\n","tags":["Month-End Close"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["periodIds"],"properties":{"periodIds":{"type":"array","minItems":1,"items":{"type":"string","format":"uuid"}}}}}}},"responses":{"200":{"description":"Per-period close results; allClosed is false when the sequence aborted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"allClosed":{"type":"boolean"},"results":{"type":"array","items":{"type":"object","properties":{"periodId":{"type":"string","format":"uuid"},"closed":{"type":"boolean"},"reason":{"type":"string"},"closingEntryId":{"type":["string","null"],"format":"uuid"}}}}}}}}}}},"400":{"description":"periodIds missing or not a non-empty array of string IDs"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/accountant/companies/{customerId}/sub-ledgers/revenue":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetSubLedgerRevenue","summary":"Revenue sub-ledger view (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/sub-ledgers/revenue`. Same payload for the same company; requires the accountant to be assigned to the customer (403 otherwise). All amounts in cents. Posted-only.\n","tags":["Sub-Ledgers"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/reportStartDate"},{"$ref":"#/components/parameters/reportEndDate"},{"$ref":"#/components/parameters/reportEntityId"}],"responses":{"200":{"description":"Revenue sub-ledger payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/SubLedgerRevenueView"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Invalid query parameters (missing or malformed date range)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/sub-ledgers/expenses":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetSubLedgerExpenses","summary":"Expenses sub-ledger view (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/sub-ledgers/expenses`. Same payload for the same company; requires the accountant to be assigned to the customer (403 otherwise). All amounts in cents. Posted-only.\n","tags":["Sub-Ledgers"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/reportStartDate"},{"$ref":"#/components/parameters/reportEndDate"},{"$ref":"#/components/parameters/reportEntityId"}],"responses":{"200":{"description":"Expenses sub-ledger payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/SubLedgerExpensesView"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Invalid query parameters (missing or malformed date range)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/sub-ledgers/assets":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetSubLedgerAssets","summary":"Assets sub-ledger view (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/sub-ledgers/assets`. Same payload shape for the same company; requires the accountant to be assigned to the customer (403 otherwise). Unlike the customer route (which reads today's balances, #2411), balance-sheet figures here use the last closed GL period, and `asOf` is that period's end date or null. All amounts in cents. Posted-only.\n","tags":["Sub-Ledgers"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/reportEntityId"}],"responses":{"200":{"description":"Assets sub-ledger payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/SubLedgerAssetsView"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/accountant/companies/{customerId}/sub-ledgers/liabilities":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetSubLedgerLiabilities","summary":"Liabilities sub-ledger view (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/sub-ledgers/liabilities`. Same payload shape for the same company; requires the accountant to be assigned to the customer (403 otherwise). Unlike the customer route (which reads today's balances, #2411), balance-sheet figures here use the last closed GL period, and `asOf` is that period's end date or null. All amounts in cents. Posted-only.\n","tags":["Sub-Ledgers"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/reportEntityId"}],"responses":{"200":{"description":"Liabilities sub-ledger payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/SubLedgerLiabilitiesView"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/accountant/companies/{customerId}/overview":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetCustomerOverview","summary":"Customer Home overview (accountant mirror)","description":"Accountant-scoped read-only mirror of `GET /companies/{companyId}/overview` — the same service, so the accountant sees exactly the numbers the customer's Home board shows. Requires assignment to the customer (403 otherwise). Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE. With a concrete entity resolved, the overview's non-blocking balance refreshers never fire, so this read is side-effect-free.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/homeEntityId"},{"$ref":"#/components/parameters/reportStartDate"},{"$ref":"#/components/parameters/reportEndDate"},{"name":"months","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":12,"default":6}}],"responses":{"200":{"description":"Overview payload (same shape as the customer mount)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OverviewResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown customer or an explicit entityId not belonging to the customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/overview/autonomous-impact":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetCustomerAutonomousImpact","summary":"Customer autonomous-impact recap (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/overview/autonomous-impact`. Same payload for the same company and period (`this_month` | `last_month`). Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/homeEntityId"},{"name":"period","in":"query","required":false,"schema":{"type":"string","enum":["this_month","last_month"],"default":"this_month"}}],"responses":{"200":{"description":"Autonomous-impact payload (same shape as the customer mount)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutonomousImpactResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown customer or an explicit entityId not belonging to the customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/metrics/mrr-state":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetCustomerMrrCurrentState","summary":"Customer current MRR state (accountant mirror)","description":"Accountant mirror of the company current-MRR read. An explicit entityId must be one of the customer's concrete entities; absent, the sole concrete entity is selected. Multiple entities require selection (422 ENTITY_SELECTION_REQUIRED); no concrete entity returns 422 ENTITY_SCOPE_UNAVAILABLE. Returns a persisted current recurring run-rate revision, separate from completed-month MRR and movement history. This read performs no provider requests, refresh, publication or financial writes. enabled is presentation permission, not evidence of freshness. An unavailable or withheld current value is null, never fabricated zero. No historical coverage is inferred. Responses use Cache-Control private, no-store.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"entityId","in":"query","required":false,"description":"Concrete legal entity in the authorized company scope.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Current state, freshness metadata and separately unavailable history.","headers":{"Cache-Control":{"schema":{"type":"string","const":"private, no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MrrCurrentStateResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Current-state service is unavailable, or the selected company/entity does not exist in scope."},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"Legal-entity scope or current-state read authority could not be established."}}}},"/accountant/companies/{customerId}/metrics/saas":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetCustomerSaasMetrics","summary":"Customer SaaS metrics envelope (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/metrics/saas`. Unlike the customer mount, `entityId` is optional here — it defaults to the customer's single concrete entity. Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/homeEntityId"},{"name":"asOf","in":"query","required":false,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"SaaS metrics envelope (same shape as the customer mount)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaasMetricsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown customer or an explicit entityId not belonging to the customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/metrics/mrr-movements":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetCustomerMrrMovements","summary":"Customer MRR movements history (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/metrics/mrr-movements`. Unlike the customer mount, `entityId` is optional here — it defaults to the customer's single concrete entity. Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/homeEntityId"},{"name":"months","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":24,"default":12}}],"responses":{"200":{"description":"MRR movements envelope (same shape as the customer mount)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MrrMovementsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown customer or an explicit entityId not belonging to the customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/metrics/cash-history":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetCustomerCashHistory","summary":"Customer posted-books cash series (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/metrics/cash-history`. Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/homeEntityId"},{"name":"months","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":24,"default":6}}],"responses":{"200":{"description":"Cash-history envelope (same shape as the customer mount)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashHistoryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown customer or an explicit entityId not belonging to the customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/metrics/revenue-mix":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetCustomerRevenueMix","summary":"Customer revenue-mix card (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/metrics/revenue-mix` — the same service, so the accountant sees the numbers the customer's Home revenue-mix card shows. Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/homeEntityId"}],"responses":{"200":{"description":"Revenue-mix payload (same shape as the customer mount)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueMixResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown customer or an explicit entityId not belonging to the customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/metrics/revenue-by-client":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetCustomerRevenueByClient","summary":"Customer revenue-by-client card (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/metrics/revenue-by-client`. Same payload for the same company and window; non-attributable revenue stays in `otherCents`, never invented per client. Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/homeEntityId"},{"name":"months","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":12,"default":6}}],"responses":{"200":{"description":"Revenue-by-client payload (same shape as the customer mount)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueByClientResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown customer or an explicit entityId not belonging to the customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/metrics/cash-by-entity":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetCustomerCashByEntity","summary":"Customer cash-by-entity card (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/metrics/cash-by-entity`. Inherently cross-entity (no `entityId` param): rows cover the customer's full non-group entity roster — the accountant's company-wide read authority stands in for the per-user entity grants the customer mount filters by. Same honesty gates as the customer mount: `available:false` with reason `single_entity` for single-entity customers and `no_cash_accounts` when no cash accounts exist.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Cash-by-entity envelope (same shape as the customer mount)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashByEntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown customer"}}}},"/accountant/companies/{customerId}/metrics/burn-runway":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"accountantGetCustomerBurnRunway","summary":"Customer burn headline and runway composite (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/metrics/burn-runway`. Same service, same honesty gates (one-third uncategorized refusal, etc). Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Burn and runway payload (same shape as the customer mount)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BurnRunwayResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/metrics/daily-trends":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"accountantGetCustomerDailyTrends","summary":"Customer daily Runway and Receivables lines (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/metrics/daily-trends`. Same service, same fail-closed reasons. Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Daily trend lines (same shape as the customer mount)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DailyTrendsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/insights/home":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetCustomerHomeInsights","summary":"Customer Home insights card (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/insights/home`. Same readiness gate as the customer surface (`available:false` with a reason until enough closed months exist). Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/homeEntityId"}],"responses":{"200":{"description":"Home-insights payload (same shape as the customer mount)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HomeInsightsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown customer or an explicit entityId not belonging to the customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/action-items":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetCustomerActionItems","summary":"Customer action-items queue (accountant mirror, read-only)","description":"Accountant-scoped read-only mirror of `GET /companies/{companyId}/action-items` — the customer's open work queue (uncategorized transactions, unmatched documents, overdue invoices, bills due soon, open threads). Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/homeEntityId"}],"responses":{"200":{"description":"Same payload as the customer mount: { available: true, items: [{ id, kind, count, totalCents, label }] }"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown customer or an explicit entityId not belonging to the customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/books-status":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetCustomerBooksStatus","summary":"Customer books status (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/books-status`. Company-level (no entity scope, like the customer mount); carries the same derived `displayLabel` the customer surface computes on read.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Books-status payload (same shape as the customer mount)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BooksStatusResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown customer"}}}},"/accountant/companies/{customerId}/overview/activity-summary":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetCustomerActivitySummary","summary":"Customer recent bookkeeping activity (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/overview/activity-summary`. Same counts for the same window (`days` clamped 1-90, default 7). Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/homeEntityId"},{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":90,"default":7}}],"responses":{"200":{"description":"Entity-scoped activity payload (same shape as the customer mount)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OverviewActivitySummaryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown customer or an explicit entityId not belonging to the customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/receivables/summary":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"accountantGetCustomerReceivablesSummary","summary":"Customer receivables summary (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/receivables/summary`. Same conversion gate as the customer surface (404 unless ar_ap_items_enabled), without the customer-app demo-parity allowlist — parity with the sub-ledgers mirror. Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["Receivables"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Same payload as the customer mount: { overdue, dueSoon, current, outstanding, currency, minorUnitExponent }; figures are { amountCents, count }"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"AR/AP items not enabled for this customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/receivables/pipeline":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"accountantGetCustomerReceivablesPipeline","summary":"Customer contract-to-cash pipeline (accountant mirror)","description":"Accountant-scoped mirror of `GET /companies/{companyId}/receivables/pipeline`. Same conversion gate as the customer surface (404 while dark). Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["Receivables"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Same payload as the customer mount: months[3] with contracted/invoiced/collected cents + totals"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"AR/AP items not enabled for this customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/ap":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"accountantListCustomerApItems","summary":"Customer AP bill list (accountant mirror, read-only)","description":"Accountant-scoped read-only mirror of `GET /companies/{companyId}/ap` (bill read models; the open-bills totals the customer app derives are computed from the same rows). Same conversion gate (404 while dark). Optional `status` and `vendorId` filters as on the customer mount. Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"vendorId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Same payload as the customer mount: ApItem read models"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"AR/AP items not enabled for this customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/customers":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/financialEntityId"}],"get":{"operationId":"accountantListCustomerRecords","summary":"Customer's customer records (accountant mirror, read-only)","description":"Accountant-scoped read-only mirror of `GET /companies/{companyId}/customers` (the customer count / top-customers rollup on the customer Home derives from these rows). Same conversion gate (404 while dark). Optional `includeInactive` as on the customer mount. Entity scope is resolved from the customer's own entity roster (accountants hold no per-user entity grants): an explicit `entityId` must be one of the customer's concrete (non-group) entities; absent, the customer's single concrete entity is used; a multi-entity customer without `entityId` gets 422 ENTITY_SELECTION_REQUIRED and a customer with no entity gets 422 ENTITY_SCOPE_UNAVAILABLE.\n","tags":["AR/AP"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"includeInactive","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Same payload as the customer mount: customer records"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"AR/AP items not enabled for this customer"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/gl-accounts":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listGlAccounts","summary":"List GL accounts (chart of accounts)","tags":["GL Accounts"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"type","in":"query","schema":{"type":"string","enum":["Asset","Liability","Equity","Revenue","Expense"]}},{"name":"isActive","in":"query","schema":{"type":"string","enum":["true","false"]}},{"name":"limit","in":"query","description":"Maximum GL accounts to return. Defaults high enough to avoid truncating normal charts of accounts.","schema":{"type":"integer","minimum":1,"maximum":5000,"default":5000}},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Paginated list of GL accounts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlAccountsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createGlAccount","summary":"Create a GL account","tags":["GL Accounts"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGlAccountInput"}}}},"description":"Creates a GL account, audited with the acting user. An exact replay (#2883) — an active account with the same code whose name, type, detail type, subtype, parent and normal balance all match the request — returns that account with 200 and writes nothing. A same-code request that differs is a 409 GL_ACCOUNT_CODE_CONFLICT naming the fields; a code held by a retired account is a 409 GL_ACCOUNT_CODE_RETIRED.","responses":{"200":{"description":"Exact replay; the existing GL account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlAccountResponse"}}}},"201":{"description":"GL account created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlAccountResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Account code already exists with different fields (GL_ACCOUNT_CODE_CONFLICT) or belongs to a retired account (GL_ACCOUNT_CODE_RETIRED)"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/gl-accounts/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getGlAccount","summary":"Get a GL account by ID","tags":["GL Accounts"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"GL account found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlAccountResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"GL account not found"}}},"patch":{"operationId":"updateGlAccount","summary":"Update a GL account","tags":["GL Accounts"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGlAccountInput"}}}},"responses":{"200":{"description":"GL account updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlAccountResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"GL account not found"},"422":{"description":"Validation error"}}},"delete":{"operationId":"softDeleteGlAccount","summary":"Soft-delete a GL account (set inactive)","tags":["GL Accounts"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"GL account deactivated"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"GL account not found"}}}},"/companies/{companyId}/gl-accounts/{id}/monetary-classification":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"},{"$ref":"#/components/parameters/qaAppSurface"}],"patch":{"operationId":"classifyGlAccountMonetaryQa","summary":"Record an audited monetary decision (QA test companies only)","description":"Requires an allowlisted test company, the QA application marker, and company role admin or owner. Unknown foreign-balance accounts block revaluation until this explicit decision exists.\n","tags":["GL Accounts"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["isMonetary"],"properties":{"isMonetary":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Classification recorded with actor and timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlAccountResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Hidden outside QA, or account not found"},"422":{"description":"Only Asset and Liability accounts may be manually classified"}}}},"/companies/{companyId}/bank-accounts":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listBankAccounts","summary":"List bank accounts","tags":["Bank Accounts"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","description":"Concrete legal-entity owner to list","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","schema":{"type":"string","enum":["active","disconnected","error"]}},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Paginated list of bank accounts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BankAccountsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createBankAccount","summary":"Register a bank account","tags":["Bank Accounts"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBankAccountInput"}}}},"responses":{"201":{"description":"Bank account created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BankAccountResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Invite email already belongs to an active company member"},"422":{"description":"Validation error"},"429":{"description":"Outstanding invite was sent recently; wait before resending"}}}},"/companies/{companyId}/bank-accounts/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getBankAccount","summary":"Get a bank account by ID","tags":["Bank Accounts"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Bank account found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BankAccountResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Bank account not found"}}},"patch":{"operationId":"updateBankAccount","summary":"Update a bank account","tags":["Bank Accounts"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBankAccountInput"}}}},"responses":{"200":{"description":"Bank account updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BankAccountResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Bank account not found"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteBankAccount","summary":"Delete a bank account","tags":["Bank Accounts"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Bank account deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Bank account not found"},"409":{"description":"Bank account has linked transactions"}}}},"/companies/{companyId}/transactions":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listTransactions","summary":"List transactions with filters","tags":["Transactions"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","description":"Concrete legal entity. `consolidated` requires all-entity access; omitted scopes to the actor's grants.","schema":{"oneOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["consolidated"]}]}},{"name":"status","in":"query","schema":{"type":"string","enum":["needs_review","categorized"]}},{"name":"direction","in":"query","schema":{"type":"string","enum":["in","out"]}},{"name":"dateFrom","in":"query","schema":{"type":"string","format":"date"}},{"name":"dateTo","in":"query","schema":{"type":"string","format":"date"}},{"name":"bankAccountId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"sourceProvider","in":"query","description":"Source provider filter. Distinct from category filters.","schema":{"type":"string","minLength":1,"maxLength":80}},{"name":"sourceAccountId","in":"query","description":"Integration account or bank account source filter. Distinct from categoryGlAccountId. Accepts a single UUID, comma-separated UUIDs, or repeated params (OR semantics within dimension; max 50).\n","style":"form","explode":true,"schema":{"oneOf":[{"type":"string","format":"uuid"},{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50}]}},{"name":"categoryGlAccountId","in":"query","description":"GL account category filter. Distinct from sourceAccountId. Accepts a single UUID, comma-separated UUIDs, or repeated params (OR semantics within dimension; max 50).\n","style":"form","explode":true,"schema":{"oneOf":[{"type":"string","format":"uuid"},{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50}]}},{"name":"classId","in":"query","description":"Accounting class filter. Distinct from categoryGlAccountId.","schema":{"type":"string","format":"uuid"}},{"name":"tagId","in":"query","description":"Accounting tag filter (#1166). Comma-separated or repeated; a transaction matches when it carries ANY listed tag. ORed with `untagged`, ANDed with every other filter. An existence test, so a transaction with several selected tags appears once.\n","schema":{"oneOf":[{"type":"string","format":"uuid"},{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50}]}},{"name":"untagged","in":"query","description":"When `true`, include transactions with no tag (ORed with `tagId`).","schema":{"type":"string","enum":["true","false"]}},{"name":"categoryState","in":"query","description":"Filters transactions by category assignment state. `uncategorized` keeps meaning \"null category only\" and ANDs with the other filters (with `categoryGlAccountId` ids it matches nothing, as before).","schema":{"type":"string","enum":["uncategorized"]}},{"name":"includeUnassignedSource","in":"query","description":"`true` also selects rows with no source (neither bank nor integration account). With `sourceAccountId` the source dimension is `ids OR unassigned`; alone it is unassigned-only. `false` or absent adds nothing.\n","schema":{"type":"string","enum":["true","false"]}},{"name":"includeUnassignedCategory","in":"query","description":"`true` also selects rows with no category GL account. With `categoryGlAccountId` the category dimension is `ids OR unassigned`; alone it is unassigned-only. `false` or absent adds nothing.\n","schema":{"type":"string","enum":["true","false"]}},{"name":"search","in":"query","schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"sort","in":"query","description":"Ordering of the whole scan, applied identically to every page. The returned `meta.nextCursor` is bound to this sort: pass the same `sort` on every page, or the request is rejected with 422 instead of returning a page from a different order. Ties break on `occurredOn` descending then `id`; `date_asc` is fully ascending; NULL confidence sorts last under both confidence sorts.","schema":{"type":"string","default":"date_desc","enum":["date_desc","date_asc","amount_desc","amount_asc","confidence_desc","confidence_asc"]}},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Paginated list of transactions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createTransaction","summary":"Create a manual transaction","tags":["Transactions"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTransactionInput"}}}},"responses":{"201":{"description":"Transaction created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/ConflictJson"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/transactions/summary":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"summarizeTransactions","summary":"Summarize transactions with filters","tags":["Transactions"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","description":"Concrete legal entity. `consolidated` requires all-entity access; omitted scopes to the actor's grants.","schema":{"oneOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["consolidated"]}]}},{"name":"status","in":"query","schema":{"type":"string","enum":["needs_review","categorized"]}},{"name":"direction","in":"query","schema":{"type":"string","enum":["in","out"]}},{"name":"dateFrom","in":"query","schema":{"type":"string","format":"date"}},{"name":"dateTo","in":"query","schema":{"type":"string","format":"date"}},{"name":"bankAccountId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"sourceProvider","in":"query","description":"Source provider filter. Distinct from category filters.","schema":{"type":"string","minLength":1,"maxLength":80}},{"name":"sourceAccountId","in":"query","description":"Integration account or bank account source filter. Distinct from categoryGlAccountId.","schema":{"type":"string","format":"uuid"}},{"name":"categoryGlAccountId","in":"query","description":"GL account category filter. Distinct from sourceAccountId.","schema":{"type":"string","format":"uuid"}},{"name":"classId","in":"query","description":"Accounting class filter. Distinct from categoryGlAccountId.","schema":{"type":"string","format":"uuid"}},{"name":"tagId","in":"query","description":"Accounting tag filter (#1166). Comma-separated or repeated; a transaction matches when it carries ANY listed tag. ORed with `untagged`, ANDed with every other filter. An existence test, so a transaction with several selected tags appears once.\n","schema":{"oneOf":[{"type":"string","format":"uuid"},{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50}]}},{"name":"untagged","in":"query","description":"When `true`, include transactions with no tag (ORed with `tagId`).","schema":{"type":"string","enum":["true","false"]}},{"name":"categoryState","in":"query","description":"Filters transactions by category assignment state. `uncategorized` keeps meaning \"null category only\" and ANDs with the other filters (with `categoryGlAccountId` ids it matches nothing, as before).","schema":{"type":"string","enum":["uncategorized"]}},{"name":"includeUnassignedSource","in":"query","description":"`true` also selects rows with no source (neither bank nor integration account). With `sourceAccountId` the source dimension is `ids OR unassigned`; alone it is unassigned-only. `false` or absent adds nothing.\n","schema":{"type":"string","enum":["true","false"]}},{"name":"includeUnassignedCategory","in":"query","description":"`true` also selects rows with no category GL account. With `categoryGlAccountId` the category dimension is `ids OR unassigned`; alone it is unassigned-only. `false` or absent adds nothing.\n","schema":{"type":"string","enum":["true","false"]}},{"name":"search","in":"query","schema":{"type":"string","minLength":1,"maxLength":200}}],"responses":{"200":{"description":"Transaction summary for the matching filtered set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionSummaryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/transactions/facets":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getTransactionFacets","summary":"Get facet counts for transactions","description":"Returns per-source-account and per-category counts for the non-deleted transactions in the authorized scope and optional inclusive `occurred_on` window (same date semantics as the list). Search, status, direction, sort and the source/category selections do not narrow the counts. Each source account counts unique rows matching either their bank or integration account ID, as selecting that source does in the list. Distinct source buckets may overlap, so their sum may exceed the number of rows. `unassignedSourceCount` counts rows with both source IDs absent. Category counts and `unassignedCategoryCount` partition the rows in the window. Used to populate multi-select filter chips in the transaction list UI.\n","tags":["Transactions"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","description":"Concrete legal entity. `consolidated` requires all-entity access; omitted scopes to the actor's grants.","schema":{"oneOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["consolidated"]}]}},{"name":"dateFrom","in":"query","description":"Inclusive lower bound on `occurred_on` (YYYY-MM-DD, a real calendar date).","schema":{"type":"string","format":"date"}},{"name":"dateTo","in":"query","description":"Inclusive upper bound on `occurred_on` (YYYY-MM-DD, a real calendar date).","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Facet counts","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["sourceAccounts","categories","unassignedSourceCount","unassignedCategoryCount"],"properties":{"unassignedSourceCount":{"type":"integer","minimum":0,"description":"Rows in the window with neither a bank nor an integration account."},"unassignedCategoryCount":{"type":"integer","minimum":0,"description":"Rows in the window with no category GL account."},"sourceAccounts":{"type":"array","description":"Per-source-account counts, sorted by count descending.","items":{"type":"object","required":["id","label","count"],"properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"count":{"type":"integer","minimum":0}}}},"categories":{"type":"array","description":"Per-category GL account counts, sorted by label ascending.","items":{"type":"object","required":["id","label","count"],"properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"count":{"type":"integer","minimum":0}}}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/transactions/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getTransaction","summary":"Get a transaction by ID","description":"Returns the transaction with enrichment fields: `journalEntry` (the single posted, non-deleted GL entry linked to the transaction and owned by its legal entity, with balanced debit/credit lines, or null), and `matchedDocument` (the matched receipt/bill owned by the transaction's legal entity, or null). When a linked entry or document is withheld, `journalEntryUnavailableReason` / `matchedDocumentUnavailableReason` says why (`scope_mismatch`: owned by another entity; `ambiguous_posting`: more than one posted entry links to the transaction); absent means nothing is linked. All other fields are unchanged.\n","tags":["Transactions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Transaction found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Transaction not found"}}},"patch":{"operationId":"updateTransaction","summary":"Update a transaction","tags":["Transactions"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTransactionInput"}}}},"responses":{"200":{"description":"Transaction updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Transaction not found"},"422":{"description":"Validation or business rule error. `error.title` carries the rule: `TRANSACTION_CATEGORY_IS_BANK_ACCOUNT` (the category is the GL account of the transaction's own bank or card account), `TRANSACTION_APPLIED_TRANSFER_MATCH_ACTIVE` (the journal entry is consolidated with another transaction by an applied transfer or card-payment match), `TRANSACTION_BANK_OFFSET_UNIDENTIFIED` (the journal entry debits and credits one account and needs the accountant bank-offset repair first). Nothing is written when refused. Also returned, with no rule code, when the body sets `categoryGlAccountId` on a Stripe revenue transaction (an inbound Stripe charge, invoice or subscription payment, or a transaction suggested from the same Stripe customer's earlier charges): the category would be set without the customer rule its revenue entry needs, and the revenue would stay on hold (#3039). Send the category to `POST /companies/{companyId}/transactions/{transactionId}/learn` instead, which records that rule. Two cases are let through: re-sending the category a categorized transaction already has, and a transaction a person categorized by hand moving to another account that can carry Stripe revenue.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"delete":{"operationId":"deleteTransaction","summary":"Delete a transaction","tags":["Transactions"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Transaction deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Transaction not found"},"409":{"description":"Transaction has linked journal entries"}}}},"/companies/{companyId}/transactions/{id}/transfer-hold":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"holdTransactionForTransfer","summary":"Hold one unmatched transfer leg for accountant review","description":"Resolves the company Transfer Clearing account and bank identity on the server, then records a non-posting needs-review hold. The operation rejects reconciled transactions, active transfer matches, posted journal entries, and money outside the ledger currency capability.\n","tags":["Transactions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Transfer leg held for review","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Transaction not found"},"409":{"description":"Transaction already has an active transfer match"},"422":{"description":"Transfer hold violates an accounting safety invariant"}}}},"/companies/{companyId}/transactions/{transactionId}/learn":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"learnTransactionCategory","summary":"Correct a transaction's category, and learn a merchant rule from it when asked","description":"The customer category picker. The ledger follows the decision before the category is written: the posted journal entry is void-and-replaced with the bank or card offset kept and only the counterpart moved, then the category is saved as a manual decision. The change applies to this transaction only; a company merchant rule is written or repointed only when `learnMerchantRule` is true (#3112). A refused request writes nothing.\n","tags":["Transactions"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["glAccountId"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"learnMerchantRule":{"type":"boolean","description":"#3112: whether this change also writes or repoints the company merchant rule for this transaction's merchant, so later transactions from the merchant take the category. true: it does. Absent or false: the category applies to this transaction only and the company's merchant rules are left alone. Stripe revenue transactions (a Stripe charge, invoice or subscription payment, or a Stripe counterparty-history suggestion) are outside this choice: their exact company rule is always written, because that rule is what lets the revenue entry post. A non-boolean value is a 422."}}}}}},"responses":{"204":{"description":"Category saved (also returned when the transaction or account does not exist in this company)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation or business rule error. `error.title` is `TRANSACTION_CATEGORY_IS_BANK_ACCOUNT`, `TRANSACTION_APPLIED_TRANSFER_MATCH_ACTIVE` or `TRANSACTION_BANK_OFFSET_UNIDENTIFIED` for the same rules as `PATCH /companies/{companyId}/transactions/{id}`, or a generic rule (split transaction).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/companies/{companyId}/transactions/{id}/splits":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"listTransactionSplits","summary":"List splits for a transaction","tags":["Transactions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of splits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionSplitsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Transaction not found"}}},"put":{"operationId":"replaceTransactionSplits","summary":"Replace all splits for a transaction","tags":["Transactions"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplaceSplitsInput"}}}},"responses":{"200":{"description":"Splits replaced","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionSplitsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Transaction not found"},"422":{"description":"Validation or business rule error"}}}},"/companies/{companyId}/transactions/{id}/receipts":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"listTransactionReceipts","summary":"List receipts for a transaction","tags":["Transactions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of receipts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceiptsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Transaction not found"}}},"post":{"operationId":"createTransactionReceipt","summary":"Attach a receipt to a transaction","tags":["Transactions"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReceiptInput"}}}},"responses":{"201":{"description":"Receipt created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceiptResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Transaction not found"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/classes":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listAccountingClasses","summary":"List accounting classes","description":"Customer-facing class list. Returns only active classes approved for this company. Draft or inactive classes and proposal evidence are never returned to customer app users.\n","tags":["Accounting Classes"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Accounting classes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerAccountingClassesListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/tags":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listAccountingTags","summary":"List accounting tags","description":"Company-owned controlled tag vocabulary (#1166). Retired tags are omitted unless includeRetired=true. Owner, admin, cfo and member roles write; viewers read. Held behind the same customer surface gate as classes.\n","tags":["Accounting Tags"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"includeRetired","in":"query","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingTagsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createAccountingTag","summary":"Create an accounting tag","tags":["Accounting Tags"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingTagNameInput"},"example":{"name":"Paid social"}}}},"responses":{"201":{"description":"Tag created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingTagResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"A live tag with the same name (ignoring case and repeated spaces) exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/tags/{tagId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"tagId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"renameAccountingTag","summary":"Rename an accounting tag","tags":["Accounting Tags"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingTagNameInput"}}}},"responses":{"200":{"description":"Tag renamed; assignments keep the same tag ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingTagResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A live tag with the same name exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/tags/{tagId}/retire":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"tagId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"retireAccountingTag","summary":"Retire an accounting tag","description":"Idempotent. A retired tag keeps its existing assignments and history but cannot be newly assigned. Tags are never deleted.\n","tags":["Accounting Tags"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Tag retired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingTagResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/transactions/{transactionId}/tags":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getTransactionTags","summary":"Get a transaction's tags and revision","tags":["Accounting Tags"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionTagAssignmentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"operationId":"replaceTransactionTags","summary":"Replace a transaction's tags","description":"Sends the full tag set with the revision the client loaded. A different set at a stale revision is 409 and changes nothing; an identical set is an idempotent no-op. Never changes amounts, accounts, dates, status or reconciliation state; reconciled transactions may be tagged. Refused (422) when the transaction or a linked posted entry is in a filing-locked period. Owner, admin, cfo and member roles write; viewers read. Held behind the same customer surface gate as classes.\n","tags":["Accounting Tags"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplaceTransactionTagsInput"},"example":{"tagIds":["6f1b2a4e-8f7c-4b8e-9d2a-1c3e5f7a9b0d"],"expectedRevision":0}}}},"responses":{"200":{"description":"Tags replaced (or unchanged)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionTagAssignmentResponse"},"example":{"success":true,"data":{"transactionId":"0b8f2c1e-2d7a-4c3b-9e1f-5a6b7c8d9e0f","tagIds":["6f1b2a4e-8f7c-4b8e-9d2a-1c3e5f7a9b0d"],"revision":1}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The tags changed since the client loaded them (TAG_REVISION_CONFLICT)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation failed, unknown or retired tag, or filing-locked period","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/companies/{companyId}/overview":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getCompanyOverview","summary":"Get home page insights (cash, burn, runway, reconciliation)","description":"Returns the metrics surfaced on the customer home page for one authorized concrete legal entity. The new liveCashBalance / glCashBalance / reconciliationDeltaCents fields are additive; legacy fields (cashBalance, burnRate, runway, mrr) remain for backward compatibility. Gated behind HOME_INSIGHTS_V2_COMPANY_IDS at the service layer; callers always receive the legacy fields regardless of the gate.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/homeEntityId"},{"$ref":"#/components/parameters/reportStartDate"},{"$ref":"#/components/parameters/reportEndDate"},{"name":"months","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":12,"default":6},"description":"Length of the `monthlyRevenue` chart series in months (clamped 1-12). Governs the series length ONLY — every other overview figure (headlines, burn, runway, breakdowns) keeps its own window. Invalid values fall back to the default.\n"}],"responses":{"200":{"description":"Overview payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OverviewResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"An entity-scoped journal, transaction, or reports authority could not be read"}}}},"/companies/{companyId}/overview/activity-summary":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getCompanyOverviewActivitySummary","summary":"Get recent Home bookkeeping activity for one legal entity","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/homeEntityId"},{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":90,"default":7}}],"responses":{"200":{"description":"Entity-scoped activity payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OverviewActivitySummaryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"An entity-scoped activity authority could not be read"}}}},"/companies/{companyId}/overview/autonomous-impact":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getAutonomousImpact","summary":"Median at work: autonomous bookkeeping counts for a period","description":"Counts the bookkeeping Median's engine did for one authorized legal entity over the chosen period, filtered to autonomous actors only (engine-run match / decision rows, system-ingested documents, system-posted schedule entries). `enabled` reflects the home_autonomous_impact rollout flag; the Home section renders only when true. A real zero is distinct from an unavailable count: unavailable metrics return null plus an explicit availability reason.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/homeEntityId"},{"name":"period","in":"query","required":false,"schema":{"type":"string","enum":["this_month","last_month"],"default":"this_month"}}],"responses":{"200":{"description":"Autonomous-impact payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutonomousImpactResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/metrics/mrr-state":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getMrrCurrentState","summary":"Current incremental MRR publication state","description":"Reads one concrete authorized entity. entityId is required; membership and entity scope are enforced. Returns a persisted current recurring run-rate revision, separate from completed-month MRR and movement history. This read performs no provider requests, refresh, publication or financial writes. enabled is presentation permission, not evidence of freshness. An unavailable or withheld current value is null, never fabricated zero. No historical coverage is inferred. Responses use Cache-Control private, no-store.\n","tags":["Overview"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"entityId","in":"query","required":true,"description":"Concrete legal entity in the authorized company scope.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Current state, freshness metadata and separately unavailable history.","headers":{"Cache-Control":{"schema":{"type":"string","const":"private, no-store"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MrrCurrentStateResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Current-state service is unavailable, or the selected company/entity does not exist in scope."},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"Legal-entity scope or current-state read authority could not be established."}}}},"/companies/{companyId}/metrics/saas":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getSaasMetrics","summary":"SaaS metrics envelope (AR turnover, MRR, LTV, CAC)","description":"Returns the Home \"SaaS Metrics\" row. `enabled` reflects the home_saas_metrics rollout flag. Each metric also carries its own `available`: AR turnover is computed from the GL today; MRR reports the final sealed snapshot of the last completed calendar month (asOf; the current partial month is excluded) — this covers `currentMinorUnits` and the five waterfall components (new / expansion / reactivation / contraction / churned), while `projectedMinorUnits` and `contractedMinorUnits` stay deliberately FORWARD-LOOKING and are derived from live subscription state, not from the completed-month snapshot; LTV reads the entity's authoritative MRR snapshots plus its posted P&L gross margin and returns available:false with a `reason` when an input is missing (see LtvMetric). enabled reflects the home_saas_metrics rollout flag as UI-visibility metadata only — it never changes the computed result. When a metric is unavailable the UI shows an honest empty state (no fabricated numbers). The envelope-level `currency` / `mixedCurrencies` fields (additive) report the subscriptions' single authoritative billing currency: `currency` is null — never an assumed USD — when there are no subscriptions, the source is unwired, or currencies are mixed (`mixedCurrencies: true`). The envelope is ENTITY-scoped: `entityId` is a required concrete legal entity from the caller's authorized scope (a sole authorized entity is resolved automatically; a multi-entity actor without a selection gets a 422, and an unauthorized entity is rejected). Cross-entity sums without a consolidation authority are never fabricated.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","required":true,"description":"Concrete authorized legal entity whose SaaS metrics are requested.","schema":{"type":"string","format":"uuid"}},{"name":"asOf","in":"query","required":false,"description":"Optional YYYY-MM-DD clock override; the MRR fields describe the last completed calendar month strictly before this date's month (defaults to the server's UTC now).\n","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"SaaS metrics payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaasMetricsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"The legal-entity scope authority could not be read"}}}},"/companies/{companyId}/metrics/mrr-movements":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getMrrMovements","summary":"Monthly MRR waterfall history","description":"Returns the monthly MRR movement history behind the Home MRR-movements widget and the Recurring-revenue report. `enabled` reflects the home_saas_metrics rollout flag; `available` requires monthly snapshots and one authoritative billing currency. `unavailableReason` explains when mixed or unknown currency makes the history unsafe to present. Months are ascending; every amount is an exact base-10 minor-unit integer string under the root currency and minor-unit exponent. Waterfall components (new / expansion / reactivation / contraction / churned) are non-negative magnitudes and `netNewMrrMinorUnits` nets them. The current partial UTC month is excluded from every window before slicing; asOf and period name the resolved completed-month range. enabled reflects the home_saas_metrics rollout flag as UI-visibility metadata only — it never changes the computed result.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","required":true,"description":"Concrete authorized legal entity whose MRR history is requested.","schema":{"type":"string","format":"uuid"}},{"name":"months","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":24,"default":12},"description":"Trailing window of months to return."}],"responses":{"200":{"description":"MRR movements payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MrrMovementsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"The legal-entity scope authority could not be read"}}}},"/companies/{companyId}/metrics/mrr-by-interval":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getMrrByInterval","summary":"Current MRR by billing interval","description":"Current recurring MRR split by Stripe billing interval (#2566), from the synced subscriptions in customer_subscriptions. MRR, not revenue: each subscription contributes its normalized-monthly MRR (an annual plan is its yearly amount / 12, exact minor units), counting the same paying statuses (active, past_due) as the Home MRR tile. Rows are `monthly` (1-month interval), `annual` (1-year interval) and `other` (any other cadence), omitted when empty. The split is published only when its total equals the tile's live current MRR; otherwise `available` is false with reason `unreconciled`. `no_subscriptions` means nothing is paying; other reasons are the MRR readiness reasons.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","required":true,"description":"Concrete authorized legal entity whose MRR split is requested.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"MRR by billing interval payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MrrByIntervalResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"The legal-entity scope authority could not be read"}}}},"/companies/{companyId}/metrics/revenue-mix":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getRevenueMix","summary":"Recurring vs services vs other revenue per month","description":"Returns the Home revenue-mix card: posted revenue per month split into recurring / services / other, classified strictly by the billing provenance the posted books actually carry (business-event linkage, document source, processor-payout source transactions). No account-code heuristics: a revenue line with no recognizable provenance lands in `otherCents`. Window is fixed at the last 6 complete months plus the current month-to-date; entity-scoped when `entityId` is given. `available` is false with `months: []` when the window holds no posted revenue lines.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/homeOptionalEntityId"}],"responses":{"200":{"description":"Revenue-mix payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueMixResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"The legal-entity scope authority could not be read"}}}},"/companies/{companyId}/metrics/revenue-by-client":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getRevenueByClient","summary":"Posted revenue grouped by invoiced customer","description":"Returns the Home \"Revenue by client\" card: POSTED revenue journal lines (closing entries excluded) grouped by the customer their invoice provenance actually names, resolved through the AR subledger. Revenue with no invoice-to-customer linkage (processor payouts, name-only invoices, unwired subledger) is summed into `otherCents` — never invented per client. Window is the last `months` complete months plus the current month-to-date; entity-scoped when `entityId` is given. `available` is false when the window holds no posted revenue lines.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/homeOptionalEntityId"},{"name":"months","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":12,"default":6},"description":"Complete months in the window (the current month-to-date is always included). Clamped 1-12; invalid values fall back to the default.\n"}],"responses":{"200":{"description":"Revenue-by-client payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueByClientResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"The legal-entity scope authority could not be read"}}}},"/companies/{companyId}/metrics/active-clients":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getActiveClients","summary":"Active clients per month (services Home)","description":"#1967 \"Active clients\" tile on a services company's Home. For each of the last twelve months (eleven completed months plus the current month to date, UTC), the number of distinct clients whose net POSTED operating revenue in that month is positive. Operating revenue leaves out other income (4100-style) and 4999 Uncategorized Income, as the Books hub does; closing entries are excluded. A revenue entry's client is the AR customer record its invoice provenance names, else the customer its source receipt names (a Stripe `cus_` id or the receipt name, folded onto the matching customer record). A payment that only settles A/R posts no revenue and never counts; a processor payout names no client. When any of a month's revenue has no client, that month is `unattributed_revenue` with `activeClients: null`, never an undercount.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/homeEntityId"}],"responses":{"200":{"description":"Active-clients series","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveClientsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The metric is not wired on this deployment"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"The legal-entity scope authority could not be read"}}}},"/companies/{companyId}/metrics/revenue-mix/billing-types":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getBillingTypeRevenueMix","summary":"Recognized revenue by billing type over completed months","description":"Additive v2 revenue-mix contract (the legacy /metrics/revenue-mix stays verbatim for old clients). Recognized posted operating revenue for the selected entity over the resolved completed-month window, classified into exactly Recurring / One-time / Usage by invoice-line billing provenance. Publishes only when recognition allocations reconcile two-way with posted operating revenue AND the posted-books month census covers every window month; anything less is available:false with a public-safe reason and exact minor-unit unclassified diagnostics. The current partial month is never included.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","required":true,"description":"Concrete legal-entity scope. REQUIRED — this endpoint never serves a company-wide roll-up and never guesses an entity; the value must be a legal entity the actor is authorized to read.\n","schema":{"type":"string","format":"uuid"}},{"name":"months","in":"query","required":false,"schema":{"type":"integer","enum":[1,3,6,12],"default":1},"description":"Completed calendar months in the window (1 = the previous full calendar month). Any other value returns 422 — never a silent fallback to a different financial period.\n"}],"responses":{"200":{"description":"Billing-type revenue metric envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingTypeRevenueMixResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The billing-type revenue service is not wired in this deployment. This is the documented fail-closed default for the whole /metrics subtree, and the state a not-yet-deployed environment returns — a generated client needs this branch, it is not an error condition.\n","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"The legal-entity scope authority could not be read"}}}},"/companies/{companyId}/metrics/revenue-by-product":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getRevenueByProduct","summary":"Posted revenue by revenue GL account over completed months","description":"Posted operating revenue for the selected entity over the resolved completed-month window (#2414, #2637). The chart of accounts carries the products (#3211): a product is an operating, credit-normal, non-contra revenue GL account, whether or not it carries a product key (J-364 keys name products for Stripe routing only). `rows` are those accounts with non-zero revenue, labelled by account name, and `total` (\"Product revenue\") is their sum. `unattributedRevenue` is 4999 Uncategorized Income only, and `mappingComplete` is always true. Refunds and discounts (contra or debit-normal revenue accounts) are `refundsAndDiscounts`, signed, and never a product. The tie-out holds exactly (J-367): total + unattributedRevenue + refundsAndDiscounts = operatingRevenue, the P&L operating revenue (Revenue accounts excluding other income and 4999) for the same entity and months. Amounts are exact minor units; no percentages are published. A window month with no posted books is available:false insufficient_history with the missing months named. The current partial month is never included. `eligibility` carries the company-level card visibility over the last 12 completed months (see RevenueByProductEligibility); it does not change the selected window's rows or census.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","required":true,"description":"Concrete legal-entity scope. REQUIRED — never a company roll-up, never a guessed entity.\n","schema":{"type":"string","format":"uuid"}},{"name":"months","in":"query","required":false,"schema":{"type":"integer","enum":[1,3,6,12],"default":1},"description":"Completed calendar months in the window (1 = the previous full calendar month). Any other value returns 422.\n"}],"responses":{"200":{"description":"Revenue-by-product metric envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueByProductMetricResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The revenue-by-product service is not wired in this deployment. This is the documented fail-closed default for the whole /metrics subtree, and the state a not-yet-deployed environment returns — a generated client needs this branch, it is not an error condition.\n","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"The legal-entity scope authority could not be read"}}}},"/companies/{companyId}/metrics/cash-history":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getCashHistory","summary":"Posted-books cash balance series (daily, or completed-month with granularity=month)","description":"Returns the daily posted-books cash balance series behind the Home hero cash card's trend chart. Cash accounts resolve through the same rule the overview uses; the opening balance is the cumulative POSTED journal-line balance before the window start, and the series then walks the window's posted journal lines day by day — one point per day with activity, plus window-boundary points. Entity-scoped when `entityId` is given. `available` is false with `series: []` when the company has no cash accounts or no posted cash journal lines at all.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/homeOptionalEntityId"},{"name":"months","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":24,"default":6},"description":"Trailing window in months; the window starts on the first day of the month months-1 back. Clamped 1-24; invalid values fall back to the default. With `granularity=month` the accepted values are restricted to 1, 3, 6, or 12 (422 otherwise, default 12).\n"},{"name":"granularity","in":"query","required":false,"schema":{"type":"string","enum":["day","month"],"default":"day"},"description":"`day` (default) preserves the original daily contract. `month` returns the F02 completed-month contract: strict concrete legal entity, separate `currentCash` and completed-month `history` with per-point provenance; `months` is then restricted to 1, 3, 6, or 12 (422 otherwise, default 12) and never includes the current partial month.\n"}],"responses":{"200":{"description":"Cash-history payload","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/CashHistoryResponse"},{"$ref":"#/components/schemas/MonthlyCashHistoryResponse"}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"The legal-entity scope authority could not be read"}}}},"/companies/{companyId}/metrics/burn-runway":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getBurnRunway","summary":"Monthly burn headline, hero series, and Runway composite","description":"F04 hero contract. Returns the trailing-three-completed-month signed net Monthly burn headline (basis posted_operating_net_burn, exact minor-unit strings, month keys and numerator/denominator included so reconciliation never depends on rounded values), a hero sparkline series of one trailing-three-month value ending at each of the last twelve completed months, and the Runway composite (finite | depleted | non_burning, or unavailable — never negative months) over posted-books current cash. Requires one concrete authorized legal entity, resolved like /metrics/saas.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/homeOptionalEntityId"}],"responses":{"200":{"description":"Burn and runway payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BurnRunwayResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"The legal-entity scope authority could not be read"}}}},"/companies/{companyId}/metrics/daily-trends":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getDailyTrends","summary":"Daily Runway and Receivables lines for the Home hero tiles","description":"One point per day over the last six months (today and the same day six months back, inclusive, UTC) for the Home Runway and Receivables tiles. Runway uses the Live tile's formula: posted-books cash at the close of the day divided by the trailing-90-day posted operating net burn ending that day (divided by 3, half away from zero), floored; a day with no posted P&L line in its 90-day window has no point. Receivables is the posted balance of the AR control accounts at the close of the day, from the first posted day of the books. Both are exact minor-unit strings; each line fails closed on its own with a reason. Requires one concrete authorized legal entity, resolved like /metrics/burn-runway.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/homeOptionalEntityId"}],"responses":{"200":{"description":"Daily trend lines","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DailyTrendsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"The legal-entity scope authority could not be read"}}}},"/companies/{companyId}/metrics/cash-by-entity":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getCashByEntity","summary":"Current posted-books cash per legal entity","description":"Returns the Home \"Cash by entity\" card: the cumulative POSTED journal-line cash balance per non-group legal entity, as of today. This is inherently the cross-entity read (no `entityId` param); rows are filtered to the entities the actor holds grants for. Honesty gates return available:false with a reason instead of a misleading card: `single_entity` (the card is only meaningful across entities), `no_accessible_entities`, `no_cash_accounts`.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Cash-by-entity payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashByEntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/metrics/expense-breakdown":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getExpenseBreakdown","summary":"Posted P&L expense breakdown over completed months","description":"Home \"Expenses by category\" card (F18). Signed net posted expense activity per category over a server-resolved completed-month window (never the current partial month), covering every P&L expense family (COGS, operating expense, depreciation/amortization, interest, income tax, other expense) with signed contra/refund effects. Exact minor-unit strings. A zero or negative signed total returns rows and total without percentages; a window the posted-books month census does not fully cover, mixed-currency, truncated, or entity-unattributable coverage returns available:false with a reason (never a partial total).\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"Concrete legal entity the actor is authorized to read."},{"name":"months","in":"query","required":true,"schema":{"type":"integer","enum":[1,3,6,12]},"description":"Completed-month window size. Values outside 1|3|6|12 are a 422; there is no silent fallback.\n"},{"name":"live","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]},"description":"Home Live mode. `true` ends the window at the month in progress (it takes the window's last slot, so 1 is the month to date) and sets `authority.postedThrough` to the day the figures run to. Omitted or `false` is the completed-month window. Any other value is a 422.\n"}],"responses":{"200":{"description":"Expense-breakdown metric envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseBreakdownResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"The legal-entity scope authority could not be read"}}}},"/companies/{companyId}/metrics/net-burn":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getNetBurnCard","summary":"Fixed six-completed-month Net burn card","description":"Home \"Net burn by month\" card (F19). Always the previous six completed months — no range parameter. Six stable month slots (observed / authoritative_zero / unavailable), each numeric slot an exact signed net-burn minor-unit string from the canonical posted-operating-net-burn series, plus an aggregate six-month average that includes authoritative zeros and is unavailable with a missingMonths diagnostic when any window month lacks coverage — the denominator is never silently reduced. missingMonths names only months the posted books do NOT cover, so a fully covered window that carries no currency authority (books present, zero operating lines) is unavailable with an EMPTY missingMonths rather than one naming months the census covered. A series-level failure propagates verbatim as the average's reason (entity_scope_unavailable, truncated, mixed_currency, incomplete_provenance, failed), distinct from honest insufficient_history.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"Concrete legal entity the actor is authorized to read."},{"name":"live","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]},"description":"Home Live mode. `true` appends the month in progress as a seventh slot and returns `inProgress` { month, postedThrough }; `endMonth` becomes that month. The average stays the six completed months. Omitted or `false` is the six completed months only. Any other value is a 422.\n"}],"responses":{"200":{"description":"Net-burn card envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NetBurnCardResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"The legal-entity scope authority could not be read"}}}},"/companies/{companyId}/metrics/practice":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getPracticeMetrics","summary":"Practice metrics envelope (four practice widgets)","description":"Returns the Home practice-metrics envelope: the two-axis widget catalog (services axis from the stored business model, ownership axis from the entity type), the practice config, the company's pinned widgets, and the four widgets assembled from the accountant-uploaded patient-free aggregate feed. Honest denominators: a widget whose inputs are absent reports `available: false` with the missing metric keys, and a figure whose denominator is unknown is null; nothing is fabricated (`costPerCustomerCents: null` means \"cost per customer unknown\"). Returns 404 unless `practice_metrics` is in the company's `additionalMetrics` list; the surface does not exist for an unlisted company.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Practice metrics envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PracticeMetricsEnvelopeResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"practice_metrics is not in this company's additionalMetrics list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/companies/{companyId}/metrics/pins":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getPinnedMetrics","summary":"List the company's pinned Home metric widgets","description":"Returns the server-authoritative pinned-widget list for the Home board, ordered by position. Returns 404 unless `practice_metrics` is in the company's `additionalMetrics` list.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Pinned widgets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedMetricsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"practice_metrics is not in this company's additionalMetrics list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"put":{"operationId":"updatePinnedMetrics","summary":"Replace the company's pinned Home metric widgets","description":"Full replacement — the client owns the complete pin list (at most 50). Returns the stored list, ordered by position. Returns 404 unless `practice_metrics` is in the company's `additionalMetrics` list.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePinnedMetricsRequest"}}}},"responses":{"200":{"description":"The stored pin list after replacement","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedMetricsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"practice_metrics is not in this company's additionalMetrics list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/insights/home":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getHomeInsights","summary":"Home \"Insights\" card (top active recommendations)","description":"Returns the Home \"Insights\" card: the top 5 active, non-dismissed, non-suppressed recommendations (engine ranking, presented newest first), gated by the insights-readiness rule — `available: false` with the unmet readiness-requirement id as `reason` until the books support trustworthy output. Recommendations are company-scoped facts today: an `entityId` is honored only when it is the company's ONLY non-group legal entity; otherwise `entity_scope_unavailable` is reported rather than silently company-widening.\n","tags":["Overview"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/homeOptionalEntityId"}],"responses":{"200":{"description":"Home insights payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HomeInsightsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"The legal-entity scope authority could not be read"}}}},"/companies/{companyId}/gl-periods":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listGlPeriods","summary":"List GL periods","tags":["GL Periods"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of periods","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlPeriodsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createGlPeriod","summary":"Create a GL period","description":"Requires company role admin or owner.","tags":["GL Periods"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGlPeriodInput"}}}},"responses":{"201":{"description":"GL period created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlPeriodResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Period overlaps with existing period"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/gl-periods/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getGlPeriod","summary":"Get a GL period by ID","tags":["GL Periods"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"GL period found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlPeriodResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"GL period not found"}}}},"/companies/{companyId}/gl-periods/{id}/close":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"closeGlPeriod","summary":"Close a GL period","description":"Generates the period's closing entry (sweeping profit and loss to\nRetained Earnings) and then marks the period closed. The closing\nentry posts before the status flip so it lands in the period being\nclosed; a stale closing entry left from an earlier close is voided\nand replaced. A closed period is a reconciliation marker: it still\naccepts postings and voids, and only a filing lock blocks them\n(#2411). Requires company role admin or owner in a signed-in\nsession; API keys are refused with 403.\n","tags":["GL Periods"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Period closed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlPeriodResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"GL period not found"},"422":{"description":"Period is already closed, the closing entry cannot be generated\n(for example the chart of accounts has no Retained Earnings\naccount), or unresolved blocking close blockers remain. In the\nlast case the error code is `CLOSE_BLOCKERS_UNRESOLVED`, the\nmessage names each blocking kind and its count, and\n`extensions` carries `periodId`, `unresolvedBlockerCount` and\n`blockers: [{ kind, count }]`. The period stays open.\n"}}}},"/companies/{companyId}/gl-periods/{id}/file-lock":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"fileLockGlPeriod","summary":"Apply the post-tax-filing immutability lock to a closed GL period","description":"Filing-lock is the only period lock, applied AFTER a tax return has\nbeen submitted. Closing a period is a reconciliation marker that\nstill accepts postings and voids; a filing-locked period rejects ALL\njournal writes at the DB level, with no bypass (#2411). Requires\nrole >= admin in a signed-in session; API keys are refused with 403.\n","tags":["GL Periods"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Period filing-locked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlPeriodResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"GL period not found"},"422":{"description":"Period is not closed, or is already filing-locked.\n"}}}},"/companies/{companyId}/close/readiness":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getCloseReadiness","summary":"Check whether the next ended GL period can be closed","description":"Read-only. Resolves the period named by `periodId`, or else the\nearliest open GL period that ended before today, and lists what\nblocks closing it: transactions in the period that still need\nreview, open blocking threads, and unresolved blocking-severity\nclose blockers. A period that has not ended reports only\n`period_not_ended`; an already-closed period reports `ready: false`\nwith an `already_closed` blocker. When no period resolves, `periodId`\nis null and the only blocker is `no_period`. Open to every company member.\n","tags":["GL Periods"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"periodId","in":"query","required":false,"description":"GL period to check. An id that matches no period of this company answers the `no_period` blocker.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Close readiness for the resolved period","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloseReadinessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/close/trigger":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"triggerAutoClose","summary":"Close the next ended GL period if it is ready","description":"Re-checks readiness for the period named by `periodId`, or else the\nearliest ended open period. Only when it is ready does it post every\ndue schedule entry, generate the closing entry, mark the period\nclosed and update the books status. A close that cannot proceed\n(not ready, already closed, a failed schedule posting, failed\nclearing verification, or a closing entry that cannot be generated)\nanswers 200 with `closed: false` and a `reason`. Requires company\nrole admin or owner, the same authority as\n`POST /companies/{companyId}/gl-periods/{id}/close`; API keys are\nrefused with 403 (#2411).\n","tags":["GL Periods"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerAutoCloseInput"}}}},"responses":{"200":{"description":"Close attempted; `closed` reports whether the period was closed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoCloseResultResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/accountant/companies/{customerId}/gl-periods/{periodId}/close":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"periodId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"closeAccountantGlPeriod","summary":"Close an assigned customer's GL period","description":"Generates the period's closing entry and sweeps profit and loss to\nRetained Earnings, then marks the period closed. The closing entry\nposts before the status flip so it lands in the period being closed,\nand a re-close after a reopen writes a fresh entry rather than\nleaving the period closed without one (#2143). A closed period is a\nreconciliation marker and still accepts postings and voids (#2411).\nCaller must be an accountant assigned to the customer. The agent\nservice API key may close a period as a high-impact operation\n(2026-10-06); other API keys cannot.\n","tags":["GL Periods"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Period closed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlPeriodResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"GL period not found, or the accountant is not assigned to this customer"},"422":{"description":"Period is already closed, the closing entry cannot be generated\n(for example the chart of accounts has no Retained Earnings\naccount), or unresolved blocking close blockers remain. In the\nlast case the error code is `CLOSE_BLOCKERS_UNRESOLVED`, the\nmessage names each blocking kind and its count, and\n`extensions` carries `periodId`, `unresolvedBlockerCount` and\n`blockers: [{ kind, count }]`. The period stays open.\n"}}}},"/accountant/companies/{customerId}/gl-periods/{periodId}/reopen":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"periodId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"reopenAccountantGlPeriod","summary":"Reopen an assigned customer's closed GL period (refused if filing-locked or a newer period is closed)","description":"Returns a closed period to open. Voids the period's closing entry so\nthe stale Retained Earnings sweep is removed, and writes an\naudit_logs entry with the supplied reason. Refused when the period is\nfiling-locked or when a newer period has already been closed, so a run\nthat reaches back several months must reopen newest-first. Post-close\nadjustments do not need a reopen: a closed period still accepts\npostings and voids (#2411).\n\nMoved here from `/companies/{companyId}/gl-periods/{id}/reopen` (#1852):\nreopening a period the client has already been shown is accountant\nwork, not company-admin work. The agent service API key may reopen a\nperiod as a high-impact operation with the same mandatory reason\n(2026-10-06, reversing #2411 for this route).\n","tags":["GL Periods"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","minLength":10,"description":"Explanation for reopening, written to audit_logs.changes.reason."}}}}}},"responses":{"200":{"description":"Period reopened","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlPeriodResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"GL period not found, or the accountant is not assigned to this customer"},"422":{"description":"Validation error (reason missing or too short), or period\nis not closed, is filing-locked, or a newer period is\nalready closed.\n"}}}},"/accountant/companies/{customerId}/gl-periods/{periodId}/reclose":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"periodId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"recloseAccountantGlPeriod","summary":"Re-close an assigned customer's closed GL period in place after its ledger changed","description":"For a closed month that changed after its close (#2835). Runs the\nsame pre-close gate as the close route, brings the period's closing\nentry in line with its current profit and loss when it no longer\nmatches, then moves `closedAt` to the database cutoff captured before\nreview and `closedByUserId` to the caller. Changes after that cutoff\nkeep the month-end `closed_period_changed` advisory for another review.\nThe period stays closed throughout and no other period is touched,\nso it works for a month that has newer closed months after it. Writes\nan audit_logs entry (action `reclose`) with the supplied reason.\nThe agent service API key may re-close a period as a high-impact\noperation with the same mandatory reason (2026-10-06, reversing\n#2411 for this route).\n","tags":["GL Periods"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["reason"],"properties":{"reason":{"type":"string","minLength":10,"description":"What was reviewed, written to audit_logs.changes.reason."}}}}}},"responses":{"200":{"description":"Period re-closed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlPeriodResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"GL period not found, or the accountant is not assigned to this customer"},"422":{"description":"Validation error (reason missing or too short, or an unknown\nfield), the period is not closed or is filing-locked, the closing\nentry cannot be regenerated, or unresolved blocking close\nblockers remain (`CLOSE_BLOCKERS_UNRESOLVED`, same body as the\nclose route). Nothing is changed.\n"}}}},"/accountant/companies/{customerId}/gl-periods/{periodId}/file-lock":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"periodId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"fileLockAccountantGlPeriod","summary":"Apply the post-tax-filing lock to an assigned customer's closed GL period (irreversible)","description":"Marks a closed period immutable after its tax return was filed\nelsewhere. It does not submit or verify a return. Irreversible: there is\nno unlock. Writes an audit_logs entry (action `file-lock`) with the\nactor and time.\n\nRequires accountant access to the customer AND the company admin/owner\nrole that `/companies/{companyId}/gl-periods/{id}/file-lock` requires;\nassignment alone is not enough (#2104). Signed-in humans only: API keys\nget 403 and the service principal gets 404.\n","tags":["GL Periods"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Period filing-locked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlPeriodResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"GL period not found for this customer"},"422":{"description":"Period is not closed, or is already filing-locked."}}}},"/accountant/companies/{customerId}/gl-periods/capabilities":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantGlPeriodCapabilities","summary":"Which period actions the signed-in accountant may take for this customer","description":"`fileLock` is true only when the accountant also holds the company\nadmin or owner role (#2104). `reopenablePeriodId` is the one period the\nreopen route would accept now: the newest closed period, unless it is\nfiling-locked (then null). Reopen itself follows the assigned-accountant\npolicy. The accountant app keeps both controls disabled until this\nanswers. API keys receive 403.\n","tags":["GL Periods"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Period action capabilities","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["fileLock","reopenablePeriodId"],"properties":{"fileLock":{"type":"boolean"},"reopenablePeriodId":{"type":["string","null"],"format":"uuid"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/fx-account-roles":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/qaAppSurface"}],"get":{"operationId":"listFxAccountingRolesQa","summary":"List configured FX accounting authorities","tags":["GL Accounts"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The three supported roles and their real company accounts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FxAccountingRolesResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Hidden outside the QA test-company boundary"}}}},"/companies/{companyId}/fx-account-roles/{role}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/fxAccountingRole"},{"$ref":"#/components/parameters/qaAppSurface"}],"put":{"operationId":"configureFxAccountingRoleQa","summary":"Map an FX authority to a real company GL account","tags":["GL Accounts"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["glAccountId"],"properties":{"glAccountId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Audited company-scoped role mapping","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FxAccountingRoleResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Hidden outside QA, or account not found"},"422":{"description":"Account is incompatible with the selected accounting role"}}}},"/companies/{companyId}/gl-periods/{periodId}/fx-revaluation":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"periodId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/qaAppSurface"}],"get":{"operationId":"getFxRevaluationQa","summary":"Read the durable FX revaluation and position derivations","tags":["GL Periods"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Durable run and immutable rate evidence","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FxRevaluationDetailResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Hidden outside QA, or no run exists"}}},"post":{"operationId":"runFxRevaluationQa","summary":"Run idempotent month-end foreign-currency revaluation","description":"QA test-company admin/owner only. Uses legal-entity functional currency, immutable closing-rate revisions, explicit monetary classification, and the configured UNREALIZED_FX_GAIN_LOSS role.\n","tags":["GL Periods"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Completed result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FxRevaluationResultResponse"}}}},"202":{"description":"Identical run already in progress","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FxRevaluationResultResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Hidden outside QA, or period not found"},"409":{"description":"Changed inputs require controlled restatement"},"422":{"description":"A required accounting authority is missing or locked"}}}},"/accountant/companies/{customerId}/gl-accounts/{id}/monetary-classification":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/resourceId"},{"$ref":"#/components/parameters/qaAppSurface"}],"patch":{"operationId":"classifyAccountantGlAccountMonetaryQa","summary":"Record an assigned QA company's audited monetary decision","tags":["GL Accounts"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["isMonetary"],"properties":{"isMonetary":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Classification recorded with accountant actor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlAccountResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Hidden outside QA, assignment missing, or account not found"},"422":{"description":"Only Asset and Liability accounts may be manually classified"}}}},"/accountant/companies/{customerId}/document-forwarding-address":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantDocumentForwardingAddress","summary":"Read an assigned client's document forwarding address","description":"The client forwards documents to handle@domain (#2901). Reading generates the handle from the company name when the company has none and one can be generated without a duplicate, a look-alike or a Median mailbox. Human accountants only; hidden from the service key.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The client's forwarding address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentForwardingAddressResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"operationId":"setAccountantDocumentForwardingAddress","summary":"Set an assigned client's document forwarding handle","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["handle"],"properties":{"handle":{"type":"string","maxLength":200,"description":"3 to 40 lowercase letters and digits, with single dots or dashes between them. The part before the @."}}}}}},"responses":{"200":{"description":"The client's forwarding address after the change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentForwardingAddressResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Another client has or had that address, or one too similar to it. The other client is not named."},"422":{"description":"The handle is malformed or belongs to a Median mailbox"}}}},"/accountant/companies/{customerId}/statement-basis":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantStatementBasis","summary":"Read an assigned client's approved statement basis","description":"The approved statement basis (#2911, J-355) is a reporting configuration an accountant records with a reason and an approval reference. It is distinct from the tax election (tax settings' accounting method) and from the book basis. The history is append-only: a correction is a new row naming the row it supersedes. `effective` is the row in force on `asOf` (today, UTC): the latest row with effectiveDate on or before it, by effectiveDate, then createdAt, then id, descending; null when none. The basis is metadata only: it never changes a figure or `reportBasis`, which comes only from the cash computation. Human accountants only; hidden from the service key.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The row in force today and the full history","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/StatementBasisHistory"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"appendAccountantStatementBasis","summary":"Record an assigned client's approved statement basis","description":"Appends one row to the client's statement basis history (#2911, J-355). The actor and timestamp are set by the server; a body that carries them is refused. `supersedesId`, when given, must belong to the same client, else 422. There is no idempotency key: a replay records a second row by design, and the read resolves the latest. Human accountants only; the assignment is re-read before the write.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatementBasisInput"}}}},"responses":{"201":{"description":"The recorded row","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/StatementBasisEntry"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"503":{"description":"The accountant assignment could not be re-read before the write; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/revenue-products":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantRevenueProducts","summary":"Read an assigned client's revenue product tags and Stripe product mappings","description":"Revenue by product (#2637, J-364). `accounts` are the client's revenue accounts that may carry a product key (operating, credit-normal, not refunds/discounts), with their current key. `stripeMappings` map Stripe product ids to product accounts (many to one). `history` is the append-only audit trail, newest first (who, when, old, new, reason). Human accountants only; hidden from the service key.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Product accounts, Stripe product mappings and their history","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevenueProducts"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/accountant/companies/{customerId}/revenue-products/accounts/{accountId}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"accountId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"put":{"operationId":"setAccountantRevenueProductKey","summary":"Tag or untag a revenue account as a product","description":"Sets (or, with `productKey: null`, removes) the account's product key. Compare-and-swap on `expected`, the key the caller last saw; the change and its audit event commit together. Only an operating, credit-normal, non-contra revenue account can be a product. Untagging is refused while Stripe products map to the account. A repeat of the current value is a replay (`replayed: true`) and writes nothing. Changes no journal entry. Human accountants only; the assignment is re-read before the write.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueProductKeyInput"}}}},"responses":{"200":{"description":"The account's product key after the write","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["glAccountId","productKey","replayed"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"productKey":{"type":["string","null"]},"replayed":{"type":"boolean"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Stale write (REVENUE_PRODUCT_STALE), key already used (REVENUE_PRODUCT_KEY_TAKEN), or an untag while Stripe products still map to the account (REVENUE_PRODUCT_ACCOUNT_MAPPED)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"503":{"description":"The accountant assignment could not be re-read before the write; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/revenue-products/stripe-products/{stripeProductId}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"stripeProductId","in":"path","required":true,"schema":{"type":"string","pattern":"^prod_[A-Za-z0-9]{1,60}$"}}],"put":{"operationId":"setAccountantStripeRevenueProductMapping","summary":"Map a Stripe product to a product account","description":"Maps (or, with `glAccountId: null`, unmaps) a Stripe product to a product-tagged revenue account; many products may share one account. Compare-and-swap on `expectedGlAccountId`; the change and its audit event commit together. Affects only Stripe charges categorized or posted after the change (J-366): manual categorizations and exact merchant rules still win, a confirmed revenue mapping keeps its posting-release hold, a charge whose products are all unmapped keeps its existing posting, and a charge with incomplete or mixed product evidence is held for review. No history is reclassified. Human accountants only; the assignment is re-read before the write.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeRevenueProductMappingInput"}}}},"responses":{"200":{"description":"The mapping after the write","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["stripeProductId","glAccountId","replayed"],"properties":{"stripeProductId":{"type":"string"},"glAccountId":{"type":["string","null"],"format":"uuid"},"replayed":{"type":"boolean"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Stale write (REVENUE_PRODUCT_STALE), key already used (REVENUE_PRODUCT_KEY_TAKEN), or an untag while Stripe products still map to the account (REVENUE_PRODUCT_ACCOUNT_MAPPED)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"503":{"description":"The accountant assignment could not be re-read before the write; retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/fx-account-roles":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/qaAppSurface"}],"get":{"operationId":"listAccountantFxAccountingRolesQa","summary":"List an assigned QA company's FX accounting authorities","tags":["GL Accounts"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Configured role mappings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FxAccountingRolesResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Hidden outside the QA test-company boundary"}}}},"/accountant/companies/{customerId}/fx-account-roles/{role}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/fxAccountingRole"},{"$ref":"#/components/parameters/qaAppSurface"}],"put":{"operationId":"configureAccountantFxAccountingRoleQa","summary":"Configure an assigned QA company's FX accounting authority","tags":["GL Accounts"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["glAccountId"],"properties":{"glAccountId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Audited role mapping","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FxAccountingRoleResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Hidden outside QA, or account not found"},"422":{"description":"Account is incompatible with the selected accounting role"}}}},"/accountant/companies/{customerId}/gl-periods/{periodId}/fx-revaluation":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"periodId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/qaAppSurface"}],"get":{"operationId":"getAccountantFxRevaluationQa","summary":"Read an assigned QA company's FX revaluation evidence","tags":["GL Periods"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Durable run detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FxRevaluationDetailResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Hidden outside the QA test-company boundary"}}},"post":{"operationId":"runAccountantFxRevaluationQa","summary":"Run FX revaluation for an assigned QA test company","tags":["GL Periods"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Revaluation completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FxRevaluationResultResponse"}}}},"202":{"description":"Identical run already in progress"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Hidden outside the QA test-company boundary"},"409":{"description":"Changed inputs require controlled restatement"},"422":{"description":"A required accounting authority is missing, stale, or locked"}}}},"/companies/{companyId}/journal-entries":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listJournalEntries","summary":"List journal entries with filters","tags":["Journal Entries"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","description":"Concrete legal entity. Legacy unscoped rows resolve only to the primary entity.","schema":{"type":"string","format":"uuid"}},{"name":"periodId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"sourceType","in":"query","schema":{"type":"string","enum":["transaction","document","adjustment","system"]}},{"name":"sourceId","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["posted","void"]}},{"name":"dateFrom","in":"query","schema":{"type":"string","format":"date"}},{"name":"dateTo","in":"query","schema":{"type":"string","format":"date"}},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Paginated list of journal entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JournalEntriesListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createJournalEntry","summary":"Create a journal entry with lines (must balance)","description":"Requires company role cfo, admin, or owner.","tags":["Journal Entries"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJournalEntryInput"}}}},"responses":{"201":{"description":"Journal entry created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JournalEntryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation or business rule error"}}}},"/companies/{companyId}/journal-entries/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getJournalEntry","summary":"Get a journal entry by ID (includes lines)","tags":["Journal Entries"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Journal entry found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JournalEntryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Journal entry not found"}}}},"/companies/{companyId}/journal-entries/{id}/source":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getJournalEntrySource","summary":"Get a journal entry with source drill-down metadata","tags":["Journal Entries"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Journal entry found with source metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JournalEntryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Journal entry not found"}}}},"/companies/{companyId}/journal-entries/{id}/void":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"voidJournalEntry","summary":"Void an active posted journal entry","description":"Requires company role cfo, admin, or owner.","tags":["Journal Entries"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoidJournalEntryRequest"}}}},"responses":{"200":{"description":"Journal entry voided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JournalEntryResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"Journal entry is already void, non-posted, or soft-deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Journal entry is reconciled or in a filing-locked period (closed periods are voidable)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/journal-entries":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/transactionId"}],"get":{"operationId":"accountantListTransactionJournalEntries","summary":"List journal entries linked to a customer transaction","tags":["Accountant Portal","Journal Entries"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Journal entries linked by source or line transaction id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JournalEntriesListResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/companies/{customerId}/journal-entries/{id}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"accountantGetJournalEntry","summary":"Get one customer journal entry by ID (includes lines)","description":"Read-back of a single journal entry, e.g. to verify the effect of a void or posting without scanning whole-account activity reports.\n","tags":["Accountant Portal","Journal Entries"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"include","in":"query","required":false,"schema":{"type":"string","enum":["source"]},"description":"Set to `source` to include source drill-down metadata."}],"responses":{"200":{"description":"Journal entry found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JournalEntryResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/journal-entries/{id}/void":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"accountantVoidJournalEntry","summary":"Accountant void of one active posted journal entry","tags":["Accountant Portal","Journal Entries"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoidJournalEntryRequest"}}}},"responses":{"200":{"description":"Journal entry voided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JournalEntryResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"Journal entry is already void, non-posted, or soft-deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Journal entry is reconciled or in a filing-locked period (closed periods are voidable)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/journal-entries/{id}/correct-date":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"accountantCorrectJournalEntryDate","summary":"Correct the posted date of one active journal entry","description":"Accountant-only date correction for a posted journal entry. The target date must be inside the posted-ledger date domain. Evidence naming the source of the new date is required. When a GL period exists for the target date it is bound onto `period_id`; otherwise period_id stays null (do not invent missing months). A matching source-transaction `occurred_on` is moved in the same write. Requires audit logging and GL recompute. Does not re-date SafeGuard `qbo-sg-9852`.\n","tags":["Accountant Portal","Journal Entries"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CorrectJournalEntryDateRequest"}}}},"responses":{"200":{"description":"Journal entry date corrected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JournalEntryResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"Journal entry is already void, non-posted, or soft-deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Date is out of policy, the entry is reconciled, or the target period is filing-locked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/transactions/import":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"accountantImportTransactionsCsv","summary":"Import bank-statement CSV rows for a customer","description":"Accepts rows parsed from a bank-statement CSV in the accountant portal and posts them to the selected \"deposit to\" account. `accountId` is polymorphic — an integration_account id (Mercury/Ramp/Plaid), a bank_account id (legacy/manual), or a gl_account id (direct Chart-of-Accounts selection) — and is resolved to a concrete GL account before any rows are written. Rows are deduped by a stable (company, account/entity, date, amount, normalized description) identity stored in `transactions.external_id`, so re-uploading the same file produces zero duplicates. The command carries the concrete legal entity; it is mandatory for a direct GL-account import and must match any connected account owner. The categorization engine runs on the newly imported set. When the async job service is configured (the production default) the request returns 202 with a pending job to poll via the import-jobs endpoint; account resolution and row processing happen in the worker, and failures surface on the job record. Servers without the job service process synchronously and return 200 with the final summary.\n","tags":["Accountant Portal","Transactions"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportTransactionsCsvInput"}}}},"responses":{"200":{"description":"Import processed synchronously (job service not configured)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionImportSummaryResponse"}}}},"202":{"description":"Import job accepted (async path). Poll the import-jobs endpoint until `status` is `completed` or `failed`; the final summary lands on the job's `summary` field.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionImportJobResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"description":"Deposit-to account not found for this customer (synchronous path)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/transactions/import-jobs/{jobId}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/jobId"}],"get":{"operationId":"accountantGetTransactionImportJob","summary":"Get a CSV import job's status and result","description":"Polling endpoint for jobs created by the CSV import endpoint. While `status` is `pending` or `running`, the counter fields report progress. Once `completed`, `summary` carries the final import summary; when `failed`, `errorMessage` explains why.\n","tags":["Accountant Portal","Transactions"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Import job found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionImportJobResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"description":"CSV import jobs are not configured on this server","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/transactions/transfer-matches/{matchId}/cancel":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/matchId"}],"post":{"operationId":"accountantCancelTransferMatch","summary":"Cancel a proposed or approved transfer match","description":"Rejects a proposed/approved transfer_matches row and records the review. Applied matches must use the unwind endpoint instead so the consolidated JE is voided; unwind is not part of the service-principal manifest.\n","tags":["Accountant Portal","Transactions"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"Review reason; defaults to a generic cancellation note."}}}}}},"responses":{"200":{"description":"Cancelled transfer match"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/practice-metrics":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"accountantUploadPracticeMetrics","summary":"Upload patient-free practice-metric aggregates for a customer","description":"Upserts the practice-metrics aggregate feed for one customer: per-member revenue/cost/hours, per-channel spend and customer counts, and owner-pay scalars the Median GL cannot compute itself. Idempotent on (metricKey, period, dimensionKey): re-uploading the same payload rewrites the same rows. Optional `retireDimensionKeys` deletes only those explicit superseded labels before the upsert so a clinician-name re-upload cannot double-count `member_a` alongside `Alex Rivera`. Dimension keys may contain staff display names or channel names, but must not contain patient identifiers; values shaped like emails or phone numbers are rejected (422). Requests are capped at 2000 points; `cents` series values must be integers. Optionally upserts the practice config in the same request. Deliberately NOT gated by the customer's additionalMetrics list, so the feed loads before `practice_metrics` is listed. This is the currently configured accountant-upload path; it is not a scheduled connector.\n","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadPracticeMetricsRequest"}}}},"responses":{"200":{"description":"Upload accepted; reports rows written and the effective config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadPracticeMetricsResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"422":{"$ref":"#/components/responses/ValidationError"}}},"get":{"operationId":"accountantListPracticeMetrics","summary":"Read back the uploaded practice-metric aggregates for a customer","description":"Returns every stored practice-metric point for the customer, ordered by metric key, period, and dimension key — the readback step of the go-live sequence (upload, verify readback, flip the flag).\n","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Stored practice-metric points","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PracticeMetricPointsResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/companies/{companyId}/credit-notes":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listCreditNotes","summary":"List credit notes","description":"Temporarily unavailable in production and QA until the complete Model A credit-note aggregate is durable and atomic with its journal effects. This operation never returns an authoritative empty collection from process memory.\n","tags":["Credit Notes"],"security":[{"bearerAuth":[]}],"x-median-capability":{"status":"unavailable","reason":"durable-model-a-credit-note-persistence-required","surfaces":["production","qa"]},"responses":{"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"503":{"$ref":"#/components/responses/CreditNotesUnavailable"}}},"post":{"operationId":"createCreditNote","summary":"Create a credit-note draft","description":"Temporarily unavailable in production and QA. No credit note or accounting entry is created while durable Model A persistence is absent.\n","tags":["Credit Notes"],"security":[{"bearerAuth":[]}],"x-median-capability":{"status":"unavailable","reason":"durable-model-a-credit-note-persistence-required","surfaces":["production","qa"]},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCreditNoteInput"}}}},"responses":{"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"422":{"description":"Invalid credit-note input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"$ref":"#/components/responses/CreditNotesUnavailable"}}}},"/companies/{companyId}/credit-notes/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getCreditNote","summary":"Get one credit note","description":"Temporarily unavailable in production and QA; process memory is not an authoritative credit-note read source.\n","tags":["Credit Notes"],"security":[{"bearerAuth":[]}],"x-median-capability":{"status":"unavailable","reason":"durable-model-a-credit-note-persistence-required","surfaces":["production","qa"]},"responses":{"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"503":{"$ref":"#/components/responses/CreditNotesUnavailable"}}},"patch":{"operationId":"updateCreditNote","summary":"Update a credit-note draft","description":"Temporarily unavailable in production and QA. No ephemeral lifecycle transition is accepted.\n","tags":["Credit Notes"],"security":[{"bearerAuth":[]}],"x-median-capability":{"status":"unavailable","reason":"durable-model-a-credit-note-persistence-required","surfaces":["production","qa"]},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCreditNoteInput"}}}},"responses":{"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"422":{"description":"Invalid credit-note update","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"$ref":"#/components/responses/CreditNotesUnavailable"}}}},"/companies/{companyId}/credit-notes/{id}/issue":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"issueCreditNote","summary":"Issue a credit note","description":"Temporarily unavailable in production and QA. The request fails before GL account lookup, journal creation, or balance recomputation.\n","tags":["Credit Notes"],"security":[{"bearerAuth":[]}],"x-median-capability":{"status":"unavailable","reason":"durable-model-a-credit-note-persistence-required","surfaces":["production","qa"]},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueCreditNoteInput"}}}},"responses":{"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"503":{"$ref":"#/components/responses/CreditNotesUnavailable"}}}},"/companies/{companyId}/credit-notes/{id}/void":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"voidCreditNote","summary":"Void a credit note","description":"Temporarily unavailable in production and QA. The request fails before journal reversal, lifecycle mutation, or balance recomputation.\n","tags":["Credit Notes"],"security":[{"bearerAuth":[]}],"x-median-capability":{"status":"unavailable","reason":"durable-model-a-credit-note-persistence-required","surfaces":["production","qa"]},"responses":{"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"503":{"$ref":"#/components/responses/CreditNotesUnavailable"}}}},"/companies/{companyId}/gl-balances":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listGlBalances","summary":"Query monthly GL balances","tags":["GL Balances"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","description":"Concrete legal entity. Required when more than one authorized entity is available.","schema":{"type":"string","format":"uuid"}},{"name":"glAccountId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"monthFrom","in":"query","schema":{"type":"string","format":"date"}},{"name":"monthTo","in":"query","schema":{"type":"string","format":"date"}},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Paginated list of monthly balances","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlBalancesListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"A concrete legal entity is required when multiple authorized entities are available"}}}},"/companies/{companyId}/reports/trial-balance":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getTrialBalance","summary":"Get the trial balance as of a date","description":"Returns the trial balance for the company as of `asOfDate` (or the latest available month when omitted). The response includes `isBalanced: true` when `|debitTotal - creditTotal| <= 1 cent` (REPORT_SELF_CHECK_TOLERANCE_CENTS). Only posted GL entries are included. Uses the same computation as the accountant trial balance but is scoped to the authenticated company member.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/reportEntityId"},{"$ref":"#/components/parameters/reportReportingScopeId"},{"$ref":"#/components/parameters/reportScopeAsOf"},{"name":"asOfDate","in":"query","description":"ISO date (YYYY-MM-DD). Mid-month requests are calculated from posted entries through this exact date when an entity can be resolved; otherwise the response identifies its monthly-cache fallback.","schema":{"type":"string","format":"date"}},{"name":"endDate","in":"query","description":"Alias for asOfDate (backward compatibility).","schema":{"type":"string","format":"date"}},{"name":"month","in":"query","description":"YYYY-MM or YYYY-MM-DD month string (legacy; prefer asOfDate).","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}(-\\d{2})?$"}}],"responses":{"200":{"description":"Trial balance","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["configuredBasis","configuredBasisSource","reportBasis","asOf","accounts","debitTotal","creditTotal","differenceCents","isBalanced","source","precision"],"properties":{"ledgerRevision":{"$ref":"#/components/schemas/LedgerRevision"},"configuredBasis":{"type":"string","enum":["cash","accrual","unknown"]},"configuredBasisSource":{"type":"string","enum":["statement_basis","tax_settings","company","missing","unavailable"]},"reportBasis":{"type":"string","enum":["accrual"]},"fiscalYearEnd":{"type":["string","null"],"pattern":"^[0-9]{2}-[0-9]{2}$","description":"companies.fiscal_year_end (MM-DD); null when not confirmed (#2019)."},"fiscalYearReview":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["unknown"]}],"description":"True when companies.fiscal_year_end is set and not 12-31, or tax_settings.fiscal_year_end is set and not 12; statements are still calendar-year and need review; \"unknown\" when the fiscal year end could not be read (#2019)."},"fiscalYearReviewReason":{"type":["string","null"],"description":"Why fiscalYearReview is raised, naming the field (companies.fiscal_year_end or tax_settings.fiscal_year_end); null when not raised (#2019)."},"asOf":{"type":"string","description":"Human-readable label for the date the figures actually answer."},"asOfDate":{"type":["string","null"],"description":"Exact posted-entry cutoff or monthly-cache effective date (YYYY-MM-DD), or null when no data."},"source":{"type":"string","enum":["journal_entries","monthly_balances","issued_snapshot"]},"precision":{"type":"string","enum":["day","month"]},"accounts":{"type":"array","description":"Non-zero GL account rows.","items":{"type":"object","properties":{"accountId":{"type":"string","format":"uuid"},"number":{"type":"string"},"name":{"type":"string"},"account":{"type":"string"},"type":{"type":"string"},"debit":{"type":"number"},"credit":{"type":"number"}}}},"debitTotal":{"type":"number","description":"Total debit in dollars."},"creditTotal":{"type":"number","description":"Total credit in dollars."},"differenceCents":{"type":"integer","description":"debitTotal - creditTotal in cents. 0 when balanced."},"isBalanced":{"type":"boolean","description":"True when |differenceCents| <= 1."}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Explicit financial scope is required, or the resolved consolidated report is not yet available"}}}},"/companies/{companyId}/reports/pl":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getProfitAndLoss","summary":"Profit and loss statement","description":"P&L over a date range. When `startDate` and `endDate` are omitted the latest posted month is returned (backward-compatible with pre-date-range clients); `allTime=true` spans the first through the last posted month. `comparePeriod` optionally returns a side-by-side comparison column; `prior-period` shifts back by the range length (snapped to full months when month-aligned), `prior-year` shifts both dates back 12 months.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/reportEntityId"},{"$ref":"#/components/parameters/reportReportingScopeId"},{"$ref":"#/components/parameters/reportScopeAsOf"},{"$ref":"#/components/parameters/reportStartDate"},{"$ref":"#/components/parameters/reportEndDate"},{"$ref":"#/components/parameters/reportAllTime"},{"$ref":"#/components/parameters/reportComparePeriod"},{"$ref":"#/components/parameters/reportGranularity"},{"$ref":"#/components/parameters/reportClassId"},{"$ref":"#/components/parameters/reportGroupBy"},{"name":"tagId","in":"query","description":"Accounting tag filter (#1166). Comma-separated or repeated, up to 50. Keeps posted journal lines owned by a transaction carrying ANY listed tag: the line's own transaction link, or for an unlinked line the entry's single source transaction when no other line names a different transaction. Each line counts once however many selected tags it carries. Single legal entity only; not combinable with groupBy=class. The monthly-cache check reports NOT_CHECKED with reason tag_filtered. Every other report (balance sheet, trial balance, cash flow, exports) refuses tagId with 400, because a tag selects one leg of a balanced entry. `untagged` is refused on reports.\n","schema":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50}]}},{"name":"month","in":"query","deprecated":true,"description":"Legacy month param (YYYY-MM or YYYY-MM-DD). Prefer `startDate`/`endDate`.\n","schema":{"type":"string"}}],"responses":{"200":{"description":"P&L payload. Includes legacy numeric/boolean self-check fields and additive `checks` execution evidence for arithmetic and monthly-cache reconciliation. `isConsistent: true` alone does not prove all checks ran. When a comparison is requested, an optional `comparison` object with the same shape plus `mode`, `startDate`, `endDate`, `period` and `hasData` is included on the payload.\n","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"allOf":[{"$ref":"#/components/schemas/StatementBasisMetadata"},{"$ref":"#/components/schemas/ReportSelfCheckConsistent"},{"$ref":"#/components/schemas/LedgerRevisionStamp"},{"type":"object","properties":{"startDate":{"type":["string","null"],"format":"date"},"endDate":{"type":["string","null"],"format":"date"},"revenue":{"type":"array","description":"Operating revenue rows. Other income is reported in `otherIncome`, below operating income (#964,","items":{"type":"object"}},"otherIncome":{"type":"array","description":"Non-operating income rows (interest, FX gains; detail type `other_income`), `reportSection` `other_income`.","items":{"type":"object"}},"totalRevenue":{"type":"number","description":"Operating revenue; excludes other income."},"totalRevenueCents":{"type":"integer"},"totalCogs":{"type":"number"},"totalOpex":{"type":"number"},"totalExpenses":{"type":"number"},"operatingIncome":{"type":"number","description":"totalRevenue − totalExpenses."},"operatingIncomeCents":{"type":"integer"},"totalOtherIncome":{"type":"number"},"totalOtherIncomeCents":{"type":"integer"},"netIncome":{"type":"number","description":"operatingIncome + totalOtherIncome."},"netIncomeCents":{"type":"integer"},"comparison":{"$ref":"#/components/schemas/ProfitAndLossComparison"},"classFilter":{"$ref":"#/components/schemas/ReportClassDescriptor"},"tagFilter":{"type":"object","description":"Present when the P&L was filtered by tagId.","properties":{"tagIds":{"type":"array","items":{"type":"string","format":"uuid"}}}},"classGroups":{"type":"array","items":{"$ref":"#/components/schemas/ProfitAndLossClassGroup"}},"classReconciliation":{"$ref":"#/components/schemas/ProfitAndLossClassReconciliation"}}}]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Active accounting class filter not found"},"422":{"description":"Explicit financial scope is required, or the resolved consolidated report is not yet available"}}}},"/companies/{companyId}/reports/category-diagnostics":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getReportCategoryDiagnostics","summary":"Report/category consistency diagnostics","description":"Read-only diagnostic comparing active categorized transactions, posted income-statement journal lines, P&L rows, and GL drill-down totals for a date range. Designed for accountant QA before releasing report fixes.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/reportEntityId"},{"$ref":"#/components/parameters/reportReportingScopeId"},{"$ref":"#/components/parameters/reportScopeAsOf"},{"$ref":"#/components/parameters/reportStartDate"},{"$ref":"#/components/parameters/reportEndDate"},{"name":"month","in":"query","deprecated":true,"description":"Legacy month param (YYYY-MM or YYYY-MM-DD). Prefer `startDate`/`endDate`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Report/category consistency diagnostic payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ReportCategoryDiagnostics"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"description":"Explicit financial scope is required, or the resolved consolidated report is not yet available"}}}},"/companies/{companyId}/reports/balance-sheet":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getBalanceSheet","summary":"Balance sheet (assets, liabilities, equity)","description":"Snapshot as-of a single date. `asOfDate` (or `endDate`) selects the point in time; the latest posted month is used when omitted. `comparePeriod=prior-year` compares to the same date 12 months earlier; `prior-period` compares to the previous month-end.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/reportEntityId"},{"$ref":"#/components/parameters/reportReportingScopeId"},{"$ref":"#/components/parameters/reportScopeAsOf"},{"name":"asOfDate","in":"query","description":"As-of date (YYYY-MM-DD). Falls back to `endDate`, then `month`, then latest posted balance.","schema":{"type":"string","format":"date"}},{"name":"endDate","in":"query","description":"Alias for `asOfDate` when the client already models a date range.","schema":{"type":"string","format":"date"}},{"$ref":"#/components/parameters/reportComparePeriod"},{"name":"month","in":"query","deprecated":true,"description":"Legacy month param (YYYY-MM). Prefer `asOfDate`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Balance sheet payload. Includes additive self-check totals (`totalAssets`, `totalLiabilities`, `totalEquity`, `totalLiabilitiesAndEquity`, `differenceCents`, `isBalanced`). When a comparison is requested, an optional `comparison` object with the same shape plus `mode`, `asOfDate` and `hasData` is included on the payload.\n","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"allOf":[{"$ref":"#/components/schemas/StatementBasisMetadata"},{"$ref":"#/components/schemas/ReportSelfCheckBalanced"},{"$ref":"#/components/schemas/LedgerRevisionStamp"},{"type":"object","properties":{"totalAssets":{"type":"number"},"totalLiabilities":{"type":"number"},"totalEquity":{"type":"number"},"totalLiabilitiesAndEquity":{"type":"number"},"comparison":{"$ref":"#/components/schemas/BalanceSheetComparison"}}}]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"description":"Explicit financial scope is required, or the resolved consolidated report is not yet available"}}}},"/companies/{companyId}/reports/cash-flow":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getCashFlow","summary":"Cash flow statement (indirect method)","description":"Cash flow computed via the indirect method. Starts from net income and reconciles by adjusting for non-cash balance sheet movements. The sum of operating + investing + financing always equals the actual cash movement for the period; any unclassified drift is surfaced as \"Other net adjustments\" in operating. Accepts a date range; `comparePeriod` returns a side-by-side comparison column.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/reportEntityId"},{"$ref":"#/components/parameters/reportReportingScopeId"},{"$ref":"#/components/parameters/reportScopeAsOf"},{"$ref":"#/components/parameters/reportStartDate"},{"$ref":"#/components/parameters/reportEndDate"},{"$ref":"#/components/parameters/reportAllTime"},{"$ref":"#/components/parameters/reportComparePeriod"},{"$ref":"#/components/parameters/reportGranularity"},{"$ref":"#/components/parameters/reportClassId"},{"name":"month","in":"query","deprecated":true,"description":"Legacy month param (YYYY-MM). Prefer `startDate`/`endDate`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Cash flow payload. `checks` independently evaluates exact beginning-plus-statement-movement-equals-ending identity and the one-cent-tolerance ending-cash versus monthly-balance cross-check. Legacy `differenceFromBalanceSheetCents` remains an integer (zero when skipped); legacy `isConsistent` is false for any executed failure and true otherwise, including skipped checks. Optional `comparison` object on the payload when a comparison was requested.\n","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"allOf":[{"$ref":"#/components/schemas/StatementBasisMetadata"},{"$ref":"#/components/schemas/ReportSelfCheckConsistent"},{"$ref":"#/components/schemas/LedgerRevisionStamp"},{"type":"object","properties":{"startDate":{"type":["string","null"],"format":"date"},"endDate":{"type":["string","null"],"format":"date"},"comparison":{"$ref":"#/components/schemas/CashFlowComparison"}}}]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Active accounting class filter not found"},"422":{"description":"Explicit financial scope is required, or the resolved consolidated report is not yet available"}}}},"/companies/{companyId}/reports/pl/comparison":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getProfitAndLossComparison","summary":"Explicit two-month P&L comparison (legacy)","description":"Returns two P&L snapshots side by side. New clients should prefer `GET /reports/pl?comparePeriod=...` which supports arbitrary date ranges. This endpoint is retained for backward compatibility.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/reportEntityId"},{"$ref":"#/components/parameters/reportReportingScopeId"},{"$ref":"#/components/parameters/reportScopeAsOf"},{"name":"month1","in":"query","required":true,"schema":{"type":"string","description":"YYYY-MM"}},{"name":"month2","in":"query","required":true,"schema":{"type":"string","description":"YYYY-MM"}}],"responses":{"200":{"description":"Two P&L snapshots and a comparison block.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"description":"Explicit financial scope is required, or the resolved consolidated report is not yet available"}}}},"/companies/{companyId}/reports/general-ledger":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getGeneralLedger","summary":"General ledger (recent posted journal entries)","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/reportEntityId"},{"$ref":"#/components/parameters/reportReportingScopeId"},{"$ref":"#/components/parameters/reportScopeAsOf"},{"$ref":"#/components/parameters/reportStartDate"},{"$ref":"#/components/parameters/reportEndDate"},{"$ref":"#/components/parameters/reportAllTime"},{"$ref":"#/components/parameters/reportClassId"},{"name":"limit","in":"query","description":"Maximum journal entries per page. Defaults to 200 and is clamped to 1000.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":200}},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"General ledger payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["currency","minorUnitExponent","items","nextCursor","hasMore"],"properties":{"ledgerRevision":{"$ref":"#/components/schemas/LedgerRevision"},"currency":{"type":["string","null"],"minLength":3,"maxLength":3},"minorUnitExponent":{"type":["integer","null"],"enum":[2,null]},"items":{"type":"array","items":{"type":"object"}},"nextCursor":{"type":["string","null"]},"hasMore":{"type":"boolean"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"description":"Explicit financial scope is required, or the resolved consolidated report is not yet available"}}}},"/companies/{companyId}/reports/general-ledger/{accountId}/entries":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"accountId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getGeneralLedgerAccountEntries","summary":"Paginated journal-line drill-down for a GL account","description":"Returns all journal lines that hit the account, sorted chronologically, with a running balance per the account's normal balance. Supports date-window filtering and cursor pagination.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/reportEntityId"},{"$ref":"#/components/parameters/reportReportingScopeId"},{"$ref":"#/components/parameters/reportScopeAsOf"},{"name":"startDate","in":"query","schema":{"type":"string","format":"date"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"}},{"$ref":"#/components/parameters/reportClassId"},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Paginated drill-down payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":true,"properties":{"items":{"type":"array","items":{"type":"object"}},"ledgerRevision":{"$ref":"#/components/schemas/LedgerRevision"}}},"meta":{"type":"object","properties":{"nextCursor":{"type":["string","null"]},"hasMore":{"type":"boolean"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"description":"Explicit financial scope is required, or the resolved consolidated report is not yet available"}}}},"/companies/{companyId}/reports/ar-aging":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getArAging","summary":"Accounts receivable aging report","description":"Returns open invoices grouped by customer and by age bucket (current, 1-30, 31-60, 61-90, 90+) based on due date vs asOfDate. The aggregate and each line item carry currency/minorUnitExponent; mixed, invalid, missing, and non-two-decimal currency authority fails closed with 422 rather than publishing a false total.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"asOfDate","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"AR aging payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":true,"properties":{"unlinkedAccountantEntries":{"$ref":"#/components/schemas/UnlinkedAccountantEntries"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"description":"MONETARY_AGGREGATE_CURRENCY_UNAVAILABLE"}}}},"/companies/{companyId}/reports/ap-aging":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getApAging","summary":"Accounts payable aging report","description":"Returns unpaid bills grouped by vendor and by age bucket (current, 1-30, 31-60, 61-90, 90+) based on due date vs asOfDate. The aggregate and each line item carry currency/minorUnitExponent; mixed, invalid, missing, and non-two-decimal currency authority fails closed with 422 rather than publishing a false total.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"asOfDate","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"AP aging payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":true,"properties":{"unlinkedAccountantEntries":{"$ref":"#/components/schemas/UnlinkedAccountantEntries"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"description":"MONETARY_AGGREGATE_CURRENCY_UNAVAILABLE"}}}},"/companies/{companyId}/books/overview":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getBooksOverview","summary":"Books hub overview (today's balances, last completed month)","description":"Demo-parity customer route for an explicitly allowlisted active or test company. `/qa` callers additionally require the QA application marker and persisted test lifecycle.\nReturns a single-screen summary of the company's financial position. Balances are as of **today** (read at the current UTC month end, so they tie to the Assets and Liabilities sub-ledgers); revenue and expenses cover the **last completed calendar month** (UTC). Revenue is operating revenue (other income and 4999 Uncategorized Income excluded). Includes headline asset / liability / revenue / expense figures plus composition segments and P&L spark series for the trailing months.\nAll monetary amounts are in **cents** (integer).\nEvery amount comes from the selected entity's posted books. A liability balance is never mirrored into a synthetic asset segment. A company that has never closed a GL period still gets its real balances (#2411).\n","tags":["Books"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/reportEntityId"}],"responses":{"200":{"description":"Books overview payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/BooksOverview"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/books/schedules/recognition":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getRecognitionSchedule","summary":"Recognition / amortization schedule for a document","description":"Demo-parity customer route for an explicitly allowlisted active or test company. `/qa` callers additionally require the QA application marker and persisted test lifecycle.\nReturns the recognition or amortization schedule for a contract / invoice document line: the schedule type and a list of period entries with running cumulative amounts and posted/pending status. `{ immediate: true }` is returned only when the company posts through the subledger core and no schedule exists for the document in the selected entity. Every other schedule-less case returns `{ status, reason }` and makes no recognition claim: `unavailable`/`document_not_found` for a document outside the selected entity (unknown and sibling-entity documents are indistinguishable), `not_scheduled`/`no_business_event` for a document with no business event, and `unavailable`/`schedule_authority_not_entity_scoped` when the only schedule authority is not keyed to the selected entity.\n","tags":["Books"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/reportEntityId"},{"name":"documentId","in":"query","required":true,"description":"The invoice/bill document id. Resolved to its recognition schedule only after the document is authorized for the selected legal entity. It is then matched against `business_events.metadata.sourceDocumentId`, and the schedule keys on that event id (`event_schedules.source_event_id`).\n","schema":{"type":"string"}},{"name":"lineIndex","in":"query","required":false,"description":"Zero-based line index for multi-line documents (reserved for future use; currently only the first schedule per document is returned).\n","schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Recognition schedule payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/RecognitionSchedule"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Missing or invalid query parameters (e.g. documentId not provided)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/companies/{companyId}/sub-ledgers/revenue":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getSubLedgerRevenue","summary":"Revenue sub-ledger view","description":"Demo-parity customer route for an explicitly allowlisted active or test company.\nRange-driven revenue sub-ledger composing the P&L recognized total (posted JE lines on Revenue accounts) with booked documents (invoices in `processed` or `reviewed` status) and direct categorized transactions. Returns tiles (recognized, booked, and deferred carrying), a 6-month-floor monthly chart, and a drill-down grouped by customer. All amounts in cents. Posted-only.\n","tags":["Sub-Ledgers"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/reportStartDate"},{"$ref":"#/components/parameters/reportEndDate"},{"$ref":"#/components/parameters/reportEntityId"}],"responses":{"200":{"description":"Revenue sub-ledger payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/SubLedgerRevenueView"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Invalid query parameters (missing or malformed date range)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/companies/{companyId}/sub-ledgers/expenses":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getSubLedgerExpenses","summary":"Expenses sub-ledger view","description":"Demo-parity customer route for an explicitly allowlisted active or test company.\nRange-driven expenses sub-ledger composing the P&L recognized total (posted JE lines on Expense accounts) with booked documents (bills in `processed` or `reviewed` status) and direct categorized transactions. Returns tiles (recognized, booked, prepaid carrying, accrued carrying), a 6-month-floor monthly chart, and a drill-down grouped by GL expense category. All amounts in cents. Posted-only.\n","tags":["Sub-Ledgers"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/reportStartDate"},{"$ref":"#/components/parameters/reportEndDate"},{"$ref":"#/components/parameters/reportEntityId"}],"responses":{"200":{"description":"Expenses sub-ledger payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/SubLedgerExpensesView"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Invalid query parameters (missing or malformed date range)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/companies/{companyId}/sub-ledgers/assets":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getSubLedgerAssets","summary":"Assets sub-ledger view","description":"Demo-parity customer route for an explicitly allowlisted active or test company.\nAssets sub-ledger as of today (#2411) composing the balance-sheet asset section. Returns entity-scoped current and fixed-asset GL balances (the latter ties to /reports/balance-sheet within 1 cent). The legacy fixed-asset register is explicitly unavailable because it has no entity authority. Prepaid schedules are returned only from entity-keyed schedule definitions; legacy company-wide event schedules fail closed. Inventory is null. All amounts are in cents. Posted-only.\n","tags":["Sub-Ledgers"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/reportEntityId"}],"responses":{"200":{"description":"Assets sub-ledger payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/SubLedgerAssetsView"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/sub-ledgers/liabilities":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getSubLedgerLiabilities","summary":"Liabilities sub-ledger view","description":"Demo-parity customer route for an explicitly allowlisted active or test company.\nLiabilities sub-ledger as of today (#2411) composing the balance-sheet liability + equity section. Returns GL-derived totals (ties to /reports/balance-sheet totalLiabilities and the Books headline within 1 cent), entity-scoped credit-card GL balances, entity-keyed schedule definitions, accrued liabilities, equity accounts, and sales-tax 2200/1210 pairing. The company-wide legacy loan register is explicitly unavailable, and no APR or monthly interest is invented. Posted-only.\n","tags":["Sub-Ledgers"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/reportEntityId"}],"responses":{"200":{"description":"Liabilities sub-ledger payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/SubLedgerLiabilitiesView"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/fixed-assets":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listFixedAssets","summary":"List fixed assets (paginated, optional status filter)","tags":["Fixed Assets"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["active","retired"]}},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Paginated list of fixed assets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FixedAssetsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createFixedAsset","summary":"Create a fixed asset (auto-generates depreciation schedule)","tags":["Fixed Assets"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFixedAssetInput"}}}},"responses":{"201":{"description":"Fixed asset created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FixedAssetResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/fixed-assets/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getFixedAsset","summary":"Get a fixed asset by ID","tags":["Fixed Assets"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Fixed asset found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FixedAssetResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Fixed asset not found"}}},"patch":{"operationId":"updateFixedAsset","summary":"Update a fixed asset","tags":["Fixed Assets"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFixedAssetInput"}}}},"responses":{"200":{"description":"Fixed asset updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FixedAssetResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Fixed asset not found"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/fixed-assets/{id}/retire":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"retireFixedAsset","summary":"Retire a fixed asset","tags":["Fixed Assets"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Fixed asset retired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FixedAssetResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Fixed asset not found"},"422":{"description":"Asset is already retired"}}}},"/companies/{companyId}/fixed-assets/{id}/depreciation-schedule":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getDepreciationSchedule","summary":"Get depreciation schedule for a fixed asset","tags":["Fixed Assets"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Depreciation schedule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DepreciationScheduleResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Fixed asset not found"}}}},"/companies/{companyId}/loans":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listLoans","summary":"List loans (paginated)","tags":["Loans"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Paginated list of loans","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoansListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createLoan","summary":"Create a loan (auto-generates amortization schedule)","tags":["Loans"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLoanInput"}}}},"responses":{"201":{"description":"Loan created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoanResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/loans/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getLoan","summary":"Get a loan by ID","tags":["Loans"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Loan found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoanResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Loan not found"}}},"patch":{"operationId":"updateLoan","summary":"Update a loan","tags":["Loans"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLoanInput"}}}},"responses":{"200":{"description":"Loan updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoanResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Loan not found"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteLoan","summary":"Delete a loan (only if no payments recorded)","tags":["Loans"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Loan deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Loan not found"},"409":{"description":"Loan has recorded payments"}}}},"/companies/{companyId}/loans/{id}/amortization-schedule":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getAmortizationSchedule","summary":"Get amortization schedule for a loan","tags":["Loans"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Amortization schedule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AmortizationScheduleResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Loan not found"}}}},"/companies/{companyId}/loans/{id}/payments":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"listLoanPayments","summary":"List payments for a loan (paginated)","tags":["Loans"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Paginated list of payments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoanPaymentsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Loan not found"}}},"post":{"operationId":"createLoanPayment","summary":"Record a payment for a loan","tags":["Loans"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLoanPaymentInput"}}}},"responses":{"201":{"description":"Payment recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoanPaymentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Loan not found"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/books-status":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getBooksStatus","summary":"Get books status for a company","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current books status (returns defaults if not yet set)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BooksStatusResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"put":{"operationId":"updateBooksStatus","summary":"Update books status (upsert)","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBooksStatusInput"}}}},"responses":{"200":{"description":"Books status updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BooksStatusResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/books-integrity":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getBooksIntegrityStatus","summary":"Get the company's latest books integrity check status","description":"Read-only, any company member. Customer Reports shows a warning while `status` is `failing` (#2010, J-378).","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Latest integrity verdict, or not_checked when none exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BooksIntegrityStatusResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/weekly-email/settings":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getWeeklyEmailSettings","summary":"Get weekly summary email settings for a company","description":"Demo-parity read for an explicitly allowlisted active or test company.","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current weekly-email settings (returns defaults if not set)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WeeklyEmailSettingsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"operationId":"updateWeeklyEmailSettings","summary":"Update weekly summary email settings (upsert)","description":"Demo-parity mutation for an explicitly allowlisted active or test company. Requires company admin or owner; `/qa` callers additionally require the test-only QA boundary.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWeeklyEmailSettingsInput"}}}},"responses":{"200":{"description":"Weekly-email settings updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WeeklyEmailSettingsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/weekly-email/preview":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getWeeklyEmailPreview","summary":"Resolve the exact model that a weekly send would produce","description":"Demo-parity read for an explicitly allowlisted active or test company.\nReturns the fully-resolved email model (from, to, subject, intro, snapshot, sections, monthlyClose) built from real overview/reports metrics. The snapshot tiles carry the Live Home hero's figures for the same legal entity and day: Cash, Revenue month to date, Monthly burn (the last 90 days averaged per month; \"Not burning\" at or below zero) and Runway in whole months on gross cash (\"No net burn\" when not burning, \"120+ mo\" at the display cap). The client preview renders this exact model, so preview and the delivered email match. Any metric without a real source is omitted (never fabricated) and listed in omittedSections.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"mode","in":"query","required":false,"schema":{"type":"string","enum":["weekly","firstOfMonth"],"default":"weekly"}}],"responses":{"200":{"description":"Resolved weekly-email model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WeeklyEmailPreviewResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/comms/settings":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getCommsSettings","summary":"Get communications settings for a company","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current comms settings (returns defaults if not yet set)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommsSettingsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"put":{"operationId":"updateCommsSettings","summary":"Update communications settings (upsert)","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCommsSettingsInput"}}}},"responses":{"200":{"description":"Comms settings updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommsSettingsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/comms/contacts":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listCommsContacts","summary":"List communications contacts (paginated)","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"},{"name":"role","in":"query","schema":{"type":"string","enum":["primary","backup"]}}],"responses":{"200":{"description":"Paginated list of contacts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommsContactsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createCommsContact","summary":"Create a communications contact","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommsContactInput"}}}},"responses":{"201":{"description":"Contact created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommsContactResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/comms/contacts/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getCommsContact","summary":"Get a communications contact by ID","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Contact details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommsContactResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Contact not found"}}},"patch":{"operationId":"updateCommsContact","summary":"Update a communications contact","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCommsContactInput"}}}},"responses":{"200":{"description":"Contact updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommsContactResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Contact not found"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteCommsContact","summary":"Delete a communications contact","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Contact deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Contact not found"}}}},"/companies/{companyId}/threads":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listThreads","summary":"List threads (paginated, optional status filter)","tags":["Threads"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["open","resolved"]}},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Paginated list of threads","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createThread","summary":"Create a new thread","tags":["Threads"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateThreadInput"}}}},"responses":{"201":{"description":"Thread created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/threads/{threadId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/threadId"}],"get":{"operationId":"getThread","summary":"Get a thread by ID","tags":["Threads"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Thread found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Thread not found"}}},"patch":{"operationId":"updateThread","summary":"Update a thread (subject, status)","tags":["Threads"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateThreadInput"}}}},"responses":{"200":{"description":"Thread updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Thread not found"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteThread","summary":"Delete a thread","tags":["Threads"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Thread deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Thread not found"}}}},"/companies/{companyId}/threads/{threadId}/messages":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/threadId"}],"get":{"operationId":"listThreadMessages","summary":"List messages in a thread (chronological ASC)","description":"Each attachment is resolved for the caller on every read. A `document` or `file` attachment that resolves inside the thread's company, under the caller's own authority, with a servable stored file, is `available` and carries a `downloadUrl` minted for this caller; otherwise it is `available: false` with no link, whatever the reason.","tags":["Threads"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Paginated list of messages with embedded attachments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadMessagesListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Thread not found"}}},"post":{"operationId":"createThreadMessage","summary":"Create a message in a thread (with optional attachments)","description":"Every attached document or transaction is admitted against the thread's company and the caller's authority before anything is written; the message and its attachments are stored together or not at all.","tags":["Threads"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateThreadMessageInput"}}}},"responses":{"201":{"description":"Message created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadMessageResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The thread was not found, or an attached document or transaction does not resolve for the caller in this company. A reference that belongs to another company, one that does not exist and one the caller has no authority over get the same answer. Nothing is written."},"422":{"description":"Validation error, or `THREAD_ATTACHMENT_NOT_ACCEPTED`: an attached document the caller may see has no stored file or its scan verdict is not clean. Nothing is written."}}}},"/companies/{companyId}/scheduled-calls":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listScheduledCalls","summary":"List scheduled calls (paginated, optional status filter)","tags":["Scheduled Calls"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["scheduled","completed","cancelled"]}},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Paginated list of scheduled calls","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduledCallsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createScheduledCall","summary":"Schedule a new call","tags":["Scheduled Calls"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateScheduledCallInput"}}}},"responses":{"201":{"description":"Scheduled call created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduledCallResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/scheduled-calls/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getScheduledCall","summary":"Get a scheduled call by ID","tags":["Scheduled Calls"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Scheduled call found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduledCallResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Scheduled call not found"}}},"patch":{"operationId":"updateScheduledCall","summary":"Update a scheduled call","tags":["Scheduled Calls"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateScheduledCallInput"}}}},"responses":{"200":{"description":"Scheduled call updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduledCallResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Scheduled call not found"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteScheduledCall","summary":"Delete a scheduled call","tags":["Scheduled Calls"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Scheduled call deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Scheduled call not found"}}}},"/companies/{companyId}/documents":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listDocuments","summary":"List documents for a company","tags":["Documents"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"},{"name":"type","in":"query","schema":{"type":"string","enum":["invoice","bill","receipt","contract","statement"]}},{"name":"status","in":"query","schema":{"type":"string","enum":["needs_review","reviewed","processed","archived"]}},{"name":"category","in":"query","schema":{"type":"string"}},{"name":"search","in":"query","description":"Case-insensitive substring over the document's own descriptive fields (name, vendor name, customer name, invoice number). Deliberately not a filter on type: the displayed type is re-derived from metadata at read time, so a column filter would drop rows the UI labels bill/receipt.","schema":{"type":"string","maxLength":200}},{"name":"displayStatus","in":"query","description":"Derived Feed chip status (matched ⇔ transaction linked, unmatched ⇔ needs review with no link, bill payment labels, …). Not the stored `status` column — forwarding a chip value as `status` returns nothing because the column never holds those values. `active` (#2738) is every document that is not archived; the customer list sends it by default.","schema":{"type":"string","enum":["active","archived","paid","pending_payment","pending","matched","unmatched","processed","needs_review","reviewed"]}}],"responses":{"200":{"description":"A list of documents","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createDocument","summary":"Upload/create a document","tags":["Documents"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDocumentInput"}}}},"responses":{"201":{"description":"Document created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/documents/match-proposals/auto-apply":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"autoApplyDocumentMatchProposals","summary":"Super-admin auto-apply of high-confidence engine document-match proposals","description":"Super-admin Stage-1 sweep. Promotes high-precision engine document↔transaction match proposals (method exact_amount_date_vendor, confidence >= minConfidence, expense document -> outflow transaction, single unambiguous candidate, and current amount/date/vendor evidence still matching) to applied matches, reusing the standard match path so GL side-effects and reconciliation guards are inherited. Defaults to a dry-run; pass dryRun=false to write.\n","tags":["Documents"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"dryRun":{"type":"boolean","default":true},"minConfidence":{"type":"number","minimum":0,"maximum":1},"limit":{"type":"integer","minimum":1}}}}}},"responses":{"200":{"description":"Sweep summary with exact document/transaction identities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentMatchAutoApplyResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/documents/match-proposals/confirm":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"confirmDocumentMatchProposals","summary":"Super-admin confirm an explicit set of document-match proposal pairs","tags":["Documents"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmDocumentMatchProposalsInput"}}}},"responses":{"200":{"description":"Confirmation outcomes for every requested pair","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentMatchConfirmResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/documents/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getDocument","summary":"Get a document by ID","tags":["Documents"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Document found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Document not found"}}},"patch":{"operationId":"updateDocument","summary":"Update a document","tags":["Documents"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDocumentInput"}}}},"responses":{"200":{"description":"Document updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Document not found"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteDocument","summary":"Delete a document","tags":["Documents"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Document deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Document not found"},"409":{"description":"Immutable entity-assignment history prevents deletion"}}}},"/companies/{companyId}/documents/{id}/assignment":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"assignDocumentEntity","summary":"Assign or reassign an eligible document to a legal entity","description":"Audited assignment command for an unassigned intake document or a pre-financial-link reassignment. Requires a company administrator with all-entity authority. The target must be a concrete legal entity in this company; a financially linked document cannot be reassigned.\n","tags":["Documents"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignDocumentEntityInput"}}}},"responses":{"200":{"description":"Document assigned through the audited authority command","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Document or target legal entity not found"},"409":{"description":"Document already has the requested assignment or is not eligible for reassignment"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/transactions/{id}/document-candidates":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"listTransactionDocumentCandidates","summary":"List entity-scoped candidate documents for a transaction","description":"The mirror of /documents/{id}/match-candidates (#2013). Search and ranking run on the server; the attach-document picker previously filtered a ten-row client page, so a company holding hundreds of unmatched receipts could be shown none. Candidates are filtered on the DISPLAYED document type, which is re-derived from metadata and can differ from the stored `type` column. A candidate whose `attachedTransactionId` is non-null is already attached to another transaction: attaching it here replaces that link rather than adding one, and for a bill that reverses its payment posting.","tags":["Transactions"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"query","in":"query","description":"Case-insensitive substring over document name, vendor and invoice number.","schema":{"type":"string","maxLength":200}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":25,"default":8}}],"responses":{"200":{"description":"Ranked candidate documents, money-compatible with the transaction","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"candidates":{"type":"array","items":{"$ref":"#/components/schemas/TransactionDocumentCandidate"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/documents/{id}/match-candidates":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"listCustomerDocumentMatchCandidates","summary":"List entity-scoped candidate transactions for a customer document","tags":["Documents"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"query","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Customer-safe exact-money candidates without matcher diagnostics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerDocumentMatchCandidatesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/documents/{id}/match":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"matchCustomerDocument","summary":"Apply a customer document match through the authoritative matching service","tags":["Documents"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchDocumentInput"}}}},"responses":{"200":{"description":"Matched customer-safe document","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Document match conflicts with current accounting state"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"operationId":"unmatchCustomerDocument","summary":"Reject the active customer document match and restore review state","tags":["Documents"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Unmatched customer-safe document","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Applied accounting state cannot be safely reversed"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/documents/{id}/match-proposal":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getCustomerDocumentMatchProposal","summary":"Get the latest real persisted document-match proposal or applied allocation","tags":["Documents"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Exact public match evidence and its entity-bound transaction, or null/null","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerDocumentMatchProposalResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/documents/{documentId}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"documentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getAccountantDocument","summary":"Single document (accountant read)","description":"The accountant document DTO for one document, plus `autoMatchLastDecision` — the auto-matcher's last recorded decision for the document (outcome, reason, candidateCount, source, at), null when the auto-matcher has never abstained on it. 404 for documents that are unassigned or missing an entity, matching the other accountant document reads.\n","tags":["Accountant Documents"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Accountant document DTO + autoMatchLastDecision (object | null)"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"patchAccountantCompaniesCustomerIdDocumentsDocumentId","summary":"Update companies documents","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"delete":{"operationId":"deleteAccountantCompaniesCustomerIdDocumentsDocumentId","summary":"Delete companies documents","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/documents/{documentId}/matches":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"documentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listAccountantDocumentMatches","summary":"Full match history for a document","description":"Every document_matches row for the document — proposed, applied, and rejected — in created_at order, with provenance: honest `method` (system_auto_apply vs accountant_manual), `appliedByActorType` (engine | system | accountant | founder; null on rows predating migration 393), and the rejection/unmatch audit keys merged into match metadata by the reject/unmatch flows.\n","tags":["Accountant Documents"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Match history rows","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantDocumentMatchHistoryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/accountant/companies/{customerId}/documents/{documentId}/quickbooks-candidates":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/documentId"}],"get":{"operationId":"listAccountantDocumentQuickBooksCandidates","summary":"Review read-only QBO source candidates for one document","description":"Requires assigned-accountant document access. Uses only the exact entity's current connected realm and latest completed source snapshot; a newer active or failed run is unavailable. Never fetches from QuickBooks, attaches documents, posts journals or changes document status. Candidates are review hints, not posting authority. Money with unknown currency or scale is unavailable.","tags":["Accountant Documents"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Explicit availability and at most twenty deterministic candidates","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksDocumentCandidates"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/documents/{documentId}/match-candidates":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/documentId"}],"get":{"operationId":"listAccountantDocumentMatchCandidates","summary":"List exact-money candidates with accountant ranking diagnostics","tags":["Accountant Documents"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"query","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Accountant candidates with diagnostics bound to transaction money authority","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantDocumentMatchCandidatesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/documents/{documentId}/match":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/documentId"}],"post":{"operationId":"matchAccountantDocument","summary":"Apply an accountant document match","tags":["Accountant Documents"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MatchDocumentInput"}}}},"responses":{"200":{"description":"Matched public document projection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Document match conflicts with current accounting state"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"operationId":"unmatchAccountantDocument","summary":"Reject the active accountant document match","tags":["Accountant Documents"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Unmatched public document projection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Applied accounting state cannot be safely reversed"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/documents/{documentId}/match-proposal":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/documentId"}],"get":{"operationId":"getAccountantDocumentMatchProposal","summary":"Get persisted match evidence with accountant diagnostics","tags":["Accountant Documents"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Exact persisted match and entity-bound transaction, or null/null","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantDocumentMatchProposalResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/document-matches/{matchId}/reject":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/matchId"}],"post":{"operationId":"rejectAccountantDocumentMatch","summary":"Reject a proposed document match without ledger effects","tags":["Accountant Documents"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentMatchReasonInput"}}}},"responses":{"200":{"description":"Sanitized rejected match","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantDocumentMatchResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Match is already applied or otherwise immutable"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/document-matches/{matchId}/unmatch":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/matchId"}],"post":{"operationId":"unmatchAccountantDocumentMatchById","summary":"Reverse an applied match through the authoritative unmatch workflow","tags":["Accountant Documents"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentMatchReasonInput"}}}},"responses":{"200":{"description":"Rejected match, restored public document, and journal replacement identities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantDocumentUnmatchResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Applied accounting state cannot be safely reversed"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/match-bill":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/transactionId"}],"post":{"operationId":"matchAccountantBillPayment","summary":"Apply one exact bill-payment allocation","tags":["Accountant Documents"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentIdInput"}}}},"responses":{"201":{"description":"Exact applied allocation and journal replacement identities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantDocumentMatchMutationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Payment allocation conflicts with current accounting state"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/match-bills":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/transactionId"}],"post":{"operationId":"matchAccountantBillPayments","summary":"Apply a complete set of exact split bill-payment allocations","tags":["Accountant Documents"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentMatchAllocationsInput"}}}},"responses":{"201":{"description":"Exact applied allocations and journal replacement identities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantDocumentMatchBulkMutationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Split allocations conflict with current accounting state"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/match-receipt":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/transactionId"}],"post":{"operationId":"attachAccountantReceipt","summary":"Attach a receipt with an exact applied allocation and no journal mutation","tags":["Accountant Documents"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentIdInput"}}}},"responses":{"201":{"description":"Exact applied receipt allocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantDocumentMatchMutationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Receipt link conflicts with current accounting state"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/match-contract":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"$ref":"#/components/parameters/transactionId"}],"post":{"operationId":"attachAccountantContract","summary":"Attach a contract with an exact applied allocation and no journal mutation","tags":["Accountant Documents"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentIdInput"}}}},"responses":{"201":{"description":"Exact applied contract allocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantDocumentMatchMutationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Contract link conflicts with current accounting state"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/data-entries":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listDataEntries","summary":"List data entries for a company","tags":["Data Entries"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"},{"name":"entryType","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["active","archived"]}}],"responses":{"200":{"description":"A list of data entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataEntriesListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createDataEntry","summary":"Create a data entry","tags":["Data Entries"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDataEntryInput"}}}},"responses":{"201":{"description":"Data entry created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataEntryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/data-entries/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getDataEntry","summary":"Get a data entry by ID","tags":["Data Entries"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Data entry found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataEntryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Data entry not found"}}},"patch":{"operationId":"updateDataEntry","summary":"Update a data entry","tags":["Data Entries"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDataEntryInput"}}}},"responses":{"200":{"description":"Data entry updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataEntryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Data entry not found"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteDataEntry","summary":"Delete a data entry","tags":["Data Entries"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Data entry deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Data entry not found"}}}},"/companies/{companyId}/members":{"get":{"operationId":"listCompanyMembers","summary":"List company members","tags":["Company Members"],"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"limit","in":"query","schema":{"type":"integer","default":50}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"role","in":"query","schema":{"type":"string","enum":["owner","admin","cfo","member","viewer"]}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of company members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyMembersListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/members/{id}":{"get":{"operationId":"getCompanyMember","summary":"Get a company member by ID","tags":["Company Members"],"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Company member details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyMemberResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Company member not found"}}},"patch":{"operationId":"updateCompanyMemberRole","summary":"Update a member's role","tags":["Company Members"],"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCompanyMemberInput"}}}},"responses":{"200":{"description":"Updated company member","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyMemberResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Company member not found"},"422":{"description":"Cannot assign owner role"}}},"delete":{"operationId":"removeCompanyMember","summary":"Remove a company member","tags":["Company Members"],"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Company member removed"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Company member not found"},"422":{"description":"Cannot remove the company owner"}}}},"/companies/{companyId}/accountant-assignments":{"get":{"operationId":"listAccountantAssignments","summary":"List accountant assignments","tags":["Accountant Assignments"],"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"limit","in":"query","schema":{"type":"integer","default":50}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of accountant assignments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantAssignmentsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createAccountantAssignment","summary":"Assign an accountant to a company","tags":["Accountant Assignments"],"parameters":[{"$ref":"#/components/parameters/companyId"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountantAssignmentInput"}}}},"responses":{"201":{"description":"Assignment created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantAssignmentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/accountant-assignments/{id}":{"get":{"operationId":"getAccountantAssignment","summary":"Get an accountant assignment by ID","tags":["Accountant Assignments"],"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Accountant assignment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantAssignmentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Assignment not found"}}},"delete":{"operationId":"deleteAccountantAssignment","summary":"Remove an accountant assignment","tags":["Accountant Assignments"],"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Assignment removed"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Assignment not found"}}}},"/accountants":{"post":{"operationId":"createAccountant","summary":"Create a new accountant (super-admin only)","description":"Creates a new user + accountant profile. Gated behind a super-admin\nemail check — only callers whose JWT email matches `SUPER_ADMIN_EMAILS`\n(default: augusto@medianfi.com) may invoke this endpoint.\n","tags":["Accountants"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountantInput"}}}},"responses":{"201":{"description":"Accountant created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountantResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Email already registered"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/business-events":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listBusinessEvents","summary":"List business events for a company","description":"Superseded events are omitted (#969): an event whose journal entries have all been voided or soft-deleted no longer has a live posting behind it. Events with no journal entry at all are still returned. A page may therefore contain fewer items than `limit` while `hasMore`/`nextCursor` keep advancing; the event is still readable by id.\n","tags":["Business Events"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":200}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Business events, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/BusinessEventWire"}},"meta":{"$ref":"#/components/schemas/BusinessEventListMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createBusinessEvent","summary":"Create a business event and post its journal entry","description":"Strict by default (#1705/#1790/#1815): a request that cannot produce a journal entry — unknown event type, unresolvable accounts, or a resolve-time posting blocker (closed or missing period, filing-locked period, locked/non-postable account, out-of-domain date) — returns 422 naming the blocker, before any row is written. Pass allowWithoutJournalEntry: true to save the event with jeGenerationSkipped instead and retry-post after fixing the blocker. A client idempotencyKey identifies one create operation within this company. An identical completed request returns its existing event with 200 and idempotentReplay: true; this never posts again. A changed request or unfinished/uncertain create returns 409. Safely skipped stored outcomes remain visible on replay. A keyed posting or schedule failure returns 409 even on its first response and stays held for review because its write may already have committed. Exception (#2529): when a vendor bill's journal entry posts but its Payables bill cannot be written, the entry is voided and the outcome is known, so the create completes with 201 and jeGenerationError naming the reason; the event stays listed and can be retried or deleted. Vendor bills (#2529) also return 422 field errors for parameters.apItemId (must be a UUID), parameters.dueDate (a real YYYY-MM-DD date, not before the bill date) and parameters.createNewApItem (boolean; not together with apItemId).\n","tags":["Business Events"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBusinessEventRequest"}}}},"responses":{"200":{"description":"Completed operation replayed without creating or posting again; a safely skipped outcome remains visible","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/BusinessEventWire"}}}}}},"201":{"description":"Event created (journal entry posted, or explicitly skipped via opt-in)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/BusinessEventWire"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Same key with a different request, or creation still in progress/needs review; no new posting. Also STRIPE_CHARGE_ALREADY_BOOKED (#2424): an API-key caller booked Stripe revenue by hand (the entry credits revenue or debits Stripe Clearing) naming a ch_/pi_/txn_ id that resolves to one of this company's Stripe balance transactions the sync has posted, holds, or will post. Nothing is written; signed-in people are not subject to this check. #2529 vendor bills (vendor_bill / accounts_payable_bill). These 409s are returned while planning, before any row is written: AP_ITEM_SELECTION_REQUIRED — an open, unposted Payables bill already matches this vendor, amount and currency; extensions.candidates lists { id, vendor, amountCents, dueDate, issueDate, billNumber } (and candidateApItemIds). Resend with parameters.apItemId set to the chosen id (and that bill's billDate/dueDate), or with parameters.createNewApItem: true to record a separate bill; that override is audited on the new AP item. AP_ITEM_POSTING_CONFLICT — the selected bill differs in entity, status, amount, currency, bill date, vendor, expense account or due date (extensions.mismatches). AP_ITEM_ALREADY_POSTED — the selected bill already has a journal entry, source event or document. If the bill changes after planning (a concurrent writer), this is not a 409: the create completes with 201, the journal entry is voided, and jeGenerationError says why.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/business-events/{eventId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"eventId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getBusinessEvent","summary":"Get one business event","tags":["Business Events"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The business event","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/BusinessEventWire"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateBusinessEvent","summary":"Update an unposted business event","description":"Events with a generated journal entry or schedule cannot be edited — void and recreate instead.\n","tags":["Business Events"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBusinessEventRequest"}}}},"responses":{"200":{"description":"The updated business event","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/BusinessEventWire"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"operationId":"deleteBusinessEvent","summary":"Delete an orphan business event (zero GL impact)","description":"Orphan cleanup only (#1705/#1815) — removes an event whose journal entry generation was skipped or failed, so it carries zero GL impact. An event linked to a posted journal entry, or one driving a derived posting schedule (whose entries post to the GL), returns 409; void the journal entry first.\n","tags":["Business Events"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Event deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Event is linked to a posted journal entry or a derived posting schedule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/companies/{companyId}/business-events/{eventId}/retry-post":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"eventId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"retryPostBusinessEvent","summary":"Retry posting the journal entry for a saved event","description":"Re-runs account resolution and posting for an event saved without a journal entry. Resolve-time posting blockers return 422 naming the blocker and leave the saved event untouched; there is no allowWithoutJournalEntry affordance on retry.\n","tags":["Business Events"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"entityId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Event with the posted journal entry, or updated skip metadata","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/BusinessEventWire"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Event already has a posted journal entry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/business-events":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantListBusinessEvents","summary":"List business events for an assigned customer","description":"Historical events remain listed for accountant review. journalEntryState and journalEntryStateCounts distinguish posted, void, deleted, missing, mixed and not-posted states. generatedJEs includes only live journal entries.\n","tags":["Business Events"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":200}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Business events, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/BusinessEventWire"}},"meta":{"$ref":"#/components/schemas/BusinessEventListMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"accountantCreateBusinessEvent","summary":"Create a business event for an assigned customer","description":"Same strict-by-default contract as the customer endpoint: unresolvable accounts and resolve-time posting blockers (closed/missing period, locked account, out-of-domain date) return 422 before any row is written unless allowWithoutJournalEntry is true. An API-key caller (the bookkeeping service key) that books Stripe revenue by hand for a charge the Stripe sync already posted, holds, or will post gets 409 STRIPE_CHARGE_ALREADY_BOOKED (#2424). Vendor bills (#2529) also return 422 field errors for parameters.apItemId (must be a UUID), parameters.dueDate (a real YYYY-MM-DD date, not before the bill date) and parameters.createNewApItem (boolean; not together with apItemId).\n","tags":["Business Events"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBusinessEventRequest"}}}},"responses":{"201":{"description":"Event created (journal entry posted, or explicitly skipped via opt-in)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/BusinessEventWire"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"BUSINESS_EVENT_IDEMPOTENCY_CONFLICT (same key, different request) or STRIPE_CHARGE_ALREADY_BOOKED (#2424): an API-key caller booked Stripe revenue by hand (the entry credits revenue or debits Stripe Clearing) naming a ch_/pi_/txn_ id that resolves to one of this customer's Stripe balance transactions the sync has posted, holds, or will post. The detail names the Stripe id, the balance transaction, and why. Nothing is written. #2529 vendor bills (vendor_bill / accounts_payable_bill). These 409s are returned while planning, before any row is written: AP_ITEM_SELECTION_REQUIRED — an open, unposted Payables bill already matches this vendor, amount and currency; extensions.candidates lists { id, vendor, amountCents, dueDate, issueDate, billNumber } (and candidateApItemIds). Resend with parameters.apItemId set to the chosen id (and that bill's billDate/dueDate), or with parameters.createNewApItem: true to record a separate bill; that override is audited on the new AP item. AP_ITEM_POSTING_CONFLICT — the selected bill differs in entity, status, amount, currency, bill date, vendor, expense account or due date (extensions.mismatches). AP_ITEM_ALREADY_POSTED — the selected bill already has a journal entry, source event or document. If the bill changes after planning (a concurrent writer), this is not a 409: the create completes with 201, the journal entry is voided, and jeGenerationError says why.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/business-events/{eventId}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"eventId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"delete":{"operationId":"accountantDeleteBusinessEvent","summary":"Delete an orphan business event (zero GL impact)","description":"Human accountants only — the bookkeeping service principal's route manifest has no DELETE rule here, so bearerAuth is the only accepted scheme (deletion stays a reviewed human action).\n","tags":["Business Events"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Event deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Event is linked to a posted journal entry or a derived posting schedule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/business-events/{eventId}/retry-post":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"eventId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"accountantRetryPostBusinessEvent","summary":"Retry posting the journal entry for a saved event","tags":["Business Events"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"entityId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Event with the posted journal entry, or updated skip metadata","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/BusinessEventWire"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Event already has a posted journal entry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/me":{"get":{"operationId":"getAccountantMe","summary":"Return the logged-in accountant's profile","description":"Lightweight identity check used by the accountant app to verify the\ncurrent user is a registered accountant. Returns 403 for non-accountants.\n","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Accountant profile","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["accountantId","userId","email","displayName","assignedCompanyIds"],"properties":{"accountantId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"displayName":{"type":"string"},"email":{"type":["string","null"]},"assignedCompanyIds":{"type":"array","items":{"type":"string","format":"uuid"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/accountant/admin/custom-pricing":{"get":{"operationId":"listCustomPricingOffers","summary":"List sales-led custom pricing offers","description":"Service-key access requires SERVICE_KEY_CUSTOM_PRICING_ENABLED (default false);\notherwise the operation is concealed with 404. Human accountant access is unchanged.\nReturns all custom pricing offers (newest first). Offers are keyed by\nemail and can be recorded before the customer has an account. Accountant\nauth required (not customer-scoped).\n","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Offers, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/CustomPricingOffer"}}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createCustomPricingOffer","summary":"Create or replace a sales-led custom pricing offer for an email","description":"Service-key access requires SERVICE_KEY_CUSTOM_PRICING_ENABLED (default false);\notherwise the operation is concealed with 404. Human accountant access is unchanged.\nRecords an active offer for an email, voiding any prior active offer for\nthe same email. Price is taken in whole dollars and stored as cents.\nWhen firstMonthFree is true, checkout grants a 30-day trial.\n","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"monthlyPriceDollars":{"type":"integer","minimum":1,"maximum":1000000},"trialDays":{"type":"integer","minimum":0,"maximum":365,"description":"Free-trial days before the first charge (0 = none)."},"firstMonthFree":{"type":"boolean","description":"Deprecated back-compat alias; maps to a 30-day trial when trialDays is omitted."},"expiresAt":{"type":["string","null"],"format":"date-time"},"note":{"type":"string"},"billingInterval":{"type":"string","enum":["month","year"],"description":"Default billing interval (month when omitted). An annual offer charges monthlyPriceDollars x 10 once a year and must not carry a trial (422)."},"allowMonthly":{"type":"boolean","description":"Annual offers only: the customer may switch to monthly billing at the same band (default true)."}},"additionalProperties":false,"required":["email","monthlyPriceDollars"]}}}},"responses":{"201":{"description":"The created offer","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CustomPricingOffer"}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/admin/custom-pricing/{id}/void":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"voidCustomPricingOffer","summary":"Void an active custom pricing offer","description":"Service-key access requires SERVICE_KEY_CUSTOM_PRICING_ENABLED (default false);\notherwise the operation is concealed with 404. Human accountant access is unchanged.\n","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Void acknowledged","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"ok":{"type":"boolean"}}}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/accountant/admin/custom-pricing/{offerId}/prepared-profile":{"parameters":[{"name":"offerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getPreparedOnboardingProfile","summary":"Read the accountant-prepared onboarding profile for a custom pricing offer (#2560)","description":"Service-key access requires SERVICE_KEY_CUSTOM_PRICING_ENABLED (default false);\notherwise the operation is concealed with 404. Human accountant access is unchanged.\n","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Prepared profile with its resolved customer view","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/PreparedOnboardingProfile"}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"operationId":"upsertPreparedOnboardingProfile","summary":"Create or replace the prepared onboarding profile for a custom pricing offer (#2560)","description":"Service-key access requires SERVICE_KEY_CUSTOM_PRICING_ENABLED (default false);\notherwise the operation is concealed with 404. Human accountant access is unchanged.\nService keys cannot change or remove human-verified request definitions (403).\n","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreparedOnboardingProfileInput"}}}},"responses":{"200":{"description":"Prepared profile saved","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/PreparedOnboardingProfile"}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/admin/custom-pricing/{offerId}/prepared-profile/requests/{requestId}":{"parameters":[{"name":"offerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"requestId","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9-]{2,40}$"}}],"patch":{"operationId":"setPreparedOnboardingRequestVerified","summary":"Mark a prepared onboarding request verified (or clear it) (#2560)","tags":["Accountants"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"verified":{"type":"boolean"}},"required":["verified"],"additionalProperties":false}}}},"responses":{"200":{"description":"Updated customer view of the prepared profile","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/PreparedOnboardingProfileView"}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/integrations/quickbooks/posting-setup":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getQuickBooksPostingSetup","summary":"QuickBooks posting cutoff and account mappings for a customer (#2642)","description":"The accountant-set cutoff (with history) and every QuickBooks account from the latest completed source read with its approved Median GL mapping and cash source. Read-only; nothing here posts or writes to QuickBooks.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Posting setup","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksPostingSetup"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"QuickBooks is not connected (QUICKBOOKS_LEDGER_NOT_CONNECTED)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"503":{"description":"Selected account-reference projection is not verified (QUICKBOOKS_REFERENCE_PROJECTION_NOT_READY); no transfer is applied and no recursive fallback runs","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/arap-enablement":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getQuickBooksArApEnablement","summary":"Whether QuickBooks invoices and bills can post for a customer (#2642)","description":"Invoices, bills, customer and bill payments, credit memos and vendor credits post through the AR/AP items subledger, which is off until the company's subledger conversion has run and passed its integrity check. Read-only.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Enablement status","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksArApEnablementStatus"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"enableQuickBooksArAp","summary":"Turn on QuickBooks invoices and bills for a customer (#2642)","description":"Runs the one-time subledger conversion on this company's Median books and only turns invoices and bills on when it passes: enter dual_read, convert (re-tags business-event journal entries' provenance; lines and amounts never change), validate INV-1..9 against a pre-conversion snapshot, stamp that validation, then set ar_ap_items_enabled. Idempotent and resumable: an enabled company returns `already_enabled`; a converted but unvalidated company resumes at validation. A failed or incomplete check returns 200 with `outcome: validation_failed` and the failing checks, and leaves the company in dual_read with invoices and bills off. Requires a verified QuickBooks connection. Never changes immediate AP journal entries or Stripe invoice sync. Takes no body.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Result of the attempt (check `outcome`)","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksArApEnablementResult"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"QuickBooks is not connected (QUICKBOOKS_LEDGER_NOT_CONNECTED), or the conversion state changed concurrently","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/posting-cutoff":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"setQuickBooksPostingCutoff","summary":"Record the date from which Median posts QuickBooks activity (#2642)","description":"Appends a cutoff that supersedes the current one. Activity dated before the cutoff stays read-only. `expectedCurrentCutoffId` must name the cutoff being replaced (null for the first); a stale value returns 409.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["cutoffDate","reason","expectedCurrentCutoffId"],"properties":{"cutoffDate":{"type":"string","format":"date"},"reason":{"type":"string","minLength":1,"maxLength":1000},"expectedCurrentCutoffId":{"type":["string","null"],"format":"uuid"}}}}}},"responses":{"200":{"description":"The recorded cutoff","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksPostingCutoff"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"The cutoff changed since it was read","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Validation error, or QuickBooks is not connected","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/account-mappings":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"approveQuickBooksAccountMappings","summary":"Approve QuickBooks account to Median GL account mappings (#2642)","description":"Each mapping supersedes the account's current mapping. Accounts must come from the latest completed QuickBooks read; GL accounts must be active accounts of the customer. `cashSource` defaults to `quickbooks` (QBO's own feed brings that account's cash, so Median never posts it back).","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["mappings"],"properties":{"mappings":{"type":"array","minItems":1,"maxItems":500,"items":{"type":"object","additionalProperties":false,"required":["qboAccountId","glAccountId"],"properties":{"qboAccountId":{"type":"string","minLength":1,"maxLength":128},"glAccountId":{"type":"string","format":"uuid"},"cashSource":{"type":"string","enum":["quickbooks","median"],"default":"quickbooks"}}}}}}}}},"responses":{"200":{"description":"The recorded mappings","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["mappings"],"properties":{"mappings":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksAccountMapping"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"A mapping changed concurrently","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Validation error, unknown QuickBooks account, invalid GL account, or no completed QuickBooks read","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/account-mapping-transfers":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"transferQuickBooksAccountMappings","summary":"Explicitly release inactive cash mappings and approve their replacements","description":"Dry run is the default and changes nothing. Apply requires the same source run, complete expected current mapping IDs, reason, exact transfers, expiry and digest returned by the dry run. In one transaction the API records immutable releases and replacement mappings with actor and API-key audit. Old QuickBooks accounts must be inactive Bank/Card accounts with no current source activity since the cutoff; replacements must be active accounts of the same type/currency on the same GL and cash source. Concurrent source/mapping or pending import/writeback work blocks apply. No bank/GL status, provenance, journal, provider or historical receipt is changed. Released old accounts with new activity hold imports instead of falling through to Ask My Accountant. Requires fresh accountant assignment; the reviewed service principal may call this high-impact route.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["expectedSourceRunId","expectedMappingIds","transfers","reason"],"properties":{"dryRun":{"type":"boolean","default":true},"expectedSourceRunId":{"type":"string","format":"uuid"},"expectedMappingIds":{"type":"array","maxItems":10000,"items":{"type":"string","format":"uuid"}},"reason":{"type":"string","minLength":10,"maxLength":1000},"expiresAt":{"type":"string","format":"date-time","description":"Required on apply; copy the dry-run expiry (at most ten minutes)."},"planDigest":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Required on apply; copy the dry-run digest."},"transfers":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"object","additionalProperties":false,"required":["oldMappingId","newQboAccountId","glAccountId","cashSource"],"properties":{"oldMappingId":{"type":"string","format":"uuid"},"newQboAccountId":{"type":"string","minLength":1,"maxLength":128},"glAccountId":{"type":"string","format":"uuid"},"cashSource":{"type":"string","enum":["quickbooks","median"]}}}}}}}}},"responses":{"200":{"description":"Prepared transfer plan or atomically applied mappings","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["dryRun","sourceRunId","expectedMappingIds","expiresAt","planDigest","transfers","mappings"],"properties":{"dryRun":{"type":"boolean"},"sourceRunId":{"type":"string","format":"uuid"},"expectedMappingIds":{"type":"array","items":{"type":"string","format":"uuid"}},"expiresAt":{"type":"string","format":"date-time"},"planDigest":{"type":"string"},"transfers":{"type":"array","items":{"type":"object","required":["oldMappingId","oldQboAccountId","newQboAccountId","sourceObjectId","glAccountId","cashSource"],"properties":{"oldMappingId":{"type":"string","format":"uuid"},"oldQboAccountId":{"type":"string"},"newQboAccountId":{"type":"string"},"sourceObjectId":{"type":"string","format":"uuid"},"glAccountId":{"type":"string","format":"uuid"},"cashSource":{"type":"string","enum":["quickbooks","median"]}}}},"mappings":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksAccountMapping"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Source, mappings, pending work or dry-run digest changed; prepare again","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Invalid economic replacement, source activity, scope, currency or reconciliation authority","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"503":{"description":"Selected account-reference projection is not verified (QUICKBOOKS_REFERENCE_PROJECTION_NOT_READY); no transfer is applied and no recursive fallback runs","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/account-mappings/auto":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"autoMapQuickBooksAccounts","summary":"Map unmapped QuickBooks accounts automatically (#2642)","description":"Fills only QuickBooks accounts with no current mapping (an existing mapping always wins), from the latest completed QuickBooks read, in order: system role (A/R, A/P, retained earnings, opening balance equity), connected bank/card last four digits, exact account number or name. For an established QuickBooks file (a transaction dated before the posting cutoff), also creates a Median account mirroring each remaining QuickBooks account, renames role-matched system accounts to the QuickBooks name, and deactivates unused Median accounts that have no QuickBooks counterpart. A new file (or no cutoff) gets matches only. Idempotent; nothing posts. The same run happens after every completed QuickBooks read.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false}}}},"responses":{"200":{"description":"What this run did","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksAutoMapSummary"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"A mapping changed concurrently; run again","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Validation error, QuickBooks not connected, or no completed QuickBooks read","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"503":{"description":"Selected account-reference projection is not verified (QUICKBOOKS_REFERENCE_PROJECTION_NOT_READY); no transfer is applied and no recursive fallback runs","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/statement-accounts/{bankAccountId}/retire":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"bankAccountId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"retireQuickBooksStatementAccount","summary":"Retire Median's QuickBooks statement account for an account made inactive in QuickBooks (#3489)","description":"Marks Median's own institution \"QuickBooks\" statement account (no provider, integration or external id) `disconnected`, requiring immutable creation-mapping provenance recorded when the materializer inserted the row. Unverified legacy or manual rows return 422 `QUICKBOOKS_STATEMENT_ACCOUNT_PROVENANCE_UNVERIFIED`; labels, timestamps and matching shape do not establish provenance, and this endpoint cannot recover it. The GL account can then be separately deactivated through `chart-of-accounts/{accountId}/deactivate`, subject to its guards, including posted lines in an open period even at zero net balance. Allowed only while every current mapping to that GL account is a QuickBooks Bank or Credit Card account that the latest completed read found inactive. The row and its reconciliations are kept; the change and the reason are audited with the actor (and, for the agent service token, its key) in the same transaction. A customer's bank connection, an already retired row, or an account still active in QuickBooks is refused (422). Median never reactivates the row; GET posting-setup reports `quickbooks_account_inactive` and `quickbooks_account_reactivated` instead.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["reason"],"properties":{"reason":{"type":"string","minLength":1,"maxLength":1000}}}}}},"responses":{"200":{"description":"The statement account was retired","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["bankAccountId","glAccountId","qboAccountId","status"],"properties":{"bankAccountId":{"type":"string","format":"uuid"},"glAccountId":{"type":"string","format":"uuid"},"qboAccountId":{"type":"string"},"status":{"type":"string","enum":["disconnected"]}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No such bank account for this customer","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Validation error, QuickBooks not connected or not read yet, not Median's QuickBooks statement account (QUICKBOOKS_STATEMENT_ACCOUNT_NOT_RETIRABLE), or not mapped only to QuickBooks bank or card accounts read inactive (QUICKBOOKS_ACCOUNT_NOT_INACTIVE)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/trial-balances":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listQuickBooksTrialBalances","summary":"QuickBooks trial balance snapshots read for a customer (#2642)","description":"The latest 20 immutable TrialBalance report snapshots (lossless amounts, integer cents per account row).","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Snapshots","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["snapshots"],"properties":{"snapshots":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksTrialBalanceSnapshot"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"QuickBooks is not connected","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}},"post":{"operationId":"fetchQuickBooksTrialBalance","summary":"Read QuickBooks' TrialBalance report as of a date into immutable evidence (#2642)","description":"Calls QuickBooks' TrialBalance report (accrual basis) with `end_date = asOfDate` and stores the payload immutably with its SHA-256. The opening-balance batch needs the snapshot as of the day before the cutoff. Nothing posts.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["asOfDate"],"properties":{"asOfDate":{"type":"string","format":"date"}}}}}},"responses":{"201":{"description":"The stored snapshot","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksTrialBalanceSnapshot"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error, QuickBooks not connected, or the report's period, basis or currency does not match","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"503":{"description":"QuickBooks is unavailable or returned an unexpected report","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/import-batches":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listQuickBooksImportBatches","summary":"QuickBooks import batches for a customer (#2642)","description":"The latest 50 batches with item counts per decision.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Batches","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["batches"],"properties":{"batches":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/QuickBooksImportBatch"},{"type":"object","required":["counts"],"properties":{"counts":{"type":"object","additionalProperties":{"type":"integer","minimum":0}}}}]}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"QuickBooks is not connected","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}},"post":{"operationId":"createQuickBooksImportBatch","summary":"Build a draft QuickBooks import batch (#2642)","description":"`opening_balance`: one balanced brought-forward entry at the cutoff from a trial balance snapshot as of the day before the cutoff; after the opening is posted, a later snapshot builds a true-up that posts only the per-account difference. `activity`: every postable QuickBooks object from the latest completed read dated from the cutoff through `dateTo` (default today) that is not already posted, each with a default decision (post, duplicate of a native bank row, skip, or blocked with a reason). Nothing posts until the batch is approved and posted.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","additionalProperties":false,"required":["kind","trialBalanceSnapshotId"],"properties":{"kind":{"type":"string","enum":["opening_balance"]},"trialBalanceSnapshotId":{"type":"string","format":"uuid"}}},{"type":"object","additionalProperties":false,"required":["kind"],"properties":{"kind":{"type":"string","enum":["activity"]},"dateTo":{"type":"string","format":"date"}}}]}}}},"responses":{"201":{"description":"The draft batch","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksImportBatch"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Validation error, no cutoff, no completed QuickBooks read, wrong trial balance date, nothing to import, or too many objects","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/import-batches/{batchId}":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"batchId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getQuickBooksImportBatch","summary":"One QuickBooks import batch with a page of its items (#2642)","description":"`manifestSha256` is the hash approval must present (recomputed for a draft; the approved hash otherwise; null when the batch is stale).","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Batch with items","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["batch","manifestSha256","items","page","arApSubledger","parity"],"properties":{"batch":{"$ref":"#/components/schemas/QuickBooksImportBatch"},"manifestSha256":{"type":["string","null"]},"arApSubledger":{"description":"Whether the batch's invoices, bills and their payments/credits post into Median's AR/AP subledger. `blockCode` is arap_subledger_disabled when invoices and bills are off (arap-enablement): since #2642 automatic posting those items still post, to the GL only, with no AR/AP item. Null when the server has no database.","oneOf":[{"type":"object","required":["enabled","arApItems","blockCode"],"properties":{"enabled":{"type":"boolean"},"arApItems":{"type":"integer","minimum":0,"description":"Unposted AR/AP items in the batch"},"blockCode":{"type":["string","null"],"enum":["arap_subledger_disabled",null]}}},{"type":"null"}]},"parity":{"description":"Latest QuickBooks parity check, information only (approval never depends on it); null when none has run.","oneOf":[{"$ref":"#/components/schemas/QuickBooksParitySummary"},{"type":"null"}]},"items":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksImportItem"}},"page":{"type":"object","required":["limit","offset","total"],"properties":{"limit":{"type":"integer"},"offset":{"type":"integer"},"total":{"type":"integer"}}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/integrations/quickbooks/import-batches/{batchId}/items/{itemId}":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"batchId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"updateQuickBooksImportItem","summary":"Change a draft import item's decision (#2642)","description":"`post` re-validates the object against the current cutoff and mappings; `duplicate` names the native bank transaction to keep (QuickBooks' category is applied to it on post unless `applyQboCategory` is false); `skip` leaves the object out. Refused (409) once the batch is approved.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["decision"],"properties":{"decision":{"type":"string","enum":["post","duplicate","skip"]},"duplicateTransactionId":{"type":["string","null"],"format":"uuid"},"applyQboCategory":{"type":"boolean"}}}}}},"responses":{"200":{"description":"The updated item","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksImportItem"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The batch is no longer a draft, or the cutoff changed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Validation error, or the decision is not valid for this object (the code names why)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/import-batches/{batchId}/approve":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"batchId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"approveQuickBooksImportBatch","summary":"Approve a draft import batch's exact decisions (#2642)","description":"`manifestSha256` must equal the hash recomputed from the current item decisions, cutoff and mappings (409 otherwise). Every item marked `post` or `duplicate` is re-validated; an opening balance must be postable. Decisions freeze on approval. The preparer may approve.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuickBooksManifestInput"}}}},"responses":{"200":{"description":"The approved batch","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksImportBatch"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Manifest mismatch, batch not a draft, cutoff changed, or another opening balance is live","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Validation error, or items that cannot post as decided (listed in the problem's `invalid`)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/import-batches/{batchId}/post":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"batchId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"postQuickBooksImportBatch","summary":"Post an approved import batch into Median's books (#2642)","description":"Presents the approved manifest. Idempotent: re-posting a posted batch returns `replayed` results and creates nothing. A failing item is marked failed with its code and the batch `failed` while successful items stay posted; posting again resumes the unfinished items. Each posted object gets an active pull link.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuickBooksManifestInput"}}}},"responses":{"200":{"description":"The batch and each item's result","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["batch","results"],"properties":{"batch":{"$ref":"#/components/schemas/QuickBooksImportBatch"},"results":{"type":"array","items":{"type":"object","required":["itemId","result","errorCode"],"properties":{"itemId":{"type":"string","format":"uuid"},"result":{"type":"string","enum":["posted","replayed","linked","skipped","failed"]},"errorCode":{"type":["string","null"]}}}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Manifest mismatch, batch not approved, stale (cutoff or mappings changed), or already posting","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/integrations/quickbooks/import-batches/{batchId}/cancel":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"batchId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"cancelQuickBooksImportBatch","summary":"Cancel an import batch that has posted nothing (#2642)","description":"A draft, or an approved batch none of whose items has a result, can be cancelled.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"The cancelled batch","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksImportBatch"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The batch is posting, posted, or already cancelled","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/parity":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getQuickBooksParity","summary":"QuickBooks ↔ Median parity per account, to the cent (#2642)","description":"Without `asOf`, returns the latest stored check (null when none has run). With `asOf`, reads QuickBooks' TrialBalance as of that date and ProfitAndLoss from the posting cutoff through it, compares each mapped account with Median's GL at a 0-cent tolerance, stores the result and returns it. Before the cutoff the status is `not_applicable` and QuickBooks is not called. Read-only toward QuickBooks and the GL; a daily check also runs after each completed QuickBooks read. The result is information and never blocks posting or approval.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"asOf","in":"query","required":false,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Parity result (or null when no check exists and asOf was omitted)","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"oneOf":[{"$ref":"#/components/schemas/QuickBooksParityResult"},{"type":"null"}]}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error, QuickBooks not connected, no cutoff, no completed QuickBooks read, or a report period/basis/currency mismatch","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"503":{"description":"QuickBooks is unavailable or returned an unexpected report","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/reconciliation-snapshots":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getQuickBooksReconciliationSnapshots","summary":"Accountant-entered QuickBooks reconciliation snapshots and their parity with Median (#2873)","description":"For a client whose books are on QuickBooks, returns per bank or card account the current accountant-entered QuickBooks snapshot (reconciled-through date and ending balance, who recorded it and when), Median's latest completed reconciliation of that account (statement ending date and statement ending balance), and the parity between the two. Median does not read these values from QuickBooks and never writes them there: the snapshot is a person's statement. The comparison is between two recorded figures; it does not re-read the ledger, so a journal posted into the reconciled window after Median's completion is not detected here. Parity is derived at read time and never stored, in this order: `not_verified` when no snapshot exists, when Median has no completed reconciliation, when the snapshot is stale, when Median's reconciliation is not clean (its difference is not exactly 0, or it was force-completed, including a quick-complete within a tolerance), or when the currencies differ; `behind` when QuickBooks is reconciled through an earlier date, `ahead` when later; on the same date `agree` when the balances are equal and `balance_differs` when not. Tolerance is 0: cents are compared exactly. `balanceComparison` says how: `signed` compares the values as stored; `magnitude`, used for credit-card accounts only, compares absolute values, because QuickBooks shows a card balance as a positive amount owed while Median's reconciliations store it with either sign. Staleness rule (no day count): a snapshot is stale when Median completed a reconciliation of that account after the snapshot was recorded. Without `bankAccountId` the list holds every business bank or card account of the client. A snapshot whose bank account was later deleted is kept as history and is not listed. When the company has no QuickBooks ledger connection the answer is `applicable: false` with an empty list. Read-only.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"bankAccountId","in":"query","required":false,"description":"Limit the answer to one bank or card account of this client.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Parity per account, or a not-applicable answer","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksReconciliationParityView"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"}}},"post":{"operationId":"recordQuickBooksReconciliationSnapshot","summary":"Record what QuickBooks shows as reconciled for one account (#2873)","description":"Appends one accountant-entered snapshot for a bank or card account of a QuickBooks client: the reconciled-through date and ending balance read from QuickBooks' Reconcile screen. Who recorded it and when are set by the server; a body that carries them is refused. Append-only: a new reading is a new row and becomes the current snapshot; there is no idempotency key, so a replay records a second row. `currency` must be the account's currency. Nothing is written to QuickBooks, no reconciliation changes and the ledger is not touched. Human accountants only (hidden from the service key); the assignment is re-read before the write. A company whose books are not on QuickBooks is refused with 422 `QUICKBOOKS_RECONCILIATION_SNAPSHOT_NOT_APPLICABLE`.","tags":["Accountants"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuickBooksReconciliationSnapshotInput"}}}},"responses":{"201":{"description":"The account's parity with the recorded snapshot as current","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksReconciliationAccountParity"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"503":{"description":"The accountant assignment could not be re-read before the write; retry","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/change-reviews":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["open","resolved_take_qbo","resolved_keep_median","dismissed"]}}],"get":{"operationId":"listQuickBooksChangeReviews","summary":"QuickBooks changes to objects Median already posted, awaiting or after review (#2642)","description":"Opened by the daily QuickBooks re-read when an object Median posted (dated on or after the posting cutoff) changes economically or disappears in QuickBooks. Open reviews first; at most 500 rows.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Change reviews","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["reviews"],"properties":{"reviews":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksChangeReviewSummary"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/integrations/quickbooks/change-reviews/{reviewId}":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"reviewId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getQuickBooksChangeReview","summary":"One QuickBooks change review with a field-level before/after diff (#2642)","description":"The diff covers economic fields only (dates, amounts, accounts, counterparties, currency, lines); SyncToken, metadata and display names are excluded, but reference names are shown alongside ids.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"The review","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksChangeReviewDetail"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/accountant/companies/{customerId}/integrations/quickbooks/change-reviews/{reviewId}/resolve":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"reviewId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"resolveQuickBooksChangeReview","summary":"Decide a QuickBooks change (#2642)","description":"`take_qbo` deactivates the link so the next activity import re-imports QuickBooks' version; Median's old entry must be reversed (followupStatus `reversal_pending` until the reversal flow is wired). `keep_median` keeps Median's version. When QuickBooks changed only a line's account or class or the memo of a pulled Purchase/Deposit, a draft write-back batch restoring Median's values is prepared (`writeback_requested`; it still needs approval and posting). Otherwise the restore stays `writeback_pending` with `followupReason` (`client_must_correct_quickbooks` or `writeback_not_possible`). `dismiss` records the reason and changes nothing now in Median or QuickBooks. For a change (not a deletion), Median's link then approves the reviewed QuickBooks version, so later reads and the activity import no longer flag it as changed. For an object Median pushed, it leaves the outstanding count at once, and the bank-feed push still writes Median's category to QuickBooks whenever the transaction changed after Median's last write to it, including before the dismissal. For an object Median pulled, it leaves the outstanding count with the next activity batch, and Median's entry keeps the earlier version; only the general-ledger parity check still shows a difference. A reason is required; the actor and time are recorded. When `expectedAfterSourceObjectId` is given and QuickBooks changed again since, or the review is no longer open, returns 409.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["resolution","reason"],"properties":{"resolution":{"type":"string","enum":["take_qbo","keep_median","dismiss"]},"reason":{"type":"string","minLength":1,"maxLength":2000},"expectedAfterSourceObjectId":{"type":["string","null"],"format":"uuid"}}}}}},"responses":{"200":{"description":"The resolved review","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksChangeReview"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Already resolved, or QuickBooks changed again since it was read (QUICKBOOKS_CHANGE_REVIEW_STALE)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/transactions/quickbooks-review":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"afterReviewKey","in":"query","description":"Opaque generation-bound continuation returned as nextCursor; not an item identity.","schema":{"type":"string","minLength":1,"maxLength":512}}],"get":{"operationId":"listAccountantQuickBooksTransactionReview","summary":"Read QuickBooks source items for the existing Transactions review surface","description":"Human-accountant, company-scoped read of at most 50 immutable Purchase/Deposit identities. A matched native UUID is separate from the opaque reviewKey; source-only items create no native transaction or journal. Pending work remains needs_review until provider verification and genuine canonical mirror evidence agree. This dedicated read requires a live verified source; the existing unified Transactions queue separately keeps unavailable historical work held with canCategorize false. Changed pagination generation refuses. This read performs no provider, token-refresh or ledger writes. Service principals are forbidden.","tags":["Accountants"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Bounded review rows and truthful generation-bound continuation","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["items","hasMore","nextCursor"],"properties":{"hasMore":{"type":"boolean"},"nextCursor":{"type":["string","null"]},"items":{"type":"array","maxItems":50,"items":{"type":"object","required":["id","reviewKey","sourceKind","nativeTransactionId","customerId","entityId","sourceObjectId","sourceRunId","status","workflowState","mirrorState","canCategorize"],"properties":{"id":{"type":"string","description":"Actual matched native UUID or opaque source-only item key."},"reviewKey":{"type":"string","description":"Opaque scoped item identity; never a native transaction UUID."},"sourceKind":{"type":"string","enum":["quickbooks"]},"nativeTransactionId":{"type":["string","null"],"format":"uuid"},"customerId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"sourceObjectId":{"type":"string","format":"uuid"},"sourceRunId":{"type":"string","format":"uuid"},"date":{"type":["string","null"]},"occurredOn":{"type":"string"},"description":{"type":"string"},"amountCents":{"type":["integer","null"],"description":"Exact legacy cents projection; unavailable source money is null."},"currency":{"type":["string","null"]},"minorUnitExponent":{"type":"integer","enum":[2]},"direction":{"type":"string","enum":["in","out"]},"status":{"type":"string","enum":["needs_review","categorized"]},"categoryGlAccountId":{"type":["string","null"],"format":"uuid"},"pendingCategoryGlAccountId":{"type":["string","null"],"format":"uuid"},"workflowState":{"type":"string","enum":["pending","verified","conflict","failed"]},"mirrorState":{"type":"string","enum":["awaiting_verification","pending","refreshed"]},"canCategorize":{"type":"boolean"},"blockCode":{"type":["string","null"]},"lastErrorCode":{"type":["string","null"]}}}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Source authority or pagination generation changed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"Review source is not configured","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/transactions/review/quickbooks-category":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"approveAccountantQuickBooksTransactionCategory","summary":"Apply an accountant category intent to the same imported QuickBooks object","description":"Existing Transactions category approval, requiring authenticated human accountant access, current scoped reviewKey and exact sourceObjectId. Internally uses the existing audited sparse-update outbox and original QuickBooks Id/SyncToken. The selected category stays pending until provider verification and canonical mirror refresh; no independent local reclassification or duplicate cash journal is created. Live verified connection, cutoff, approved noncash mapping, immutable money/bank/date headers and filing authority are revalidated. Uncertain work reconciles its original request rather than blindly creating another write. Service principals are forbidden.","tags":["Accountants"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["reviewKey","expectedSourceObjectId","categoryGlAccountId"],"properties":{"reviewKey":{"type":"string","maxLength":512,"pattern":"^qbo:[A-Za-z0-9_-]+$"},"expectedSourceObjectId":{"type":"string","format":"uuid"},"categoryGlAccountId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Audited category intent; read the review queue for verified mirror completion","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["reviewKey","batchId","status"],"properties":{"reviewKey":{"type":"string"},"batchId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["needs_review"]}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Imported source, pending intent or filing authority changed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"Writeback or imported mirror is disabled or unavailable","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/writebacks/imported-review":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"afterLinkId","in":"query","schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listQuickBooksImportedReview","summary":"Imported QuickBooks holding-category items and sparse-writeback receipts","description":"Read-only keyset queue of at most 50 active pulled Purchase/Deposit links from the verified company/entity/connection/realm's latest completed source read, on or after the current posting cutoff. Includes Ask My Accountant source items and items with a sparse-writeback receipt. No provider, document or ledger writes. Unsupported lines and open change reviews remain visible.","tags":["Accountants"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Source items with pending, verified, conflict or failed receipt state","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["cutoffDate","items","nextCursor","categories"],"properties":{"cutoffDate":{"type":"string","format":"date"},"nextCursor":{"type":["string","null"],"format":"uuid"},"categories":{"type":"array","items":{"type":"object","required":["glAccountId","qboAccountId"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"qboAccountId":{"type":"string"}}}},"items":{"type":"array","items":{"type":"object","required":["linkId","objectType","providerId","sourceObjectId","sourceRunId","txnDate","total","bankAccountId","lines","state","batchId","itemStatus","blockCode","lastErrorCode"],"properties":{"linkId":{"type":"string","format":"uuid"},"objectType":{"type":"string","enum":["Purchase","Deposit"]},"providerId":{"type":"string"},"sourceObjectId":{"type":"string","format":"uuid"},"sourceRunId":{"type":"string","format":"uuid"},"txnDate":{"type":["string","null"]},"total":{"type":["string","null"]},"bankAccountId":{"type":["string","null"]},"state":{"type":"string","enum":["pending","verified","conflict","failed"]},"batchId":{"type":["string","null"],"format":"uuid"},"itemStatus":{"type":["string","null"]},"blockCode":{"type":["string","null"]},"lastErrorCode":{"type":["string","null"]},"mirrorState":{"type":"string","enum":["awaiting_verification","pending","blocked","refreshed"]},"canCategorize":{"type":"boolean"},"lines":{"type":"array","items":{"type":"object","required":["id","amount","accountId","classId"],"properties":{"id":{"type":"string"},"amount":{"type":"string"},"accountId":{"type":"string"},"classId":{"type":["string","null"]}}}}}}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"},"503":{"description":"Imported review reader is not configured","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/writebacks/eligible":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"dateFrom","in":"query","required":false,"schema":{"type":"string","format":"date"}},{"name":"dateTo","in":"query","required":false,"schema":{"type":"string","format":"date"}}],"get":{"operationId":"listQuickBooksWritebackCandidates","summary":"Median journal entries that could be written back to QuickBooks (#2642)","description":"Journal entries of the connected QuickBooks company's entity dated on or after the posting cutoff (at most 500, oldest first; `hasMore` when truncated), each with `eligible` and every block reason. Only adjusting entries created in Median are eligible; bank-feed, bill/invoice, payment/payroll, provider-derived, QuickBooks-pulled (including the opening balance) and closing entries, entries with an unmapped or ambiguously mapped account, a Median class, a foreign currency, or a cash/bank/card line whose mapping says QuickBooks' own feed brings that cash are blocked. Read-only.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Candidates with eligibility","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["cutoffId","cutoffDate","candidates","hasMore"],"properties":{"cutoffId":{"type":"string","format":"uuid"},"cutoffDate":{"type":"string","format":"date"},"hasMore":{"type":"boolean"},"candidates":{"type":"array","items":{"type":"object","required":["journalEntryId","entryDate","description","eligible","blocks"],"properties":{"journalEntryId":{"type":"string","format":"uuid"},"entryDate":{"type":"string","format":"date"},"description":{"type":"string"},"eligible":{"type":"boolean"},"blocks":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksWritebackBlock"}}}}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Invalid dates, QuickBooks not connected, or no posting cutoff (QUICKBOOKS_WRITEBACK_NO_CUTOFF)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/writebacks":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listQuickBooksWritebackBatches","summary":"QuickBooks write-back batches for a customer (#2642)","description":"The 100 most recent batches of the connected QuickBooks company, newest first.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Batches","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["batches"],"properties":{"batches":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksWritebackBatch"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"QuickBooks is not connected","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}},"post":{"operationId":"createQuickBooksWritebackBatch","summary":"Prepare a draft QuickBooks write-back batch (#2642)","description":"Stores, for review, the exact QuickBooks request of every selected item with its SHA-256, a stable Intuit `requestid`, and the batch manifest hash that approve and post must present. Nothing is sent to QuickBooks. Named `journalEntryIds` are kept even when blocked (as `blocked` items with their reason); a `dateFrom`/`dateTo` range adds only eligible entries. `sparseUpdates` correct an object pulled from QuickBooks (Purchase or Deposit): `glAccountId` is reverse-mapped to its single QuickBooks account, `classId` is a QuickBooks Class Id, `memo` sets the private note. Amounts, dates and the bank/card account are never changed. 422 QUICKBOOKS_WRITEBACK_NOTHING_ELIGIBLE when no item is eligible; 409 when an entry is already held by another batch.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"journalEntryIds":{"type":"array","maxItems":200,"items":{"type":"string","format":"uuid"}},"dateFrom":{"type":"string","format":"date"},"dateTo":{"type":"string","format":"date"},"sparseUpdates":{"type":"array","maxItems":200,"items":{"type":"object","additionalProperties":false,"required":["linkId"],"properties":{"linkId":{"type":"string","format":"uuid"},"expectedSourceObjectId":{"type":"string","format":"uuid"},"glAccountId":{"type":"string","format":"uuid"},"classId":{"type":"string","pattern":"^[0-9]{1,32}$"},"memo":{"type":"string","maxLength":4000},"lineIds":{"type":"array","minItems":1,"maxItems":250,"items":{"type":"string","minLength":1,"maxLength":64}}}}}}}}}},"responses":{"201":{"description":"The draft batch with its items","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksWritebackBatchDetail"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"An entry or object is already held by another write-back batch","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Validation error, unknown entry or link, nothing eligible, no cutoff, or QuickBooks not connected","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/writebacks/{batchId}":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"batchId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getQuickBooksWritebackBatch","summary":"A QuickBooks write-back batch with its items and request payloads (#2642)","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"The batch","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksWritebackBatchDetail"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/accountant/companies/{customerId}/integrations/quickbooks/writebacks/{batchId}/approve":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"batchId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"approveQuickBooksWritebackBatch","summary":"Approve a draft QuickBooks write-back batch (#2642)","description":"The caller presents the batch's manifest hash; the same person may prepare and approve. Records the approver and time. 409 on a manifest mismatch or when the batch is not a draft.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuickBooksWritebackManifestInput"}}}},"responses":{"200":{"description":"The approved batch","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksWritebackBatchDetail"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Manifest mismatch (QUICKBOOKS_WRITEBACK_MANIFEST_MISMATCH) or batch not in draft","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/integrations/quickbooks/writebacks/{batchId}/post":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"batchId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"postQuickBooksWritebackBatch","summary":"Write an approved batch to the customer's QuickBooks (#2642)","description":"Re-validates every unsent item (eligibility, request hash, cutoff, realm), then sends each with its stored Intuit `requestid` (a retry after a timeout cannot double-create), records the QuickBooks Id and SyncToken, and reads the object back: a match is `verified` (and a push link is recorded), a difference is `failed` with QUICKBOOKS_WRITEBACK_READBACK_MISMATCH. Items whose outcome is unknown stay `sending` and the batch stays `posting`; call post again to retry. Refused with 422 QUICKBOOKS_WRITEBACK_DISABLED while QUICKBOOKS_WRITEBACK_ENABLED is off.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuickBooksWritebackManifestInput"}}}},"responses":{"200":{"description":"The batch after posting (status posted, posting or failed)","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksWritebackBatchDetail"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Manifest mismatch, batch state, cutoff or realm changed, an entry changed since approval, or another post in progress","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Validation error, write-back switched off (QUICKBOOKS_WRITEBACK_DISABLED), or QuickBooks not connected","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"503":{"description":"QuickBooks write-back is not configured","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/writebacks/{batchId}/cancel":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"batchId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"cancelQuickBooksWritebackBatch","summary":"Cancel a draft or approved QuickBooks write-back batch (#2642)","description":"Releases the batch's entries for a new batch and records who cancelled it and when. 409 once posting has started.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"The cancelled batch","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksWritebackBatchDetail"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The batch is posting, posted, failed or already cancelled","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/chart-push":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"previewQuickBooksChartPush","summary":"Whether the QuickBooks file is new, and which Median accounts a chart push would create, map or skip (#2642)","description":"`state` is judged from the latest completed QuickBooks read. `no_inventory`: no read has completed yet. `inventory_unverified` (#2883): that read cannot be shown to hold every transaction, because for at least one transaction type (the types Median posts: JournalEntry, Purchase, Deposit, Transfer, SalesReceipt, RefundReceipt, Invoice, Bill, Payment, BillPayment, CreditMemo, VendorCredit) QuickBooks' census of the read is missing or differs from the rows the read stored; `unverifiedInventory` names each failed check, `entries` is empty and the file is never classified, with or without a cutoff. With a verified inventory and a posting cutoff, `new` means no transaction is dated before the cutoff and `established` means one is (the chart then comes from QuickBooks and a chart push is refused). The preview also runs before a posting cutoff is set (#2883): `cutoffDate` is then null, and the file is `new` only when the verified inventory holds no transaction at all (dated or undated); otherwise it is `unclassified`: the plan is still returned so the chart can be prepared and reviewed, and `transactions` lists the inventoried transactions as a warning, but nothing can be pushed until a cutoff classifies the file. Items, tax codes, tax rates and tax agencies are not transactions. `transactionCount` and `transactions` cover the latest completed read plus any newer read attempt (queued, running or failed) of the same connection, so a transaction a newer unfinished read already stored is seen; `transactions` is capped at 50, undated first and then by date, and `transactionCount` is always the total. Preparing a chart push (POST) requires a cutoff, a `new` file and no read attempt newer than the completed read. For `new` and `unclassified`, `entries` lists every active Median GL account, parents first: `create` (with the QuickBooks AccountType/AccountSubType and parent it will be created under), `map` (QuickBooks already has it: an account every new QuickBooks company has, such as Accounts Receivable, Accounts Payable or Retained Earnings, or one with the same number or name) or `skip` (already mapped, held by another batch, an internal clearing account without a balance, an ambiguous match or a type conflict), each with its reason. Read-only: it creates no cutoff, batch, journal or mapping and makes no QuickBooks call.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"The chart push preview","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksChartPushPreview"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"QuickBooks is not connected","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}},"post":{"operationId":"prepareQuickBooksChartPush","summary":"Prepare a draft batch that creates Median's chart of accounts in a new QuickBooks file (#2642)","description":"Jacob 2026-09-28: for a client new to both Median and QuickBooks, Median's chart of accounts is mirrored into QuickBooks. Builds ONE draft write-back batch: a pending `create_account` item per Median account QuickBooks lacks (Name, AcctNum = Median code, AccountType/AccountSubType from the Median detail type; a sub-account's ParentRef is resolved from its parent's created QuickBooks Id at send time, so parents are created first), and a `blocked` item per account that is mapped instead (`QUICKBOOKS_CHART_PUSH_ALREADY_IN_QUICKBOOKS`; the mapping is recorded when the batch posts) or skipped (its reason code). Nothing is sent: the batch is approved and posted through the write-back batch routes, and each created account is read back and then recorded as a QuickBooks account mapping. Takes no body. 422 QUICKBOOKS_CHART_PUSH_ESTABLISHED_FILE when QuickBooks has transactions before the cutoff, QUICKBOOKS_CHART_PUSH_NO_INVENTORY before a completed QuickBooks read, QUICKBOOKS_CHART_PUSH_INVENTORY_UNVERIFIED when the latest completed read cannot be shown to hold every transaction (`unverifiedInventory` in the problem names the failed checks; posting an approved chart push re-applies the same rule and answers 409 with the same code), QUICKBOOKS_CHART_PUSH_NEWER_READ_UNFINISHED while a QuickBooks read started after that completed read is queued, running or failed (`newerRunStatus` in the problem; the preview still shows the file as `new` so it does not change during each read, and posting an approved chart push answers 409 with the same code until a newer read completes), QUICKBOOKS_CHART_PUSH_NOTHING_TO_CREATE when nothing is missing, QUICKBOOKS_WRITEBACK_NO_CUTOFF before a posting cutoff is set (only the preview runs without one); 409 when an account is already held by another batch.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false}}}},"responses":{"201":{"description":"The draft batch with its items","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksWritebackBatchDetail"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"An account is already held by another write-back batch (QUICKBOOKS_WRITEBACK_ALREADY_HELD)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Established QuickBooks file, no completed QuickBooks read, nothing to create, no cutoff, or QuickBooks not connected","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/integrations/quickbooks/coverage":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"period","in":"query","required":true,"schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"}}],"get":{"operationId":"getQuickBooksLedgerCoverage","summary":"Median-owned QuickBooks bank/card posting coverage for a period (#2560)","description":"Reads bank and credit-card accounts from the connected QuickBooks ledger and the posted activity per account in the period. Intuit's public API has no bank-feed review queue, so coverage is posted activity; gaps are explicit exceptions.","tags":["Accountants"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Coverage report","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"period":{"type":"string"},"checkedAt":{"type":"string","format":"date-time"},"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"number":{"type":["string","null"]},"type":{"type":"string","enum":["Bank","Credit Card"]},"txnCount":{"type":"integer"},"lastTxnDate":{"type":["string","null"]},"coverage":{"type":"string","enum":["complete","partial","none"]}},"required":["id","name","number","type","txnCount","lastTxnDate","coverage"]}},"exceptions":{"type":"array","items":{"type":"string"}}},"required":["period","checkedAt","accounts","exceptions"]}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/integrations/quickbooks/connection-import":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"importQuickBooksLedgerConnection","summary":"Connect QuickBooks from a refresh token already issued to Median's Intuit app","description":"Refreshes the token with Median's own Intuit credentials (422 QUICKBOOKS_LEDGER_IMPORT_REJECTED and nothing stored if Intuit refuses), then follows the browser callback's path: CompanyInfo read, realm verification, encrypted token storage and the source-inventory enqueue. The response never contains a token.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"realmId":{"type":"string","pattern":"^[0-9]{1,32}$"},"refresh_token":{"type":"string","minLength":1,"maxLength":4096}},"required":["realmId","refresh_token"],"additionalProperties":false}}}},"responses":{"201":{"description":"Connection status after verification","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksLedgerStatus"}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/integrations/quickbooks/connection":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getAccountantQuickBooksLedgerConnection","summary":"QuickBooks connection state for an assigned customer, including needs_reauth (#2821)","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Connection status (realm masked; never a token)","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksLedgerStatus"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/accountant/companies/{customerId}/integrations/quickbooks/source-sync":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getAccountantQuickBooksSourceSync","summary":"Read the QuickBooks source-read status for an assigned customer (#2821)","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Source-read status; state is \"disabled\" while QUICKBOOKS_SOURCE_SYNC_ENABLED is off","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksSourceStatus"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"QuickBooks is not connected or needs reauthorizing (QUICKBOOKS_LEDGER_NOT_CONNECTED, QUICKBOOKS_LEDGER_NEEDS_REAUTH), the connection changed, or source sync is switched off (QUICKBOOKS_SOURCE_SYNC_DISABLED, POST only)"},"503":{"description":"Source sync or the provider is unavailable"}}},"post":{"operationId":"retryAccountantQuickBooksSourceSync","summary":"Queue a fresh read of the customer's verified QuickBooks realm (#2821)","description":"Only queues the read; the source-sync worker reads QuickBooks, then auto-map and automatic posting run as after the daily re-read. Refuses with 422 QUICKBOOKS_SOURCE_SYNC_DISABLED while QUICKBOOKS_SOURCE_SYNC_ENABLED is off.","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Queued source-read status; the active run when one is already queued or running","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksSourceStatus"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"QuickBooks is not connected or needs reauthorizing (QUICKBOOKS_LEDGER_NOT_CONNECTED, QUICKBOOKS_LEDGER_NEEDS_REAUTH), the connection changed, or source sync is switched off (QUICKBOOKS_SOURCE_SYNC_DISABLED, POST only)"},"503":{"description":"Source sync or the provider is unavailable"}}}},"/accountant/companies/{customerId}/integrations/quickbooks/source-preview":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getAccountantQuickBooksSourcePreview","summary":"Bounded preview of the customer's imported QuickBooks source objects (#2821)","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Up to 25 realm-bound source identities from one completed run","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","maxItems":25,"items":{"$ref":"#/components/schemas/QuickBooksSourcePreviewItem"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"QuickBooks is not connected or needs reauthorizing (QUICKBOOKS_LEDGER_NOT_CONNECTED, QUICKBOOKS_LEDGER_NEEDS_REAUTH), the connection changed, or source sync is switched off (QUICKBOOKS_SOURCE_SYNC_DISABLED, POST only)"},"503":{"description":"Source sync or the provider is unavailable"}}}},"/accountant/companies/{customerId}/integrations/quickbooks/status":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getAccountantQuickBooksCustomerStatus","summary":"QuickBooks read state, coverage, books state and gaps for an assigned customer (#2821)","tags":["Accountants"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"The customer-facing QuickBooks status","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/QuickBooksCustomerStatus"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"QuickBooks is not connected or needs reauthorizing (QUICKBOOKS_LEDGER_NOT_CONNECTED, QUICKBOOKS_LEDGER_NEEDS_REAUTH), the connection changed, or source sync is switched off (QUICKBOOKS_SOURCE_SYNC_DISABLED, POST only)"},"503":{"description":"Source sync or the provider is unavailable"}}}},"/accountant/companies/{customerId}/business-model":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"updateCompanyBusinessModel","summary":"Set a customer's stored business model and/or its additional-metrics list (accountant only)","description":"Two independent halves (#1967). `model` pins the stored `businessModel` as an accountant override (`businessModelOverride = model`, `businessModelSource = override`); it is never null — a stored model is required and only an accountant's pick can replace a derivation. `additionalMetrics` replaces the customer's per-company metric-pack list and touches nothing else (a pack tick never changes the model, its override or its source). At least one of the two keys is required. Accountant-only; requires `requireAccountantAccessToCompany` guard.\n","tags":["Accountants"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"At least one of `model` / `additionalMetrics` is required; a null `model` is rejected with 422.\n","properties":{"model":{"description":"The business model to store as the accountant override. `general` is retired.","type":"string","enum":["software","services","digital","ecommerce","manufacturing"]},"additionalMetrics":{"description":"The complete list of additional metric packs enabled for this customer (duplicates dropped). Unknown ids are rejected with 422.","type":"array","items":{"type":"string","enum":["practice_metrics"]}}}}}}},"responses":{"200":{"description":"Updated company with the stored businessModel/businessModelOverride/businessModelSource and additionalMetrics","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","description":"Company object with businessModel, businessModelOverride, businessModelSource and additionalMetrics fields.","additionalProperties":true}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error — `model` outside the five assignable values (or null), an unregistered `additionalMetrics` id, or a body with neither key.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/members":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listAccountantCustomerMembers","summary":"List customer app members for an accountant customer","tags":["Accountants"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"role","in":"query","schema":{"type":"string","enum":["owner","admin","cfo","member","viewer"]}},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Customer app members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyMembersListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/accountant/companies/{customerId}/classes":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listAccountantAccountingClasses","summary":"List customer accounting classes as accountant","tags":["Accounting Classes"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"includeInactive","in":"query","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Accounting classes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingClassesListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createAccountantAccountingClass","summary":"Create a customer accounting class","tags":["Accounting Classes"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountingClassInput"}}}},"responses":{"201":{"description":"Accounting class created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingClassResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Class name already exists for customer"},"422":{"description":"Validation error"}}}},"/accountant/companies/{customerId}/classes/proposals":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listAccountingClassProposals","summary":"List customer class assignment proposals","tags":["Accounting Classes"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["proposed","approved","applied","rejected","correction_proposed"]}},{"name":"transactionId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Accounting class proposals","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingClassProposalsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/accountant/companies/{customerId}/classes/proposals/bulk":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"bulkReviewAccountingClassProposals","summary":"Bulk approve, change, or reject class proposals","tags":["Accounting Classes"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkAccountingClassProposalActionInput"}}}},"responses":{"200":{"description":"Bulk class proposal action result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingClassProposalBulkActionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/classes/proposals/{proposalId}/approve":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"proposalId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"approveAccountingClassProposal","summary":"Approve a class assignment proposal","tags":["Accounting Classes"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveAccountingClassProposalInput"}}}},"responses":{"200":{"description":"Class proposal approved or converted to correction proposal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingClassProposalActionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/classes/proposals/{proposalId}/reject":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"proposalId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"rejectAccountingClassProposal","summary":"Reject a class assignment proposal","description":"Rejects an unapplied proposed, approved, or correction proposal. Applied proposals are immutable.","tags":["Accounting Classes"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectAccountingClassProposalInput"}}}},"responses":{"200":{"description":"Class proposal rejected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingClassProposalActionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/ConflictJson"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/classes/{classId}":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"classId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"updateAccountantAccountingClass","summary":"Update a customer accounting class","tags":["Accounting Classes"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAccountingClassInput"}}}},"responses":{"200":{"description":"Accounting class updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingClassResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Accounting class not found"},"409":{"description":"Class name already exists for customer"},"422":{"description":"Validation error"}}}},"/accountant/companies/{customerId}/tags":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listAccountantAccountingTags","summary":"List accounting tags","description":"Company-owned controlled tag vocabulary (#1166). Retired tags are omitted unless includeRetired=true. Assigned accountants only.\n","tags":["Accounting Tags"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"includeRetired","in":"query","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingTagsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createAccountantAccountingTag","summary":"Create an accounting tag","tags":["Accounting Tags"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingTagNameInput"},"example":{"name":"Paid social"}}}},"responses":{"201":{"description":"Tag created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingTagResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"A live tag with the same name (ignoring case and repeated spaces) exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/tags/{tagId}":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"tagId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"renameAccountantAccountingTag","summary":"Rename an accounting tag","tags":["Accounting Tags"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingTagNameInput"}}}},"responses":{"200":{"description":"Tag renamed; assignments keep the same tag ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingTagResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A live tag with the same name exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/tags/{tagId}/retire":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"tagId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"retireAccountantAccountingTag","summary":"Retire an accounting tag","description":"Idempotent. A retired tag keeps its existing assignments and history but cannot be newly assigned. Tags are never deleted.\n","tags":["Accounting Tags"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Tag retired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingTagResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/tags":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getAccountantTransactionTags","summary":"Get a transaction's tags and revision","tags":["Accounting Tags"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionTagAssignmentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"operationId":"replaceAccountantTransactionTags","summary":"Replace a transaction's tags","description":"Sends the full tag set with the revision the client loaded. A different set at a stale revision is 409 and changes nothing; an identical set is an idempotent no-op. Never changes amounts, accounts, dates, status or reconciliation state; reconciled transactions may be tagged. Refused (422) when the transaction or a linked posted entry is in a filing-locked period. Assigned accountants only.\n","tags":["Accounting Tags"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplaceTransactionTagsInput"},"example":{"tagIds":["6f1b2a4e-8f7c-4b8e-9d2a-1c3e5f7a9b0d"],"expectedRevision":0}}}},"responses":{"200":{"description":"Tags replaced (or unchanged)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionTagAssignmentResponse"},"example":{"success":true,"data":{"transactionId":"0b8f2c1e-2d7a-4c3b-9e1f-5a6b7c8d9e0f","tagIds":["6f1b2a4e-8f7c-4b8e-9d2a-1c3e5f7a9b0d"],"revision":1}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The tags changed since the client loaded them (TAG_REVISION_CONFLICT)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation failed, unknown or retired tag, or filing-locked period","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/members/{id}":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/resourceId"}],"patch":{"operationId":"updateAccountantCustomerMemberRole","summary":"Update a customer app member role","tags":["Accountants"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCompanyMemberInput"}}}},"responses":{"200":{"description":"Customer app member role updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyMemberResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Customer app member not found"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/invites":{"get":{"operationId":"listUserInvites","summary":"List user invites","tags":["User Invites"],"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"limit","in":"query","schema":{"type":"integer","default":50}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","accepted","expired","revoked"]}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of user invites","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInvitesListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createUserInvite","summary":"Send a user invite","tags":["User Invites"],"parameters":[{"$ref":"#/components/parameters/companyId"}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserInviteInput"}}}},"responses":{"201":{"description":"Invite created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInviteResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/invites/{id}":{"get":{"operationId":"getUserInvite","summary":"Get a user invite by ID","tags":["User Invites"],"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User invite details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInviteResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Invite not found"}}},"delete":{"operationId":"revokeUserInvite","summary":"Revoke a user invite","tags":["User Invites"],"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Invite revoked"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Invite not found"}}}},"/companies/{companyId}/tax-settings":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getTaxSettings","summary":"Get tax settings for a company","tags":["Tax Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current tax settings (returns defaults if not yet set)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxSettingsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"put":{"operationId":"updateTaxSettings","summary":"Update tax settings (upsert). Snapshots prior effective state to history.","tags":["Tax Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTaxSettingsInput"}}}},"responses":{"200":{"description":"Tax settings updated. Returns the underlying tax_settings row; call GET to see the merged effective view + history.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTaxSettingsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/forecast/projection":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getForecastProjection","summary":"Project the forecast model into all three scenarios (worst/base/best)","tags":["Forecast"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"horizon","in":"query","description":"Projection horizon in months (12, 18, or 24)","schema":{"type":"integer","enum":[12,18,24],"default":12}},{"name":"levers","in":"query","description":"Comma-separated lever IDs to apply before projection","schema":{"type":"string","example":"raise_prices,accelerate_new_business"}},{"name":"scenario","in":"query","description":"Hint for which scenario to highlight (response always includes all three)","schema":{"type":"string","enum":["worst","base","best"]}}],"responses":{"200":{"description":"Projection result with all scenarios, runway, and KPIs","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ProjectionResult"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"}}}},"/companies/{companyId}/forecast/projection/preview":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"previewForecastProjection","summary":"Project a transient aggregate without persisting it","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["model"],"properties":{"horizon":{"type":"integer","enum":[12,18,24],"default":12},"levers":{"type":"array","items":{"type":"string","enum":["raise_prices","accelerate_new_business","make_a_key_hire","trim_opex","churn_up","raise_financing"]}},"model":{"allOf":[{"$ref":"#/components/schemas/ForecastModel"}],"description":"Persisted company forecast model used for a transient preview; never written"},"streams":{"type":"array","items":{"$ref":"#/components/schemas/ForecastStream"}},"headcount":{"type":"array","items":{"$ref":"#/components/schemas/ForecastHeadcount"}},"opex":{"type":"array","items":{"$ref":"#/components/schemas/ForecastOpex"}},"scenarios":{"type":"array","items":{"$ref":"#/components/schemas/ForecastScenario"}}}}}}},"responses":{"200":{"description":"Projection result (not persisted)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ProjectionResult"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"}}}},"/companies/{companyId}/forecast/sensitivity":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getForecastSensitivity","summary":"Compute per-lever sensitivity (sorted by absolute 12-month cash delta)","tags":["Forecast"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"levers","in":"query","description":"Comma-separated active lever IDs (already applied before sensitivity is computed)","schema":{"type":"string"}},{"name":"horizon","in":"query","description":"Projection horizon in months (12, 18, or 24)","schema":{"type":"integer","enum":[12,18,24],"default":12}}],"responses":{"200":{"description":"Ranked list of sensitivity items","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/SensitivityItem"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"}}}},"/companies/{companyId}/forecast/decisions":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getForecastDecisions","summary":"Get recommended decisions with tone and cash impact","tags":["Forecast"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"levers","in":"query","description":"Comma-separated active lever IDs","schema":{"type":"string"}},{"name":"horizon","in":"query","description":"Projection horizon in months (12, 18, or 24)","schema":{"type":"integer","enum":[12,18,24],"default":12}}],"responses":{"200":{"description":"Decision items with tone and delta","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/DecisionItem"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"}}}},"/companies/{companyId}/tax-deadlines":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listTaxDeadlines","summary":"List tax deadlines (paginated, optional status filter)","tags":["Tax Deadlines"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["completed","upcoming","pending"]}},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Paginated list of tax deadlines","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxDeadlinesListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createTaxDeadline","summary":"Create a tax deadline","tags":["Tax Deadlines"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaxDeadlineInput"}}}},"responses":{"201":{"description":"Tax deadline created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxDeadlineResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/tax-deadlines/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getTaxDeadline","summary":"Get a tax deadline by ID","tags":["Tax Deadlines"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Tax deadline found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxDeadlineResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Tax deadline not found"}}},"patch":{"operationId":"updateTaxDeadline","summary":"Update a tax deadline","tags":["Tax Deadlines"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTaxDeadlineInput"}}}},"responses":{"200":{"description":"Tax deadline updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaxDeadlineResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Tax deadline not found"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteTaxDeadline","summary":"Delete a tax deadline","tags":["Tax Deadlines"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Tax deadline deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Tax deadline not found"}}}},"/companies/{companyId}/integrations/stripe/auth-url":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"createStripeAuthorizationUrl","summary":"Start the Stripe install flow (alias of install-link)","description":"Returns the Stripe marketplace install URL. Preflights the Stage-A GL compatibility guard for allowlisted companies, so a blocking account collision fails here rather than stranding a half-finished install.\n","tags":["Stripe Connect"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeInstallLinkInput"}}}},"responses":{"200":{"description":"Stripe install URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeInstallLinkResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/StripeGlAccountRebindRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/companies/{companyId}/integrations/stripe/install-link":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"createStripeInstallLink","summary":"Start the Stripe install flow","tags":["Stripe Connect"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeInstallLinkInput"}}}},"responses":{"200":{"description":"Stripe install URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeInstallLinkResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/StripeGlAccountRebindRequired"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/companies/{companyId}/integrations/stripe/connection":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getStripeConnectionStatus","summary":"Stripe connection status","description":"Read-only. For an allowlisted company the payload may carry `accountingBlock`, which separates codes that need accountant review (`accountCodes`) from codes that self-heal on the next sync through the audited adoption path (`adoptableCodes`).\n","tags":["Stripe Connect"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Connection status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeConnectionStatusResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/integrations/stripe/disconnect":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"disconnectStripe","summary":"Disconnect a Stripe account","description":"Marks the connection disconnected. Connection rows are never deleted — the imported transaction archive is bound to them.\n","tags":["Stripe Connect"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeDisconnectInput"}}}},"responses":{"200":{"description":"Disconnected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeDisconnectResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/integrations/stripe/sync":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"triggerStripeSync","summary":"Trigger an incremental Stripe sync","tags":["Stripe Connect"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Sync counters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeSyncResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/StripeGlAccountRebindRequired"}}}},"/companies/{companyId}/integrations":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listIntegrations","summary":"List integration connections (paginated)","tags":["Integrations"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"},{"name":"status","in":"query","schema":{"type":"string","enum":["connected","disconnected"]}},{"name":"provider","in":"query","schema":{"type":"string"}},{"name":"entityId","in":"query","description":"Scope connections to one authorized legal entity. A uuid requires access to that entity; `consolidated` requires all-entity authority. Omitting the parameter returns only the actor's authorized entities.","schema":{"oneOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["consolidated"]}]}}],"responses":{"200":{"description":"Paginated list of integration connections","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationConnectionsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Invalid entity scope"}}},"post":{"operationId":"createIntegration","summary":"Create an integration connection","tags":["Integrations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIntegrationConnectionInput"}}}},"responses":{"201":{"description":"Integration connection created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationConnectionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/integrations/{integrationId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/integrationId"}],"get":{"operationId":"getIntegration","summary":"Get an integration connection by ID","tags":["Integrations"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Integration connection found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationConnectionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Integration connection not found"}}},"patch":{"operationId":"updateIntegration","summary":"Update an integration connection","tags":["Integrations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIntegrationConnectionInput"}}}},"responses":{"200":{"description":"Integration connection updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationConnectionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Integration connection not found"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteIntegration","summary":"Delete an integration connection","tags":["Integrations"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Integration connection deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Integration connection not found"}}}},"/companies/{companyId}/financial-sync/plaid/exchange":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"completeCompanyPlaidExchange","summary":"Complete an authorized Plaid bank connection","tags":["Integrations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["publicToken","institutionId","state","redirectUri"],"properties":{"publicToken":{"type":"string","minLength":1,"maxLength":8192},"institutionId":{"type":"string","minLength":1,"maxLength":1024},"state":{"type":"string","minLength":1,"maxLength":8192,"description":"authorizationState returned by the company Link-token endpoint."},"redirectUri":{"type":"string","format":"uri","maxLength":2048}}}}}},"responses":{"201":{"description":"Connection result, including an existing owner when no new account was connected","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"integrationId":{"type":"string","format":"uuid"},"connection":{"type":"object"},"accounts":{"type":"array","items":{"type":"object"}},"syncJob":{"type":["object","null"]},"alreadyConnected":{"type":"boolean","enum":[true],"description":"Present only when a duplicate Item was parked and the existing owner was returned without importing new accounts or starting a sync job."}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Authorization or account ownership conflict"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/financial-sync/plaid/relink-token/{integrationId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/integrationId"}],"post":{"operationId":"createPlaidRelinkToken","summary":"Mint a Plaid Link token in update mode for an existing Item","description":"Starts the self-serve reconnect for a Plaid connection that is flagged needs_reauth. The returned authorizationState must be echoed back to the completion endpoint. A connection whose status is not `connected` was stopped on purpose and is refused with PLAID_RELINK_NOT_APPLICABLE — that customer must connect the bank again rather than reconnect.","tags":["Integrations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["redirectUri"],"properties":{"redirectUri":{"type":"string","format":"uri","maxLength":2048,"description":"Allowlisted Plaid OAuth return URI."}}}}}},"responses":{"200":{"description":"Update-mode Link token and its single-use authorization state","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"linkToken":{"type":"string"},"expiration":{"type":"string","format":"date-time"},"integrationId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"authorizationState":{"type":"string"},"authorizationExpiresAt":{"type":"string","format":"date-time"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Integration connection not found for this company"},"409":{"description":"Connection is not `connected` (PLAID_RELINK_NOT_APPLICABLE) — it was deliberately disconnected and cannot be reconnected in update mode."},"422":{"description":"Validation error"}}}},"/companies/{companyId}/financial-sync/plaid/relink/{integrationId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/integrationId"}],"post":{"operationId":"completePlaidRelink","summary":"Finish a Plaid update-mode relink and resume ingestion","description":"The client's word that Link succeeded is not trusted: Plaid is asked for the Item's own state first. An Item still reporting a reauth-class error keeps needs_reauth and answers 409. On success needs_reauth is cleared, the open reauth_required action item is resolved and an incremental sync is claimed. `status` is left untouched.","tags":["Integrations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["state","redirectUri"],"properties":{"state":{"type":"string","maxLength":8192,"description":"authorizationState returned by the relink-token endpoint."},"redirectUri":{"type":"string","format":"uri","maxLength":2048}}}}}},"responses":{"200":{"description":"Connection healed and ingestion resumed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"integrationId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"itemId":{"type":["string","null"]},"needsReauth":{"type":"boolean","enum":[false]},"resolvedActionItems":{"type":"integer"},"syncJob":{"type":["object","null"],"description":"Claimed sync job, or null when none could be started."}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Integration connection not found for this company"},"409":{"description":"PLAID_RELINK_INCOMPLETE (Item still reports a reauth-class error), PLAID_RELINK_NOT_APPLICABLE (connection is not `connected`), or the authorization state belongs to a different legal entity."},"422":{"description":"Validation error"}}}},"/companies/{companyId}/integrations/{integrationId}/accounts":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/integrationId"}],"get":{"operationId":"listIntegrationAccounts","summary":"List accounts for an integration (paginated)","tags":["Integration Accounts"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Paginated list of integration accounts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationAccountsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Integration connection not found"}}},"post":{"operationId":"createIntegrationAccount","summary":"Create an integration account","tags":["Integration Accounts"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIntegrationAccountInput"}}}},"responses":{"201":{"description":"Integration account created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationAccountResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Integration connection not found"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/integrations/{integrationId}/accounts/{accountId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/integrationId"},{"$ref":"#/components/parameters/accountId"}],"get":{"operationId":"getIntegrationAccount","summary":"Get an integration account by ID","tags":["Integration Accounts"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Integration account found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationAccountResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Integration account not found"}}},"patch":{"operationId":"updateIntegrationAccount","summary":"Update an integration account (only glAccountId)","tags":["Integration Accounts"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIntegrationAccountInput"}}}},"responses":{"200":{"description":"Integration account updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationAccountResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Integration account not found"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteIntegrationAccount","summary":"Delete an integration account","tags":["Integration Accounts"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Integration account deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Integration account not found"}}}},"/companies/{companyId}/external-transactions":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listExternalTransactions","summary":"List external transactions (paginated)","tags":["External Transactions"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"},{"name":"entityId","in":"query","description":"Concrete legal-entity UUID, or consolidated for an all-entity read.","schema":{"oneOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["consolidated"]}]}},{"name":"provider","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of external transactions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalTransactionsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createExternalTransaction","summary":"Create an external transaction (immutable — 409 on duplicate)","tags":["External Transactions"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExternalTransactionInput"}}}},"responses":{"201":{"description":"External transaction created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalTransactionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Duplicate external transaction (company + provider + externalId)"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/external-transactions/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getExternalTransaction","summary":"Get an external transaction by ID","tags":["External Transactions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"External transaction found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalTransactionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"External transaction not found"}}}},"/companies/{companyId}/recommendations":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listRecommendations","summary":"List recommendations for a company","tags":["Recommendations"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","active","completed","dismissed"]}},{"name":"category","in":"query","schema":{"type":"string"}},{"name":"pinned","in":"query","schema":{"type":"boolean"}},{"name":"excludeSuppressed","in":"query","schema":{"type":"boolean","default":true}}],"responses":{"200":{"description":"Paginated list of recommendations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createRecommendation","summary":"Create a recommendation","tags":["Recommendations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRecommendationInput"}}}},"responses":{"201":{"description":"Recommendation created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/recommendations/activity":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listRecommendationActivity","summary":"List recent recommendation activity for the Insights rail","tags":["Recommendations"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":25,"default":10}}],"responses":{"200":{"description":"Sanitized recommendation audit activity","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","required":["id","recommendationId","actor","action","summary","timestamp"],"properties":{"id":{"type":"string","format":"uuid"},"recommendationId":{"type":"string","format":"uuid"},"actor":{"type":"string","enum":["accountant","founder","system"]},"action":{"type":"string"},"summary":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/recommendations/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getRecommendation","summary":"Get a recommendation by ID","tags":["Recommendations"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Recommendation found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Recommendation not found"}}},"patch":{"operationId":"updateRecommendation","summary":"Update a recommendation","tags":["Recommendations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRecommendationInput"}}}},"responses":{"200":{"description":"Recommendation updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Recommendation not found"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"operationId":"deleteRecommendation","summary":"Delete a recommendation","tags":["Recommendations"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Recommendation deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Recommendation not found"}}}},"/companies/{companyId}/recommendations/{id}/pin":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"pinRecommendation","summary":"Pin a recommendation","tags":["Recommendations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["founder","accountant"],"default":"founder"}}}}}},"responses":{"200":{"description":"Recommendation pinned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationResponse"}}}}}},"delete":{"operationId":"unpinRecommendation","summary":"Unpin a recommendation","tags":["Recommendations"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Recommendation unpinned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationResponse"}}}}}}},"/companies/{companyId}/recommendations/{id}/suppress":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"suppressRecommendation","summary":"Suppress a recommendation temporarily","tags":["Recommendations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["founder","accountant"],"default":"founder"},"days":{"type":"integer","minimum":1,"maximum":365,"default":30},"reason":{"type":"string"}}}}}},"responses":{"200":{"description":"Recommendation suppressed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationResponse"}}}}}}},"/companies/{companyId}/recommendations/{id}/dismiss-with-reason":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"dismissRecommendationWithReason","summary":"Dismiss a recommendation with an optional reason","tags":["Recommendations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":1000}}}}}},"responses":{"200":{"description":"Recommendation dismissed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationResponse"}}}}}}},"/accountant/companies/{customerId}/insights/bundle":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getAccountantCustomerInsightsBundle","summary":"Get a customer insights bundle as an assigned accountant","tags":["Accountant Portal","Insights"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"},{"name":"period","in":"query","schema":{"type":"string","enum":["last_30_days","last_90_days","month_to_date"]}},{"name":"industry","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Customer insights bundle","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightsBundleResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/accountant/companies/{customerId}/intelligence/asks":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"createAccountantCustomerIntelligenceAsk","summary":"Ask a question against a customer's entity-scoped insights bundle","tags":["Accountant Portal","Insights"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAskInput"}}}},"responses":{"200":{"description":"Insight answer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAskAnswerResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"get":{"operationId":"listAccountantCustomerIntelligenceAsks","summary":"List a customer's entity-scoped Insight Ask history","tags":["Accountant Portal","Insights"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Ask history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAskListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/accountant/companies/{customerId}/insights/asks":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"createAccountantCustomerInsightAsk","summary":"Ask a question against a customer's entity-scoped insights bundle","tags":["Accountant Portal","Insights"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAskInput"}}}},"responses":{"200":{"description":"Insight answer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAskAnswerResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"get":{"operationId":"listAccountantCustomerInsightAsks","summary":"List a customer's entity-scoped Insight Ask history","tags":["Accountant Portal","Insights"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Ask history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAskListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/accountant/companies/{customerId}/insights/metric-requests":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listAccountantCustomerMetricRequests","summary":"List metric requests for an assigned customer","tags":["Accountant Portal","Insights"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Metric requests for the customer","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/accountant/companies/{customerId}/recommendations":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listAccountantCustomerRecommendations","summary":"List recommendations for an assigned customer","tags":["Accountant Portal","Recommendations"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","active","completed","dismissed"]}},{"name":"category","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Customer recommendation queue","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createAccountantCustomerRecommendation","summary":"Add an accountant-authored recommendation for an assigned customer","tags":["Accountant Portal","Recommendations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRecommendationInput"}}}},"responses":{"201":{"description":"Recommendation created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/recommendations/{id}/pin":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"pinAccountantCustomerRecommendation","summary":"Pin a customer recommendation as an accountant","tags":["Accountant Portal","Recommendations"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Recommendation pinned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationResponse"}}}}}},"delete":{"operationId":"unpinAccountantCustomerRecommendation","summary":"Unpin a customer recommendation as an accountant","tags":["Accountant Portal","Recommendations"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Recommendation unpinned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationResponse"}}}}}}},"/accountant/companies/{customerId}/recommendations/{id}/suppress":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"suppressAccountantCustomerRecommendation","summary":"Snooze a customer recommendation as an accountant","tags":["Accountant Portal","Recommendations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":365,"default":30},"reason":{"type":"string"}}}}}},"responses":{"200":{"description":"Recommendation suppressed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationResponse"}}}}}}},"/accountant/companies/{customerId}/recommendations/{id}/note":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"addAccountantCustomerRecommendationNote","summary":"Add an accountant note to a customer recommendation","tags":["Accountant Portal","Recommendations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["note"],"properties":{"note":{"type":"string","minLength":1,"maxLength":5000}}}}}},"responses":{"200":{"description":"Recommendation updated with accountant note","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationResponse"}}}}}}},"/accountant/companies/{customerId}/recommendations/{id}/customer-action-expected":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/resourceId"}],"post":{"operationId":"setAccountantCustomerRecommendationActionExpected","summary":"Mark whether a customer recommendation expects founder action","tags":["Accountant Portal","Recommendations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"expected":{"type":"boolean","default":true}}}}}},"responses":{"200":{"description":"Recommendation updated with customer-action expectation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationResponse"}}}}}}},"/accountant/companies/{customerId}/schedule-proposals/preview":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"previewScheduleProposalRuns","summary":"Preview the schedule runs a set of derived inputs would produce (no persistence)","tags":["Accountant Portal","Schedule Proposals"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchedulePreviewInput"}}}},"responses":{"200":{"description":"The runs pure generation would produce","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchedulePreviewResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/schedule-proposals/sweep":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"sweepScheduleProposals","summary":"Dispatch an on-demand detector sweep (returns not_available until a detector is wired)","tags":["Accountant Portal","Schedule Proposals"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleProposalSweepInput"}}}},"responses":{"200":{"description":"Sweep dispatch result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleProposalSweepResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/schedule-proposals":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listScheduleProposals","summary":"List AI accrual/deferral proposals for an assigned customer","tags":["Accountant Portal","Schedule Proposals"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/ScheduleProposalStatus"}},{"name":"type","in":"query","schema":{"type":"string","enum":["deferral","accrual"]}},{"name":"band","in":"query","schema":{"type":"string","enum":["high","medium","low"]}}],"responses":{"200":{"description":"Paginated proposal queue (newest first)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleProposalListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/accountant/companies/{customerId}/schedule-proposals/{id}":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getScheduleProposal","summary":"Proposal detail including its decision timeline","tags":["Accountant Portal","Schedule Proposals"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Proposal detail + timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleProposalDetailResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/accountant/companies/{customerId}/schedule-proposals/{id}/recovery":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getScheduleProposalRecovery","summary":"Read server-authoritative manual recovery evidence","description":"Requires a fresh live accountant assignment. Re-reads the exact definition, run, and journal artifact state under the proposal advisory lock and source-publication fence. Resolution revalidates period, reconciliation, entity, and currency authority. The returned revision must be echoed to resolve.","tags":["Accountant Portal","Schedule Proposals"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Current bounded recovery evidence and requirements","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleProposalRecoveryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Recovery artifacts are missing, ambiguous, or exceed bounds","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/schedule-proposals/{id}/recovery/resolve":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"resolveScheduleProposalRecovery","summary":"Verify an already-performed schedule proposal recovery","description":"Requires a fresh live accountant assignment. This operation never creates, edits, deletes, pauses, or voids ledger artifacts. It verifies pre-existing safe voids or one existing exact net-negating correction from authoritative server reads, records the audit/history, and idempotently completes the high-priority recovery task.","tags":["Accountant Portal","Schedule Proposals"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveScheduleProposalRecoveryInput"}}}},"responses":{"200":{"description":"Verified recovery, unchanged safe proposal, and completed task","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleProposalRecoveryResolutionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Stale revision or unsafe/ambiguous accounting state","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/schedule-proposals/{id}/approve":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"approveScheduleProposal","summary":"Approve and, when eligible, synchronously materialize a proposal","description":"Re-runs deterministic QA and synchronously materializes a human-approved proposal when detection and single-write are enabled. Human approval does not require the unattended auto-post flag. If single-write or detection is disabled, the row stays approved and the response reports approved_not_materialized. Re-approving resumes any partial write; posted rows are 200 no-ops. Other terminal rows return 409.","tags":["Accountant Portal","Schedule Proposals"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApproveScheduleProposalInput"}}}},"responses":{"200":{"description":"The approved proposal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleProposalApprovalResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The proposal is in a state that cannot be approved","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/schedule-proposals/{id}/clarification/send":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"sendScheduleProposalClarification","summary":"Send a server-drafted proposal clarification to the customer","description":"Accountant-only action. Atomically creates at most one AI-owned, non-close-blocking thread with one accountant-authored initial message and a schedule_proposal attachment. Retries return the existing thread; Median never auto-sends this draft.","tags":["Accountant Portal","Schedule Proposals"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Proposal with sent clarification and current thread state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleProposalResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/schedule-proposals/{id}/recheck":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"recheckScheduleProposal","summary":"Re-run deterministic QA after remediating a blocked proposal","description":"Accountant-only, idempotent recovery action. Re-reads the current chart of accounts and filing locks, refreshes role-derived account snapshots, and records proposal_rechecked. A passing proposal returns to pending_review; this endpoint never auto-approves or materializes.","tags":["Accountant Portal","Schedule Proposals"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"The still-blocked or human-review-ready proposal and current QA issues","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleProposalRecheckResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The proposal changed concurrently during the recheck","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/schedule-proposals/{id}/reject":{"parameters":[{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"rejectScheduleProposal","summary":"Reject a proposal (reason required); idempotent on already-rejected rows","tags":["Accountant Portal","Schedule Proposals"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectScheduleProposalInput"}}}},"responses":{"200":{"description":"The rejected proposal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleProposalResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The proposal is in a state that cannot be rejected","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/insights/bundle":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getInsightsBundle","summary":"Get the current insights metrics bundle","tags":["Insights"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"},{"name":"period","in":"query","schema":{"type":"string","enum":["last_30_days","last_90_days","month_to_date"]}},{"name":"industry","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Insights bundle","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightsBundleResponse"}}}}}}},"/companies/{companyId}/intelligence/home":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getIntelligenceHome","summary":"Get the feature-flagged founder Intelligence Home","description":"Returns the deterministic metric bundle, monthly curation, founder brief, operating signals, data readiness gaps, and deeper report pointers for the company. Customer-visible guidance is built only from validated signals and approved insights.\n","tags":["Insights"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"}],"responses":{"200":{"description":"Intelligence Home","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntelligenceHomeResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/intelligence/curations/run":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"runIntelligenceHomeCuration","summary":"Run Intelligence Home curation and pending insight generation","description":"Super-admin only. Rebuilds the monthly curation from deterministic metrics and may ask the curation/true-insight agents for selections and pending candidates. Agent output is rejected when it references unknown keys, unsupported numeric claims, or missing source refs.\n","tags":["Insights"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"}],"responses":{"200":{"description":"Curation run result","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["home","generatedPendingInsights"],"properties":{"home":{"$ref":"#/components/schemas/IntelligenceHome"},"generatedPendingInsights":{"type":"integer","minimum":0}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/insights/ask":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"askInsight","summary":"Ask a question against the insights metric bundle","tags":["Insights"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAskInput"}}}},"responses":{"200":{"description":"Insight answer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAskAnswerResponse"}}}}}}},"/companies/{companyId}/intelligence/asks":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"createIntelligenceAsk","summary":"Ask a question against the insights metric bundle","tags":["Insights"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAskInput"}}}},"responses":{"200":{"description":"Insight answer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAskAnswerResponse"}}}}}},"get":{"operationId":"listIntelligenceAsks","summary":"List previous insight Ask requests","tags":["Insights"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Ask history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAskListResponse"}}}}}}},"/companies/{companyId}/intelligence/asks/{askId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"askId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getIntelligenceAsk","summary":"Get a previous insight Ask request","tags":["Insights"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"}],"responses":{"200":{"description":"Ask record","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAskRecordResponse"}}}},"404":{"description":"Ask not found"}}}},"/companies/{companyId}/insights/asks":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listInsightAsks","summary":"List previous insight Ask requests","tags":["Insights"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Ask history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAskListResponse"}}}}}}},"/companies/{companyId}/insights/asks/{askId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"askId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getInsightAsk","summary":"Get a previous insight Ask request","tags":["Insights"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"}],"responses":{"200":{"description":"Ask record","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightAskRecordResponse"}}}},"404":{"description":"Ask not found"}}}},"/companies/{companyId}/insights/metrics/{metricKey}/request":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"metricKey","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"requestInsightMetric","summary":"Request an unavailable insight metric","tags":["Insights"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Metric request recorded"}}}},"/companies/{companyId}/insights/metrics/{metricKey}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"metricKey","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getInsightMetric","summary":"Get one metric from the insights bundle","tags":["Insights"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/intelligenceEntityId"},{"name":"period","in":"query","schema":{"type":"string","enum":["last_30_days","last_90_days","month_to_date"]}},{"name":"startDate","in":"query","schema":{"type":"string","format":"date"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"}},{"name":"industry","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Insight metric","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/InsightMetric"}}}}}},"400":{"description":"Invalid query parameters"},"404":{"description":"Metric not found"}}}},"/companies/{companyId}/metric-requests":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"createMetricRequest","summary":"Request priority for a coming-soon metric","tags":["Insights"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["metricKey"],"properties":{"metricKey":{"type":"string"}}}}}},"responses":{"200":{"description":"Metric request recorded"}}}},"/companies/{companyId}/marketing/connections":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listMarketingConnections","summary":"List GA4 and Google Ads marketing connections","tags":["Marketing"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Marketing connections and discovered accounts"}}}},"/companies/{companyId}/marketing/connections/{provider}/connect":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"provider","in":"path","required":true,"schema":{"type":"string","enum":["ga4","google_ads"]}}],"post":{"operationId":"connectMarketingProvider","summary":"Start a read-only Google marketing OAuth flow","tags":["Marketing"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["redirectUri"],"properties":{"entityId":{"type":"string","format":"uuid","description":"Concrete legal entity that owns the authorization request"},"redirectUri":{"type":"string","format":"uri"}}}}}},"responses":{"200":{"description":"OAuth authorization URL and state"}}}},"/companies/{companyId}/marketing/connections/{provider}/callback":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"provider","in":"path","required":true,"schema":{"type":"string","enum":["ga4","google_ads"]}}],"post":{"operationId":"completeMarketingProviderCallback","summary":"Complete a read-only Google marketing OAuth flow","tags":["Marketing"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","state","redirectUri"],"properties":{"code":{"type":"string"},"state":{"type":"string"},"redirectUri":{"type":"string","format":"uri"}}}}}},"responses":{"200":{"description":"Connected marketing provider"}}}},"/companies/{companyId}/marketing/connections/{provider}/sync":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"provider","in":"path","required":true,"schema":{"type":"string","enum":["ga4","google_ads"]}}],"post":{"operationId":"syncMarketingProvider","summary":"Run an immediate trailing-window marketing sync","tags":["Marketing"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Marketing sync result"}}}},"/companies/{companyId}/marketing/connections/{provider}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"provider","in":"path","required":true,"schema":{"type":"string","enum":["ga4","google_ads"]}}],"delete":{"operationId":"disconnectMarketingProvider","summary":"Revoke a marketing connection in Median","tags":["Marketing"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Marketing connection revoked"}}}},"/companies/{companyId}/attribution":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getAttribution","summary":"Marketing attribution for services-model companies","description":"Services-model marketing attribution: per-channel spend joined to matched clients and booked revenue (CAC, ROAS, LTV:CAC, payback) plus a budget-reallocation insight. Gated on businessModel === 'services' and a connected marketing source; returns an empty state (hasConnectedSource false, empty channels) otherwise. NOTE payback/LTV are estimates pending a Finance-confirmed gross-margin basis (see economicsBasis).\n","tags":["Attribution"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"period","in":"query","required":false,"schema":{"type":"string","enum":["mtd","t90"],"default":"mtd"}}],"responses":{"200":{"description":"Attribution channels, totals, reallocation, and sources","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/AttributionResult"}}}}}},"422":{"description":"Invalid period","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/marketing/identify":{"post":{"operationId":"identifyMarketingUser","summary":"Capture a signed marketing attribution identity mapping","tags":["Marketing"],"parameters":[{"name":"x-median-signature","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["companyId","externalUserId"],"properties":{"companyId":{"type":"string","format":"uuid"},"externalUserId":{"type":"string"},"provider":{"type":"string","default":"ga4"},"stripeCustomerId":{"type":["string","null"]},"gclid":{"type":["string","null"]},"source":{"type":["string","null"]},"medium":{"type":["string","null"]},"campaign":{"type":["string","null"]},"content":{"type":["string","null"]},"term":{"type":["string","null"]},"metadata":{"type":"object"}}}}}},"responses":{"200":{"description":"Identity mapping captured"}}}},"/identify":{"post":{"operationId":"identifyMarketingUserAlias","summary":"Capture a signed marketing attribution identity mapping","description":"Compatibility alias for /marketing/identify used by the marketing snippet spec.","tags":["Marketing"],"parameters":[{"name":"x-median-signature","in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["companyId","externalUserId"],"properties":{"companyId":{"type":"string","format":"uuid"},"externalUserId":{"type":"string"},"provider":{"type":"string","default":"ga4"},"stripeCustomerId":{"type":["string","null"]},"gclid":{"type":["string","null"]},"source":{"type":["string","null"]},"medium":{"type":["string","null"]},"campaign":{"type":["string","null"]},"content":{"type":["string","null"]},"term":{"type":["string","null"]},"metadata":{"type":"object"}}}}}},"responses":{"200":{"description":"Identity mapping captured"}}}},"/oauth/consent/preview":{"post":{"operationId":"previewOAuthConsent","summary":"Validate an MCP OAuth consent request","description":"Requires a signed-in human Bearer session and MCP_OAUTH_ENABLED. Validates the current registered client, exact approved callback, MCP resource and canonical PKCE S256 challenge before returning display metadata. Does not grant access or issue an authorization code. Approval independently checks the request and current company authority again. The stored client_name is a self-asserted connector label, not verified publisher identity.\n","tags":["MCP"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["client_id","redirect_uri","code_challenge","code_challenge_method","resource"],"properties":{"client_id":{"type":"string","minLength":1},"redirect_uri":{"type":"string","format":"uri"},"code_challenge":{"type":"string","minLength":43,"maxLength":43,"pattern":"^[A-Za-z0-9_-]{42}[AEIMQUYcgkosw048]$"},"code_challenge_method":{"type":"string","enum":["S256"]},"resource":{"type":"string","format":"uri"},"scope":{"type":"string"},"state":{"type":"string"}}}}}},"responses":{"200":{"description":"Validated consent display data, with no grant or code created","headers":{"Cache-Control":{"schema":{"type":"string","enum":["no-store"]}}},"content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["client_name","redirect_uri","issuer","resource","scopes"],"properties":{"client_name":{"type":["string","null"],"description":"Stored self-asserted DCR label; does not attest publisher identity"},"redirect_uri":{"type":"string","format":"uri"},"issuer":{"type":"string","format":"uri","description":"Exact OAuth metadata issuer, including any trailing slash"},"resource":{"type":"string","format":"uri"},"scopes":{"type":"array","items":{"type":"string"}}}}}}}}},"400":{"description":"Unknown, revoked or unapproved client, callback mismatch or resource mismatch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Missing or invalid human Bearer session"},"403":{"description":"API-key authentication cannot authorize a connector"},"404":{"description":"MCP OAuth is disabled"},"422":{"description":"Missing or invalid consent parameters, including malformed PKCE","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/mcp":{"post":{"operationId":"callMcp","summary":"Median MCP server endpoint","description":"JSON-RPC 2.0 Streamable HTTP endpoint. Default customer API keys and OAuth tokens expose only read tools. A separately scoped forecast:write API key may also expose the Forecast sandbox staging tool, which never changes the live forecast. Tool names and input schemas are documented in openapi/mcp-tools.json. Limits are 30 tool calls per minute and 300 per hour per API key or OAuth user-company identity, with an additional 20 calls per minute for each bulk-read tool. Every tool call in a JSON-RPC batch consumes its own budget. If any item exceeds a limit, the full batch is rejected atomically with HTTP 429, Retry-After, and one JSON-RPC error per request item. A batch may contain at most 20 items; a longer batch is rejected with HTTP 400 and a single JSON-RPC -32600 error before any budget is consumed.\n","tags":["MCP"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/McpJsonRpcRequest"},{"type":"array","minItems":1,"maxItems":20,"items":{"$ref":"#/components/schemas/McpJsonRpcRequest"}}]}}}},"responses":{"200":{"description":"JSON-RPC result or error","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/McpJsonRpcResponse"},{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/McpJsonRpcResponse"}}]}}}},"400":{"description":"Malformed JSON-RPC input, including a batch longer than 20 items; a single JSON-RPC error with code -32600 and a null id, returned before any tool-call budget is consumed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpJsonRpcResponse"}}}},"429":{"description":"One or more tool calls exceeded the credential or bulk-tool budget","headers":{"Retry-After":{"description":"Seconds until the exhausted window resets","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/McpJsonRpcRateLimitError"},{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/McpJsonRpcRateLimitError"}}]}}}}}}},"/admin/service-keys":{"get":{"operationId":"listServiceApiKeys","summary":"List cloud-bookkeeping service keys","description":"Requires a human bearer JWT whose user id is present in the immutable server-owned SUPER_ADMIN_USER_IDS allowlist. API keys, including serviceApiKey credentials, cannot call this operation.\n","tags":["API Keys","Admin"],"security":[{"bearerAuth":[]}],"x-median-authorization":"human-bearer-super-admin-user-id-only","parameters":[{"name":"includeRevoked","in":"query","required":false,"schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Service-key metadata; plaintext key material is never returned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceApiKeyListResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"503":{"description":"The dedicated service principal is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"post":{"operationId":"createServiceApiKey","summary":"Issue a cloud-bookkeeping service key","description":"Requires a human bearer JWT whose user id is present in the immutable server-owned SUPER_ADMIN_USER_IDS allowlist. The server binds the key to the configured non-human service principal and fixed accountant:* scope. The plaintext key is returned once and is never stored.\n","tags":["API Keys","Admin"],"security":[{"bearerAuth":[]}],"x-median-authorization":"human-bearer-super-admin-user-id-only","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceApiKeyInput"}}}},"responses":{"201":{"description":"Service key created; copy the plaintext key now","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedServiceApiKeyResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"description":"The dedicated service principal is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/admin/service-keys/{keyId}":{"parameters":[{"name":"keyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"delete":{"operationId":"revokeServiceApiKey","summary":"Revoke a cloud-bookkeeping service key","description":"Requires a human bearer JWT whose user id is present in the immutable server-owned SUPER_ADMIN_USER_IDS allowlist. API keys, including the key being revoked, cannot revoke service keys.\n","tags":["API Keys","Admin"],"security":[{"bearerAuth":[]}],"x-median-authorization":"human-bearer-super-admin-user-id-only","responses":{"200":{"description":"Revoked service-key metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceApiKeyResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"$ref":"#/components/responses/ValidationProblem"},"503":{"description":"The dedicated service principal is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/admin/repairs/ramp-cross-family-duplicates":{"post":{"operationId":"runRampCrossFamilyDuplicatesRepair","summary":"Run the Ramp cross-family duplicate-payments repair (#1715)","description":"Detects transaction pairs where the retired cash-side Ramp sync minted a `ramp:transfer-` row duplicating the live `ramp:card-payment-` row for the same transfer UUID, and (on apply) voids the orphaned transfer leg through the canonical accountant soft-delete funnel. Dry-run by default; `apply` additionally requires `companyId` and `confirm` set to exactly `REPAIR <companyId>`. Fleet-wide apply is refused. Requires a human bearer JWT whose user id is present in the immutable server-owned SUPER_ADMIN_USER_IDS allowlist; API keys cannot call this operation. Every void is audit-logged with the caller as actor.\n","tags":["Admin"],"security":[{"bearerAuth":[]}],"x-median-authorization":"human-bearer-super-admin-user-id-only","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataRepairRequest"}}}},"responses":{"200":{"description":"JSON change ledger (proposals, voids, failures, remaining work)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataRepairLedgerResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/admin/repairs/duplicate-bill-accruals":{"post":{"operationId":"runDuplicateBillAccrualsRepair","summary":"Run the duplicate bill-accrual journal-entries repair (#1704)","description":"Detects groups of posted document-sourced `Bill accrual:` journal entries duplicating the same (company, description, date, amount) and (on apply) voids the surplus entries through the atomic void-with-audit-and-recompute funnel, keeping the adjudicated or earliest-posted entry. Groups with distinct invoice numbers or reconciled surplus entries are reported, never touched. Dry-run by default; `apply` additionally requires `companyId` and `confirm` set to exactly `REPAIR <companyId>`. Fleet-wide apply is refused. Requires a human bearer JWT whose user id is present in the immutable server-owned SUPER_ADMIN_USER_IDS allowlist; API keys cannot call this operation. Every void is audit-logged with the caller as actor.\n","tags":["Admin"],"security":[{"bearerAuth":[]}],"x-median-authorization":"human-bearer-super-admin-user-id-only","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataRepairRequest"}}}},"responses":{"200":{"description":"JSON change ledger (proposals, voids, failures, remaining work)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataRepairLedgerResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"422":{"$ref":"#/components/responses/ValidationProblem"}}}},"/companies/{companyId}/api-keys":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listApiKeys","summary":"List company API keys","tags":["API Keys"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"purpose","in":"query","schema":{"type":"string","enum":["mcp"]}},{"name":"include","in":"query","schema":{"type":"string","enum":["usage"]}},{"name":"includeRevoked","in":"query","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"API keys"}}},"post":{"operationId":"createApiKey","summary":"Create a company API key","tags":["API Keys"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"purpose":{"type":"string","enum":["mcp"]},"scopes":{"type":"array","items":{"type":"string"}},"expiresAt":{"type":"string","format":"date-time"}}}}}},"responses":{"201":{"description":"API key created. Plaintext key is returned once."}}}},"/companies/{companyId}/api-keys/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"delete":{"operationId":"revokeApiKey","summary":"Revoke a company API key","tags":["API Keys"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"API key revoked"}}}},"/companies/{companyId}/mcp/connections":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listMcpConnections","summary":"List recent MCP client activity for a company","tags":["MCP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Recent MCP client activity"}}}},"/companies/{companyId}/checkout/subscription":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getCheckoutSubscription","summary":"Get the company's active Median subscription, with plan + payment method","description":"Returns the joined view of a company's Median (SaaS) subscription,\nshaped for the Billing & Plan card in the customer app. When the\nlocal median_subscriptions row is missing but the company already\nhas a Stripe customer, the service resyncs from Stripe before\nreturning (self-heals missed webhook deliveries).\n","tags":["Checkout"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Subscription (null when the company has none)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"oneOf":[{"$ref":"#/components/schemas/CheckoutSubscriptionResponse"},{"type":"null"}]}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/checkout/custom-offer":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getCustomPricingOffer","summary":"Get the sales-led custom pricing offer for the authenticated user","description":"Returns the active sales-led custom pricing offer matched by the\nauthenticated user's email, or null. When present, the onboarding price\nscreen shows a single fixed-price card (overriding the usage quote).\n","tags":["Checkout"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Custom offer (null when none is active for this email)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"oneOf":[{"type":"object","additionalProperties":false,"properties":{"monthlyPriceCents":{"type":"integer","minimum":1,"maximum":100000000},"trialDays":{"type":"integer","minimum":0,"maximum":365}},"required":["monthlyPriceCents","trialDays"]},{"type":"null"}]}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/checkout/custom-offer-session":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"createCustomOfferCheckoutSession","summary":"Start Stripe Checkout at the sales-led custom flat monthly price","description":"Creates a Stripe Checkout session billing the customer's agreed flat\nmonthly price (locked indefinitely), looked up by the authenticated\nemail and never trusted from the client. Adds a 30-day trial when the\noffer grants the first month free. The price attaches to the shared\nMedian catalog product, like the usage-based subscription.\n","tags":["Checkout"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Stripe Checkout URL","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"url":{"type":["string","null"]}},"required":["url"]}},"required":["success","data"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/checkout/quote":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getPricingQuote","summary":"Get the usage-derived flat price quote for a company","description":"Computes the usage-derived flat quote ($55/active financial account +\n$0.60/posted ledger line; annual = monthly x 12 x 0.75 with the corporate\ntax return included) from the company's connected financial data.\nestimatedMonthlyLines is the priced monthly ledger-line total;\ntransactionLines + revenueRecognitionLines + businessEventLines break it\ndown for display. Optional statementAccounts / statementMonthlyTransactions\nquery params add unconnected accounts the customer uploaded a statement\nfor; processorAccounts / processorMonthlyPayers add unconnected payment\nprocessors at their declared monthly paying-customer volume. The quote is\npersisted with a 12-month rate lock; quoteId echoes the locked price to\ncheck out at.\n","tags":["Checkout"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"statementAccounts","in":"query","required":false,"schema":{"type":"integer","minimum":0},"description":"Unconnected accounts the customer is attaching a statement for."},{"name":"statementMonthlyTransactions","in":"query","required":false,"schema":{"type":"integer","minimum":0},"description":"Summed estimated monthly transactions across those statement accounts."},{"name":"processorAccounts","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":20},"description":"Unconnected payment processors the customer declared volume for."},{"name":"processorMonthlyPayers","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":1000000},"description":"Summed declared monthly paying customers across those processors (each prices as one monthly invoice line)."}],"responses":{"200":{"description":"The usage-derived quote (null in DB-less mode)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"oneOf":[{"type":"object","properties":{"financialAccounts":{"type":"integer","minimum":0},"estimatedMonthlyLines":{"type":"integer","minimum":0},"transactionLines":{"type":"integer","minimum":0},"revenueRecognitionLines":{"type":"integer","minimum":0},"businessEventLines":{"type":"integer","minimum":0},"monthlyAmountCents":{"type":"integer","minimum":0},"annualAmountCents":{"type":"integer","minimum":0},"includesTaxFiling":{"type":"boolean"},"quoteId":{"type":["string","null"]},"rateLockedUntil":{"type":["string","null"],"format":"date-time"}},"required":["financialAccounts","estimatedMonthlyLines","transactionLines","revenueRecognitionLines","businessEventLines","monthlyAmountCents","annualAmountCents","includesTaxFiling","quoteId","rateLockedUntil"]},{"type":"null"}]}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/pricing/statement-estimate":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"estimateStatement","summary":"Estimate monthly transactions from an uploaded statement","description":"Line-counts a recent statement for one unconnected account into a monthly\ntransaction estimate, so a statement account still contributes to the\nonboarding quote. With a documentId the server reads the uploaded\nstatement itself: text-layer PDFs and text/CSV exports are counted\ndirectly; scanned PDFs/images go through a best-effort LLM count. Falls\nback to a conservative per-account default when the statement cannot be\ncounted.\n","tags":["Checkout"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"documentId":{"type":"string","format":"uuid","description":"An uploaded statement document to count server-side (takes precedence over rawText/lineCount)."},"rawText":{"type":"string","description":"Raw statement text to line-count."},"lineCount":{"type":"integer","minimum":0,"description":"A pre-counted line total (when counted client-side)."},"monthsCovered":{"type":"integer","minimum":1,"description":"Months the statement covers; the line count is divided by this."}}}}}},"responses":{"200":{"description":"The per-account monthly transaction estimate","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"monthlyTransactions":{"type":"integer","minimum":0},"source":{"type":"string","enum":["parsed","fallback"]}},"required":["monthlyTransactions","source"]}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/pricing/usage-vs-quote":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getUsageVsQuote","summary":"Compare actual posted entry volume against the quoted volume","description":"Returns the quoted monthly entry volume vs actual posted ledger lines over\nthe trailing complete months, with the re-quote threshold (150% monthly,\n200% annual) and an advisory breach flag set when every trailing month\n(>= 2) exceeds the threshold. V1 surfaces this for display only and never\nauto-rebills.\n","tags":["Checkout"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The usage-vs-quote comparison","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"hasQuotedVolume":{"type":"boolean"},"billingInterval":{"type":["string","null"]},"quotedMonthlyEntries":{"type":["integer","null"],"minimum":0},"thresholdPct":{"type":["integer","null"]},"thresholdEntries":{"type":["integer","null"],"minimum":0},"months":{"type":"array","items":{"type":"object","properties":{"month":{"type":"string"},"actualEntries":{"type":"integer","minimum":0},"ratioPct":{"type":["integer","null"]}},"required":["month","actualEntries","ratioPct"]}},"breached":{"type":"boolean"}},"required":["hasQuotedVolume","billingInterval","quotedMonthlyEntries","thresholdPct","thresholdEntries","months","breached"]}},"required":["success","data"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/companies/{companyId}/subscriptions":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listSubscriptions","summary":"List subscriptions for a company","tags":["Subscriptions"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"},{"name":"status","in":"query","schema":{"type":"string"}},{"name":"category","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of subscriptions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createSubscription","summary":"Create a subscription","tags":["Subscriptions"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSubscriptionInput"}}}},"responses":{"201":{"description":"Subscription created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/subscriptions/{id}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/resourceId"}],"get":{"operationId":"getSubscription","summary":"Get a subscription by ID","tags":["Subscriptions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Subscription found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Subscription not found"}}},"patch":{"operationId":"updateSubscription","summary":"Update a subscription","tags":["Subscriptions"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSubscriptionInput"}}}},"responses":{"200":{"description":"Subscription updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Subscription not found"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"operationId":"deleteSubscription","summary":"Delete a subscription","tags":["Subscriptions"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Subscription deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Subscription not found"}}}},"/companies/{companyId}/billing-plan":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getBillingPlan","summary":"Get the billing plan for a company","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Billing plan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingPlanResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"put":{"operationId":"updateBillingPlan","summary":"Upsert the billing plan for a company","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBillingPlanInput"}}}},"responses":{"200":{"description":"Billing plan updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingPlanResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"x-quarantined-consolidation-groups":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listConsolidationGroups","summary":"List effective consolidation groups containing this company","description":"QA-only. Returns a group only when the authenticated user is an active member of every constituent company. The hierarchy is persisted above company-scoped ledgers; this endpoint does not aggregate financial data.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"asOf","in":"query","required":false,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Authorized effective consolidation groups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsolidationGroupsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Surface unavailable outside the allowlisted QA application"},"422":{"$ref":"#/components/responses/ValidationError"}}},"post":{"operationId":"createConsolidationGroup","summary":"Create the first effective version of a consolidation group","description":"QA-only. Requires admin or owner access in every constituent test company. Persists only supplied real-company configuration; no company, rate, ownership, hierarchy, or accounting data is generated.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConsolidationGroupInput"}}}},"responses":{"201":{"description":"Consolidation group and first effective version created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsolidationGroupResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Surface or one of the supplied companies is unavailable"},"409":{"description":"Effective version or company group membership overlaps existing authority"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"x-quarantined-consolidation-report-rollups":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"groupVersionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listConsolidationRollups","summary":"List immutable pre-elimination report rollups for one group version","description":"QA-only. Requires active membership in every constituent test company. These are management P&L and balance-sheet rollups from exact immutable standalone presentation snapshots. Balance sheets also pin the exact immutable CTA snapshot derived from the same manifest. They are explicitly incomplete and are not consolidated financial statements because uniform-policy adjustments, parent-investment/subsidiary-equity elimination, intercompany eliminations, NCI attribution, and disposal reclassification have not all been applied.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Issued pre-elimination rollups, newest period first","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsolidationRollupSnapshotsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"QA surface, group version, or constituent access unavailable"},"422":{"$ref":"#/components/responses/ValidationError"}}},"post":{"operationId":"createConsolidationRollup","summary":"Issue an immutable exact-source pre-elimination report rollup","description":"QA-only and admin-only in every constituent company. The submitted manifest must contain exactly one existing immutable standalone snapshot of the requested report type for every company in the sealed group version. Balance sheets additionally require the exact sealed CTA snapshot for the same group, period, currency, and constituent hashes. All snapshots must retain their current close generation and use exact shared-chart semantics. Full consolidation includes 100 percent of a partially owned subsidiary; NCI remains explicitly pending. No data, rates, mappings, companies, or accounting values are generated by this endpoint.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConsolidationRollupInput"}}}},"responses":{"201":{"description":"Rollup issued, or an identical incumbent returned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsolidationRollupSnapshotResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"QA surface, group, company, or standalone snapshot unavailable"},"409":{"description":"Issued authority changed and requires controlled restatement"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"x-quarantined-consolidation-report-rollup":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"groupVersionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"rollupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getConsolidationRollup","summary":"Read one immutable pre-elimination P&L rollup","tags":["Reports"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Issued pre-elimination rollup with exact contribution provenance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsolidationRollupSnapshotResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"x-quarantined-consolidation-translation-adjustments":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"groupVersionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listConsolidationTranslationAdjustments","summary":"List immutable pre-elimination CTA audits for one group version","description":"QA-only. Requires active membership in every constituent test company. Each audit sums the independently validated translation difference from one exact immutable standalone balance-sheet snapshot per constituent. The result is OCI/separate-equity audit data, is not posted to the ledger, and is not a consolidated financial statement. Uniform-policy adjustments, parent-investment/equity elimination, intercompany eliminations, NCI attribution, and disposal reclassification remain explicit pending procedures.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Issued CTA audits, newest period first","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsolidationTranslationAdjustmentSnapshotsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"QA surface, group version, or constituent access unavailable"},"422":{"$ref":"#/components/responses/ValidationError"}}},"post":{"operationId":"createConsolidationTranslationAdjustment","summary":"Issue an immutable exact-source pre-elimination CTA audit","description":"QA-only and admin-only in every constituent company. The submitted manifest must contain exactly one existing immutable standalone balance-sheet snapshot for every company in the sealed group version. All snapshots must share the exact period and presentation currency, retain their current close generation, and preserve their exact closing, historical, and average FX provenance. Full consolidation contributes 100 percent of a partially owned subsidiary; no ownership multiplication or NCI attribution occurs in this slice. The endpoint creates no data, rates, companies, mappings, or ledger postings.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConsolidationTranslationAdjustmentInput"}}}},"responses":{"201":{"description":"CTA audit issued, or an identical incumbent returned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsolidationTranslationAdjustmentSnapshotResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"QA surface, group, company, or standalone snapshot unavailable"},"409":{"description":"Issued authority changed and requires controlled restatement"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"x-quarantined-consolidation-translation-adjustment":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"groupVersionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"adjustmentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getConsolidationTranslationAdjustment","summary":"Read one immutable pre-elimination CTA audit","tags":["Reports"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Issued CTA audit with exact balance-sheet and FX provenance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsolidationTranslationAdjustmentSnapshotResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/presentation-report-snapshots":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listPresentationReportSnapshots","summary":"List immutable closed-period presentation reports","description":"Demo-parity read for an explicitly allowlisted active or test company. Every row was derived from that company's closed ledger and exact persisted FX authority; reads never create templates, mock data, or seed data.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Issued presentation reports, newest closed period first","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresentationReportSnapshotsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Surface unavailable outside the allowlisted customer rollout"}}},"post":{"operationId":"createPresentationReportSnapshot","summary":"Issue an immutable presentation P&L for one closed period","description":"Demo-parity and admin-only. Requires an explicitly allowlisted active or test company and uses the exact closed-period general ledger, selected same-company legal-entity functional currency, configured presentation currency, and persisted period-average FX revision. An identical retry returns the incumbent snapshot; changed source or output authority can only create an immutable next revision through explicit supersession.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePresentationReportSnapshotInput"}}}},"responses":{"201":{"description":"Presentation report issued, or identical incumbent returned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresentationReportSnapshotResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Customer rollout surface, company, or closed GL period unavailable"},"409":{"description":"Issued authority changed and requires controlled restatement"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/presentation-report-snapshots/{snapshotId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"name":"snapshotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getPresentationReportSnapshot","summary":"Read one immutable presentation report","tags":["Reports"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Issued presentation report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresentationReportSnapshotResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-trial-balances":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listReportingTrialBalances","summary":"List immutable standalone reporting trial balances","description":"Demo-parity read for an explicitly allowlisted active or test company. Returns only trial balances for legal entities the authenticated user may access. Every result pins the exact closed period, posted journal lines, controlled chart-of-accounts mapping, and persisted FX revisions used for translation.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Issued reporting trial balances","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingTrialBalancesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Surface unavailable outside the allowlisted customer rollout"}}},"post":{"operationId":"createReportingTrialBalance","summary":"Issue an immutable standalone adjusted pre-closing trial balance","description":"Demo-parity and admin-only for an explicitly allowlisted active or test company. Uses all posted non-closing journal lines through the exact closed-period cutoff for one concrete same-company legal entity. Assets and liabilities use closing rates, equity uses historical rates, nominal accounts use exact closed-period averages, and CTA remains a separate non-ledger control-schedule line. Missing or stale authority fails closed; runtime fixtures and inferred cross-entity fallbacks are never accepted.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportingTrialBalanceInput"}}}},"responses":{"201":{"description":"Immutable reporting trial balance issued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingTrialBalanceResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Customer rollout surface, company, legal entity, or closed period unavailable"},"409":{"description":"Issued authority changed and requires controlled restatement"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-trial-balances/{snapshotId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"},{"name":"snapshotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getReportingTrialBalance","summary":"Read one immutable standalone reporting trial balance","tags":["Reports"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Reporting trial balance with exact source and FX drilldown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingTrialBalanceResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/entities":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listEntities","summary":"List the actor's authorized legal entities","description":"Ordinary authenticated company-member discovery. Returns only concrete legal entities allowed by the actor's persisted entity grants; reporting scopes are separate and never appear here.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of entities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntitiesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createLegalEntity","summary":"Create a legal subsidiary","description":"Admin/owner only. Creates persisted company accounting configuration; no demo data is generated.","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLegalEntityInput"}}}},"responses":{"201":{"description":"Legal entity created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Surface unavailable outside the allowlisted customer rollout"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/entity-access":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"listEntityAccess","summary":"List legal-entity access for company principals","description":"Owner/admin only. Returns explicit Model A access for active company members and assigned accountants. An accountant assignment alone does not grant a legal entity.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Legal-entity access summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityAccessSummaryListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/entity-access/{userId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"userId","in":"path","required":true,"description":"User ID of an active company member or assigned accountant.","schema":{"type":"string","format":"uuid"}}],"put":{"operationId":"replaceEntityAccess","summary":"Replace one principal's legal-entity access","description":"Owner/admin only. Atomically revokes the active grant set for an active company member or assigned accountant, then grants either every legal entity or the selected concrete legal entities. Consolidated reporting scopes cannot be granted.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplaceEntityAccessInput"}}}},"responses":{"200":{"description":"Updated legal-entity access summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityAccessSummaryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listReportingScopes","summary":"List read-only consolidated reporting identities","description":"Requires company-wide read access: the explicit `all_entities` grant, or entity grants that currently cover every concrete legal entity of the company (what a member of a single-entity company holds). A member limited to some of the legal entities receives 403. Reporting scopes are distinct from legal entities and can never own accounting or integration data.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Reporting scopes visible to an actor with company-wide read access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createReportingScope","summary":"Create the company's consolidated reporting identity","description":"Owner/admin plus explicit all-entity access required. The server derives the root from the company's persisted primary legal entity and requires an actual multi-entity company. No hierarchy or company data is generated.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportingScopeInput"}}}},"responses":{"201":{"description":"Reporting scope created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"An active consolidated reporting scope already exists"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getReportingScope","summary":"Get one read-only reporting identity","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Reporting scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listReportingScopeVersions","summary":"List sealed effective-dated hierarchy snapshots","description":"Unsealed drafts are never returned as reporting authority.","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Sealed hierarchy versions in effective-date order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeVersionsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createReportingScopeVersion","summary":"Atomically create and seal a complete hierarchy snapshot","description":"Owner/admin plus explicit all-entity access required. The snapshot must contain every current same-company legal entity exactly once, use the primary entity as its 100 percent full-consolidation root, and be connected and acyclic. A successor closes the prior open version in the same transaction.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportingScopeVersionInput"}}}},"responses":{"201":{"description":"Sealed reporting-scope hierarchy version","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeVersionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Effective dates or persisted reporting authority conflict"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/effective-version":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"resolveReportingScopeVersion","summary":"Resolve the sealed hierarchy effective on a date","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"asOf","in":"query","required":true,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Effective sealed reporting hierarchy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeVersionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/worksheet":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getReportingScopeWorksheet","summary":"Read the sealed consolidation worksheet for one scope and period","description":"Read-only assembly of the persisted, sealed pre-elimination reporting-scope trial-balance and management rollups, the translated (cumulative translation adjustment) columns, the virtual intercompany elimination, and the non-controlling-interest allocation for one reporting-scope hierarchy version and period, exactly as stored. Requires explicit all-entity access. It never live-computes: any stage that has not been sealed is returned as null, and a scope, sealed version, or sealed period that does not exist returns available:false with an honest reason. Defaults to the latest sealed version and period when versionId or periodEnd are omitted.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"versionId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"periodEnd","in":"query","required":false,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Sealed consolidation worksheet, or an honest-unavailable envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeWorksheetResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/worksheet/periods":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listReportingScopeWorksheetPeriods","summary":"List sealed consolidation worksheet versions and periods","description":"Enumerates every sealed hierarchy version and period that has a sealed consolidation worksheet, each with per-stage availability flags, so the client can select a versionId and periodEnd for the worksheet read. Requires explicit all-entity access. Returns available:false with an honest reason when no consolidation scope or sealed worksheet exists.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Sealed worksheet version and period list, or an honest-unavailable envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeWorksheetPeriodsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getReportingScopeVersion","summary":"Get one sealed hierarchy snapshot","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Sealed hierarchy snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeVersionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/rollups":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listReportingScopeRollups","summary":"List immutable pre-elimination reporting-scope rollups","description":"Requires explicit all-entity access and an explicitly allowlisted active or test company. Every result is derived from one exact standalone snapshot per concrete same-company legal entity. Results remain labeled incomplete until the required elimination, NCI, and other consolidation procedures exist.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Reporting-scope rollups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeRollupsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createReportingScopeRollup","summary":"Issue an immutable pre-elimination P&L or balance-sheet rollup","description":"Owner/admin plus all-entity access required. The explicit manifest must contain every legal entity in the sealed reporting-scope version exactly once and pin one current immutable standalone snapshot per entity. Balance sheets must pin the separately sealed CTA snapshot for the identical entity manifest. No mock, seed, inferred cross-company, or unsupported consolidated authority is accepted.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportingScopeRollupInput"}}}},"responses":{"201":{"description":"Immutable reporting-scope rollup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeRollupResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A different immutable rollup already exists for this window"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/trial-balances":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listReportingScopeTrialBalances","summary":"List immutable reporting-scope trial balances","description":"Demo-parity and all-entity protected for an explicitly allowlisted active or test company. Every result pins one exact current standalone trial-balance snapshot per legal entity in the explicitly requested sealed reporting-scope version.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Reporting-scope trial balances","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeTrialBalancesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createReportingScopeTrialBalance","summary":"Issue an immutable pre-elimination reporting-scope trial balance","description":"Demo-parity, admin-only, and all-entity protected for an explicitly allowlisted active or test company. The explicit manifest must contain every legal entity in the sealed hierarchy exactly once, pin each current adjusted pre-closing trial balance, and share the exact company GL-account mapping and presentation currency. The result remains labeled incomplete and non-consolidated until elimination, NCI, policy, and disposal procedures are applied. No runtime fixture or inferred latest snapshot is accepted.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportingScopeTrialBalanceInput"}}}},"responses":{"201":{"description":"Immutable reporting-scope trial balance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeTrialBalanceResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A different immutable authority already exists for this period"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/designations":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listModelAIntercompanyDesignations","summary":"List exact Model A intercompany source designations","description":"Demo-parity and all-entity protected for an explicitly allowlisted active or test company. Returns active immutable designations over real posted journal lines for two concrete legal entities inside this company and sealed reporting-scope version.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["all","unmatched","partially_matched","matched"],"default":"all"}}],"responses":{"200":{"description":"Intercompany source designations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAIntercompanyDesignationsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"post":{"operationId":"createModelAIntercompanyDesignation","summary":"Explicitly designate one posted intercompany source line","description":"Demo-parity, admin-only, and all-entity protected for an explicitly allowlisted active or test company. The server derives and seals transaction, functional-currency, FX-revision, source, actor, and fingerprint authority from the exact persisted journal line. No counterparty, classification, rate, or amount is inferred.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateModelAIntercompanyDesignationInput"}}}},"responses":{"201":{"description":"Immutable intercompany designation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAIntercompanyDesignationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The source line already has different active designation authority"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/proposals":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"proposeModelAIntercompanyMatches","summary":"Deterministically propose reciprocal intercompany matches","description":"Computes proposals from current persisted designations and immutable allocations for one exact closed period. Cross-period sources are explicitly marked as timing differences. The result is not accounting authority until an admin confirms the exact proposal.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/modelAIntercompanyGlPeriodId"}],"responses":{"200":{"description":"Deterministic proposals and review exceptions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAIntercompanyProposalResultResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/exceptions":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listModelAIntercompanyExceptions","summary":"List unmatched and mismatched intercompany sources with drilldown","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/modelAIntercompanyGlPeriodId"}],"responses":{"200":{"description":"Exception queue with exact designation and source authority","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAIntercompanyExceptionsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/rollforwards":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listModelAIntercompanyBalanceRollforwards","summary":"Build due-to, due-from, and loan-principal rollforwards","description":"Builds directional opening, movement, closing, matching, and difference authority by exact creditor, debtor, transaction currency, and closed period. Matching never erases source-book balances.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/modelAIntercompanyGlPeriodId"}],"responses":{"200":{"description":"Intercompany balance rollforwards","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAIntercompanyBalanceRollforwardsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/matches":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listModelAIntercompanyMatches","summary":"List immutable confirmed intercompany matches","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"glPeriodId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Confirmed matches with source allocation drilldown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAIntercompanyMatchesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"post":{"operationId":"createModelAIntercompanyMatch","summary":"Explicitly confirm one current deterministic proposal","description":"Demo-parity, admin-only, and all-entity protected for an explicitly allowlisted active or test company. The exact proposal and source hashes are recomputed before an immutable match is sealed. Stale or client-edited allocations fail closed.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateModelAIntercompanyMatchInput"}}}},"responses":{"201":{"description":"Immutable confirmed match","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAIntercompanyMatchResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The proposal was already sealed with different authority"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/eliminations":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listModelAIntercompanyEliminations","summary":"List immutable Model A intercompany elimination authorities","description":"Demo-parity and all-entity protected for an explicitly allowlisted active or test company. Each result is a virtual reporting adjustment over one immutable pre-elimination trial-balance rollup. It never posts to the legal-entity ledgers.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"glPeriodId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Intercompany elimination and reversal authorities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAIntercompanyEliminationsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"post":{"operationId":"createModelAIntercompanyElimination","summary":"Seal one exact virtual intercompany elimination authority","description":"Demo-parity, admin-only, and all-entity protected for an explicitly allowlisted active or test company. The request must include the exact current pre-elimination rollup and every immutable match for its closed period. The server pins journal, standalone snapshot, posting-FX, and presentation-rate provenance and refuses an invented FX plug or a stale match manifest.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateModelAIntercompanyEliminationInput"}}}},"responses":{"201":{"description":"Immutable virtual elimination authority","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAIntercompanyEliminationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A source, close generation, match, or snapshot authority is stale"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/eliminations/{snapshotId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"snapshotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getModelAIntercompanyElimination","summary":"Read one immutable intercompany elimination authority","tags":["Reports"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Exact elimination or reversal authority with drilldown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAIntercompanyEliminationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/eliminations/{snapshotId}/reverse":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"snapshotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"reverseModelAIntercompanyElimination","summary":"Seal the exact reversal of one elimination authority","description":"Demo-parity, admin-only, and all-entity protected for an explicitly allowlisted active or test company. Reversal is derived from the original sealed authority and restores the exact base control schedule without changing any legal-entity journal.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReverseModelAIntercompanyEliminationInput"}}}},"responses":{"201":{"description":"Immutable exact reversal authority","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAIntercompanyEliminationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The original authority is stale or already reversed differently"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/nci":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listModelANciSnapshots","summary":"List immutable Model A NCI allocation authorities","description":"Demo-parity and all-entity protected for an explicitly allowlisted active or test company. Results derive solely from sealed, current post-elimination reporting authorities and never post to a legal-entity ledger.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"glPeriodId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Immutable NCI authorities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelANciSnapshotsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"post":{"operationId":"createModelANciSnapshot","summary":"Seal one exact post-elimination NCI authority","description":"Demo-parity, admin-only, and all-entity protected for an explicitly allowlisted active or test company. The server derives every source amount from the current immutable elimination snapshot. The caller classifies exact report lines and controlled output accounts but cannot submit or override money.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateModelANciSnapshotInput"}}}},"responses":{"201":{"description":"Immutable NCI allocation authority","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelANciSnapshotResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The period, scope, elimination, or restatement authority is stale"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/nci/events":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listModelANciLifecycleEvents","summary":"List immutable source-backed NCI lifecycle events","description":"Demo-parity and all-entity protected for an explicitly allowlisted active or test company.","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"glPeriodId","in":"query","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"subsidiaryEntityId","in":"query","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Exact sealed lifecycle event authorities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelANciLifecycleEventsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"post":{"operationId":"createModelANciLifecycleEvent","summary":"Seal a source-backed NCI acquisition, distribution, ownership, or disposal event","description":"Demo-parity and admin-only for an explicitly allowlisted active or test company. The caller selects a persisted source and event identity; all money, ownership, carrying values, hashes, and valuation fields are derived from reviewed company records and sealed authorities.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateModelANciLifecycleEventInput"}}}},"responses":{"201":{"description":"Immutable lifecycle event authority","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelANciLifecycleEventResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Source or scope authority is stale"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/nci/rollforwards":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listModelANciRollforwards","summary":"List immutable NCI control-account rollforwards","description":"Demo-parity and all-entity protected for an explicitly allowlisted active or test company.","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"subsidiaryEntityId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Exact sealed NCI rollforwards","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelANciRollforwardsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"post":{"operationId":"createModelANciRollforward","summary":"Issue one complete NCI lifecycle rollforward","description":"Demo-parity and admin-only for an explicitly allowlisted active or test company. The server selects the current sealed NCI source, latest compatible opening authority, and complete lifecycle-event set; clients cannot omit events or submit accounting amounts.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateModelANciRollforwardInput"}}}},"responses":{"201":{"description":"Immutable NCI rollforward authority","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelANciRollforwardResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Controlled restatement is required"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/nci/rollforwards/{snapshotId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"snapshotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getModelANciRollforward","summary":"Read one immutable NCI lifecycle rollforward","tags":["Reports"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Exact NCI rollforward authority","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelANciRollforwardResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/nci/{snapshotId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"snapshotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getModelANciSnapshot","summary":"Read one immutable Model A NCI allocation authority","tags":["Reports"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Exact NCI authority with source provenance and allocation drilldown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelANciSnapshotResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/consolidated-statements":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listModelAIssuedConsolidatedStatements","summary":"List final immutable Model A consolidated-statement authorities","description":"Demo-parity and all-entity protected for an explicitly allowlisted active or test company. Each result is tied to one sealed same-company legal-entity hierarchy, closed period, exact post-NCI source snapshot, reviewed consolidation-procedure documents, and current NCI rollforwards. Results are virtual consolidated presentation authorities and never post adjustments into a legal entity ledger.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"glPeriodId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Final immutable consolidated-statement authorities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAIssuedConsolidatedStatementsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"post":{"operationId":"createModelAIssuedConsolidatedStatement","summary":"Issue one final source-backed Model A consolidated statement","description":"Demo-parity, admin-only, and all-entity protected for an explicitly allowlisted active or test company. The caller selects exact persisted source authorities and supplies an audit reason only. The server derives all accounting amounts, validates uniform-policy, investment-versus-equity, NCI, and disposal procedures, and refuses stale, incomplete, unbalanced, or caller-authored financial values.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateModelAIssuedConsolidatedStatementInput"}}}},"responses":{"201":{"description":"Final immutable consolidated-statement authority","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAIssuedConsolidatedStatementResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Source authority changed and controlled restatement is required"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/intercompany/consolidated-statements/{snapshotId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"snapshotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getModelAIssuedConsolidatedStatement","summary":"Read one final immutable Model A consolidated statement","description":"Returns exact statement lines, source hashes, reviewed-procedure provenance, and NCI rollforward provenance for audit drilldown.\n","tags":["Reports"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Final immutable consolidated-statement authority","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelAIssuedConsolidatedStatementResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/translation-adjustments":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listReportingScopeTranslationAdjustments","summary":"List immutable reporting-scope CTA authorities","description":"Requires explicit all-entity access and an explicitly allowlisted active or test company. Each result pins the exact same-company balance-sheet snapshots and FX revisions used to recognize the cumulative translation adjustment in OCI. It is not a report and does not post to the ledger.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Reporting-scope CTA authorities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeTranslationAdjustmentsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"operationId":"createReportingScopeTranslationAdjustment","summary":"Issue an immutable reporting-scope CTA authority","description":"Owner/admin plus all-entity access required. The manifest must contain every legal entity in the sealed reporting-scope version exactly once and pin current immutable balance-sheet snapshots for one closed period. No mock, seed, cross-company identity, or CTA ledger posting is accepted.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportingScopeTranslationAdjustmentInput"}}}},"responses":{"201":{"description":"Immutable reporting-scope CTA authority","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeTranslationAdjustmentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A different immutable CTA authority already exists for this window"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/translation-adjustments/{adjustmentId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"adjustmentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getReportingScopeTranslationAdjustment","summary":"Get one immutable reporting-scope CTA authority","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Reporting-scope CTA authority","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeTranslationAdjustmentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/rollups/{rollupId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"rollupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getReportingScopeRollup","summary":"Get one immutable pre-elimination reporting-scope rollup","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Reporting-scope rollup","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeRollupResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/reporting-scopes/{reportingScopeId}/versions/{versionId}/trial-balances/{snapshotId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"reportingScopeId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"versionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"snapshotId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getReportingScopeTrialBalance","summary":"Read one immutable reporting-scope trial balance","tags":["Reports"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Reporting-scope trial balance with entity, journal, and rate drilldown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportingScopeTrialBalanceResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/entities/{entityId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getEntity","summary":"Get a single entity by ID","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Entity details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateLegalEntity","summary":"Update a legal entity","description":"Admin/owner only. Consolidated scope rows cannot be edited and hierarchy cycles are rejected.","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLegalEntityInput"}}}},"responses":{"200":{"description":"Legal entity updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/entities/{entityId}/functional-currency-history":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getFunctionalCurrencyHistory","summary":"List the immutable functional-currency history for a legal entity","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Effective-dated functional-currency history, ordered by effective date","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunctionalCurrencyHistoryResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/entities/{entityId}/functional-currency-transitions":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"entityId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"changeFunctionalCurrency","summary":"Append a prospective functional-currency transition","description":"Admin/owner only. Appends immutable authority after the latest effective transition and after the entity's latest posted journal date.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeFunctionalCurrencyInput"}}}},"responses":{"201":{"description":"Functional-currency transition appended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunctionalCurrencyTransitionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Transition conflicts with immutable currency or posted-journal history"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/currencies":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getCurrencies","summary":"Get the company's currencies view","description":"Returns the company's presentation currency, the FX as-of date, and one entry per enabled business currency (display metadata + rate to the presentation currency).\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Currencies view","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrenciesViewResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Surface unavailable outside the allowlisted customer rollout"}}}},"/companies/{companyId}/currencies/rates":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"listFxRateRevisions","summary":"List immutable FX-rate revisions for the company","description":"Returns persisted provider and manual observations, including superseded revisions.","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"FX-rate revision history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FxRatesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Surface unavailable outside the allowlisted customer rollout"}}}},"/companies/{companyId}/currencies/rates/manual":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"createManualFxRate","summary":"Create or supersede a manual FX-rate revision","description":"Admin/owner only. The prior revision remains immutable and auditable.","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateManualFxRateInput"}}}},"responses":{"201":{"description":"Manual FX-rate revision created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FxRateResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Surface unavailable outside the allowlisted customer rollout"},"409":{"description":"Superseded revision is not the active rate for this exact lookup"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/currencies/presentation":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"put":{"operationId":"setPresentationCurrency","summary":"Set the company's presentation currency","description":"Updates the company's presentation currency. Admin/owner only. Returns the updated currencies view. Rejects a currency outside the enabled set with a 422.\n","tags":["Company Settings"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPresentationCurrencyInput"}}}},"responses":{"200":{"description":"Presentation currency updated; returns the updated currencies view","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrenciesViewResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Surface unavailable outside the allowlisted customer rollout"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/metrics/cac":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"get":{"operationId":"getCacDetail","summary":"Entity-scoped CAC detail for an analysis period","description":"Customer acquisition cost for one concrete legal entity and an explicit analysis period (default: year to date). The numerator is explicit CAC-tagged sales & marketing spend (GL classification is reconciliation evidence, never a tag); the denominator is canonical new paying customers, available only with continuous subscription history from before the period start. When `available` is false, `reason` names why and no numeric zero is fabricated. The top-level `available` always equals `metric.available`: a snapshot can compute and still have no ratio (`insufficient_inputs`), in which case `period` and `breakdown` are still returned as evidence while `metric.value` is null.\n","tags":["Metrics"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","description":"Concrete legal entity; defaults to the caller's single authorized entity.","schema":{"type":"string","format":"uuid"}},{"name":"period","in":"query","description":"Named analysis period (default ytd). Mutually exclusive with startDate/endDate.","schema":{"type":"string","enum":["ytd","month"]}},{"name":"startDate","in":"query","schema":{"type":"string","format":"date"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Availability-discriminated CAC detail payload","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["enabled","entityId","available","reason","metric","trend"],"properties":{"enabled":{"type":"boolean","description":"Rollout stamp for saas_metrics_engines. Informational ONLY: metric bodies are identical at any flag state (F07). It does not gate the correction write path.\n"},"entityId":{"type":"string","format":"uuid"},"available":{"type":"boolean"},"reason":{"oneOf":[{"$ref":"#/components/schemas/CacUnavailableReason"},{"type":"null"}]},"metric":{"$ref":"#/components/schemas/CacMetric"},"period":{"oneOf":[{"$ref":"#/components/schemas/CacAnalysisPeriod"},{"type":"null"}]},"breakdown":{"oneOf":[{"$ref":"#/components/schemas/CacBreakdown"},{"type":"null"}]},"trend":{"type":"array","description":"Up to 12 persisted snapshots for this entity, newest first. DENSITY IS A ROLLOUT ARTIFACT, not a claim: the complete-month rows come from the CAC backfill worker, which only visits companies the saas_metrics_engines candidate list names, so a company outside it carries only the windows that were actually requested.\n","items":{"$ref":"#/components/schemas/CacTrendRow"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/metrics/cac/classifications":{"parameters":[{"$ref":"#/components/parameters/companyId"}],"post":{"operationId":"recordCacClassification","summary":"Record an is/is-not sales & marketing correction","description":"Teaches the CAC tagger whether a vendor is sales & marketing spend for one concrete legal entity. Requires the founder/admin capability (company role admin or owner). Writes an entity-scoped cac_vendor_rule (confidence drifts on repeat corrections) plus a durable append-only audit event. Provide a merchant or a transactionId; the entity resolves from the entityId query parameter or the caller's single authorized entity.\n","tags":["Metrics"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"entityId","in":"query","description":"Concrete legal entity; defaults to the caller's single authorized entity.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["isSm"],"properties":{"isSm":{"type":"boolean"},"merchant":{"type":"string","minLength":3,"maxLength":500},"transactionId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"The learned or updated entity-scoped vendor rule","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/companies/{companyId}/forecast":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getForecast","summary":"Get the persisted forecast aggregate for a company","tags":["Forecast"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"businessType","in":"query","schema":{"type":"string","enum":["software","services","digital","usage","license","blended","custom"]}}],"responses":{"200":{"description":"Forecast aggregate (model + streams + headcount + opex + scenarios)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForecastAggregateResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No forecast is configured for this legal entity yet (`title` is `FORECAST_NOT_FOUND`; clients render the first-use state), or the company or legal entity is not found or not available to the caller (`title` is `NOT_FOUND`).\n","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"422":{"description":"Invalid businessType query parameter"}}},"post":{"operationId":"createForecastModel","summary":"Create an empty persisted forecast model for a company","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateForecastModelInput"}}}},"responses":{"201":{"description":"Created forecast aggregate","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForecastAggregateResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A forecast already exists for this company"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/forecast/from-books":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"initializeForecastFromBooks","summary":"Start an empty forecast from today's posted books cash","description":"Creates a model using only today's posted GL cash, the calendar boundary (actuals through the last completed month), and functional currency. No closed accounting period is required (#2652). It does not create revenue, headcount, opex, or scenario assumptions.\n","tags":["Forecast"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Books-sourced empty forecast aggregate","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForecastAggregateResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A forecast already exists for this company"},"422":{"description":"Ambiguous ledger currency or unavailable legal-entity authority"}}}},"/companies/{companyId}/forecast/books-baseline":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"reviewForecastBooksBaseline","summary":"Review a revenue baseline derived from posted books","description":"Returns a read-only proposal based on the latest one to three consecutive completed calendar months. The arithmetic average includes zero months and does not infer recurrence, growth, customers, or pricing. This endpoint performs no forecast mutation and fails closed without one legal entity and one reconciled functional-currency authority.\n","tags":["Forecast"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Reviewable books baseline and optimistic review fingerprint","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastBooksBaselineCandidate"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Posted revenue is unavailable, non-positive, multi-entity, or currency-ambiguous"}}}},"/companies/{companyId}/forecast/{forecastId}/books-baseline/apply":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"forecastId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"applyForecastBooksBaseline","summary":"Apply the exact books revenue baseline the customer reviewed","description":"Atomically creates or refreshes the one system-owned ledger run-rate stream. A fingerprint mismatch returns 409 and writes nothing.\n","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyForecastBooksBaselineInput"}}}},"responses":{"200":{"description":"Applied baseline plus refreshed forecast aggregate","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["candidate","aggregate"],"properties":{"candidate":{"$ref":"#/components/schemas/ForecastBooksBaselineCandidate"},"aggregate":{"$ref":"#/components/schemas/ForecastAggregate"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The posted books changed after review; refresh before applying"},"422":{"description":"Invalid fingerprint or unavailable accounting authority"}}}},"/companies/{companyId}/forecast/active-sandbox":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getActiveForecastSandbox","summary":"Recover the one persisted AI or MCP sandbox from current books authority","tags":["Forecast"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Active sandbox recovery result, or null when no sandbox is active","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["sandbox"],"properties":{"sandbox":{"oneOf":[{"$ref":"#/components/schemas/ForecastActiveSandboxResponse"},{"type":"null"}]}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Persisted sandbox state is ambiguous and must be repaired"}}}},"/companies/{companyId}/forecast/steer":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"steerForecast","summary":"Stage a typed AI forecast plan in an adhoc sandbox","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForecastSteerInput"}}}},"responses":{"201":{"description":"Persisted sandbox preview; live forecast rows are unchanged","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastSteerResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Another active sandbox exists or the reviewed authority is stale"},"422":{"description":"Invalid or out-of-bounds tool plan"},"503":{"description":"Live forecast AI is not configured"}}}},"/companies/{companyId}/forecast/{modelId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"modelId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"put":{"operationId":"updateForecastModel","summary":"Update forecast model header (label, businessType, startCashCents, horizonMonths)","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateForecastModelInput"}}}},"responses":{"200":{"description":"Updated forecast model","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastModel"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteForecastModel","summary":"Delete a persisted forecast model and its child rows","tags":["Forecast"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/forecast/{forecastId}/financing-events/{eventId}/expected-date":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"forecastId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"eventId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"patch":{"operationId":"setForecastFinancingExpectedDate","summary":"Set the first expected receipt date on an undated financing event","description":"The date must be within the event's effective month. Repeating the same date is idempotent; a different date conflicts. Amount, entity, currency and all other event fields remain immutable. This operation does not post or match ledger cash.","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["expectedDate"],"properties":{"expectedDate":{"type":"string","format":"date"}}}}}},"responses":{"200":{"description":"Dated financing event","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/ForecastFinancingEvent"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Financing event already has a different expected date"},"422":{"description":"Invalid calendar date or date outside the event's effective month"}}}},"/companies/{companyId}/forecast/{forecastId}/financing-events/{eventId}/receipt":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"forecastId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"eventId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"linkForecastFinancingReceipt","summary":"Confirm a financing assumption corresponds to one posted receipt","description":"Explicitly links one complete cash receipt with an equity or financing-debt credit in the same company and entity. Repeating the same link is idempotent; either identity already linked to live cash elsewhere conflicts. A voided or deleted prior receipt can be explicitly replaced with a verified receipt, preserving its history. The association never posts or changes books, and projections revalidate posted status and money in the opening-cash snapshot.","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["journalEntryId"],"properties":{"journalEntryId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Receipt association confirmed","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["linked"],"properties":{"linked":{"type":"boolean","const":true}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Event or receipt is already linked elsewhere"},"422":{"description":"Invalid receipt identity or incomplete financing economics"}}}},"/companies/{companyId}/forecast/{forecastId}/streams":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"forecastId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"addForecastStream","summary":"Add a revenue stream to the forecast","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateForecastStreamInput"}}}},"responses":{"200":{"description":"Created stream","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastStream"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Validation error (unknown stream type or out-of-range driver)"}}}},"/companies/{companyId}/forecast/{forecastId}/streams/{streamId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"forecastId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"streamId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"put":{"operationId":"updateForecastStream","summary":"Update a forecast stream","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateForecastStreamInput"}}}},"responses":{"200":{"description":"Updated stream","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastStream"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteForecastStream","summary":"Delete a forecast stream","tags":["Forecast"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/forecast/{forecastId}/headcount":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"forecastId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"addForecastHeadcount","summary":"Add a headcount row to the forecast","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateForecastHeadcountInput"}}}},"responses":{"200":{"description":"Created headcount row","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastHeadcount"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/forecast/{forecastId}/headcount/{headcountId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"forecastId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"headcountId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"put":{"operationId":"updateForecastHeadcount","summary":"Update a headcount row","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateForecastHeadcountInput"}}}},"responses":{"200":{"description":"Updated headcount row","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastHeadcount"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteForecastHeadcount","summary":"Delete a headcount row","tags":["Forecast"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/forecast/{forecastId}/opex":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"forecastId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"addForecastOpex","summary":"Add an operating expense row to the forecast","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateForecastOpexInput"}}}},"responses":{"200":{"description":"Created opex row","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastOpex"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/forecast/{forecastId}/opex/{opexId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"forecastId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"opexId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"put":{"operationId":"updateForecastOpex","summary":"Update an opex row","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateForecastOpexInput"}}}},"responses":{"200":{"description":"Updated opex row","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastOpex"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Validation error"}}},"delete":{"operationId":"deleteForecastOpex","summary":"Delete an opex row","tags":["Forecast"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/forecast/{forecastId}/scenarios":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"forecastId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"addForecastScenario","summary":"Add a scenario to the forecast","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateForecastScenarioInput"}}}},"responses":{"200":{"description":"Created scenario","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastScenario"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/forecast/{forecastId}/scenarios/{scenarioId}":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"forecastId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"scenarioId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"delete":{"operationId":"deleteForecastScenario","summary":"Delete a forecast scenario","tags":["Forecast"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The AI or MCP sandbox was already applied and its audit row is immutable"}}},"put":{"operationId":"updateForecastScenario","summary":"Update a saved forecast scenario","tags":["Forecast"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateForecastScenarioInput"}}}},"responses":{"200":{"description":"Updated scenario","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastScenario"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Validation error"}}}},"/companies/{companyId}/forecast/{forecastId}/scenarios/{scenarioId}/merge":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"forecastId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"scenarioId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"mergeForecastScenario","summary":"Approve and merge a forecast sandbox into the live model","tags":["Forecast"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Merged forecast aggregate","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForecastAggregateResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The sandbox was already resolved or its reviewed authority is stale"},"422":{"description":"Sandbox is invalid or has no approved changes"}}}},"/companies/{companyId}/forecast/{forecastId}/scenarios/{scenarioId}/lock":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"name":"forecastId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"scenarioId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"post":{"operationId":"lockForecastScenarioAsBudget","summary":"Lock a scenario as the single budget baseline for variance (#1159)","description":"Sets the scenario kind to 'budget' and is_locked=true, unlocking any previously locked budget scenario for the same forecast. The locked budget is the plan used by GET /forecast/variance.\n","tags":["Forecast"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The newly locked budget scenario","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastScenario"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/forecast/actuals":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getForecastActuals","summary":"Calendar-month actuals from the GL + calendar boundary (#1159,","description":"Returns one MonthlyPoint per calendar month through the last completed UTC month (revenue/expense/net from posted journal entries; ending cash = cumulative GL cash-account balance at month end) plus the boundary (last completed month, projection anchor, and today's posted GL cash). No closed accounting period is required.\n","tags":["Forecast"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Actuals line + boundary","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastActualsResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/companies/{companyId}/forecast/variance":{"parameters":[{"$ref":"#/components/parameters/companyId"},{"$ref":"#/components/parameters/demoParityCustomerAppSurface"}],"get":{"operationId":"getForecastVariance","summary":"Budget-vs-actual variance per completed calendar month (#1159)","tags":["Forecast"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"scenario","in":"query","description":"'budget' (the locked budget baseline) or a scenario uuid","schema":{"oneOf":[{"type":"string","enum":["budget"]},{"type":"string","format":"uuid"}],"default":"budget"}}],"responses":{"200":{"description":"Per-month variance with favorability + material flags","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastVarianceResponse"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"}}}},"/accountant/search":{"get":{"operationId":"getAccountantSearch","summary":"Read search","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/dashboard":{"get":{"operationId":"getAccountantDashboard","summary":"Read dashboard","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/accuracy-history":{"get":{"operationId":"getAccountantAccuracyHistory","summary":"Read accuracy history","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/engine-runs/summary":{"get":{"operationId":"getAccountantEngineRunsSummary","summary":"Read engine runs summary","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/customers":{"get":{"operationId":"getAccountantCustomers","summary":"Read customers","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker. Each customer row carries `fiscalYearEnd` (string MM-DD or null): the stored companies.fiscal_year_end, null when not confirmed (#2019).","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/books-closure-status":{"get":{"operationId":"getAccountantBooksClosureStatus","summary":"Read books closure status","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/companies/{customerId}/client-status":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"patch":{"operationId":"patchAccountantCompaniesCustomerIdClientStatus","summary":"Update companies client status","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/onboarding-status":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"patch":{"operationId":"patchAccountantCompaniesCustomerIdOnboardingStatus","summary":"Update companies onboarding status","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/metrics-enabled":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"patch":{"operationId":"patchAccountantCompaniesCustomerIdMetricsEnabled","summary":"Update companies metrics enabled","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"Go-live refused by the stored business model (#1967), before any write. `error.title` is `GO_LIVE_BUSINESS_MODEL_UNCONFIRMED` when the model is still the stored software default (an accountant confirms it by picking the model through PATCH .../business-model, the same value included), or `GO_LIVE_BUSINESS_MODEL_UNSET` when the stored model is missing or unregistered. `error.extensions` carries `businessModel` and `businessModelSource`. Re-locking (`metricsEnabled: false`) is never refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/viewer-access":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"patch":{"operationId":"patchAccountantCompaniesCustomerIdViewerAccess","summary":"Update companies viewer access","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/portal-credentials":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdPortalCredentials","summary":"Read companies portal credentials","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"post":{"operationId":"postAccountantCompaniesCustomerIdPortalCredentials","summary":"Create or run companies portal credentials","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/portal-credentials/{credentialId}/reveal":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"credentialId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdPortalCredentialsCredentialIdReveal","summary":"Read companies portal credentials reveal","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/portal-credentials/{credentialId}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"credentialId","in":"path","required":true,"schema":{"type":"string"}}],"patch":{"operationId":"patchAccountantCompaniesCustomerIdPortalCredentialsCredentialId","summary":"Update companies portal credentials","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"delete":{"operationId":"deleteAccountantCompaniesCustomerIdPortalCredentialsCredentialId","summary":"Delete companies portal credentials","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/client-context":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdClientContext","summary":"Read companies client context","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"post":{"operationId":"postAccountantCompaniesCustomerIdClientContext","summary":"Create or run companies client context","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/client-context/ai":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdClientContextAi","summary":"Read companies client context ai","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/client-context/{contextId}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"contextId","in":"path","required":true,"schema":{"type":"string"}}],"patch":{"operationId":"patchAccountantCompaniesCustomerIdClientContextContextId","summary":"Update companies client context","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/gl-periods":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdGlPeriods","summary":"Read companies gl periods","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"post":{"operationId":"accountantCreateGlPeriod","summary":"Open one calendar month for an assigned customer","description":"#3516. An assigned accountant (signed in, or the agent service token) opens one whole calendar month, including a month before the customer's first period, so a migration can post source-dated history. The period is created `open`; close, reopen and the locks are unchanged. Refused: anything but the 1st through the month's last day of a year from 1900 to 2100 (422); a month in a calendar year that holds a filing-locked period, or starting on or before the end of the latest filing-locked period (422, `GL_PERIOD_FILED_BOOKS`); a month starting before the customer's QuickBooks cutoff (422, `GL_PERIOD_BEFORE_QUICKBOOKS_CUTOFF`); and a month overlapping a period, including a concurrent create of the same month (409). The audit row records the acting person, or the service key's `source` and `apiKeyId`. An unassigned customer is 403.\n","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGlPeriodInput"}}}},"responses":{"201":{"description":"The new open period","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlPeriodResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"$ref":"#/components/responses/ConflictJson"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/tasks":{"get":{"operationId":"getAccountantTasks","summary":"Read tasks","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/tasks/{taskId}":{"parameters":[{"name":"taskId","in":"path","required":true,"schema":{"type":"string"}}],"patch":{"operationId":"patchAccountantTasksTaskId","summary":"Update tasks","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/transactions/review":{"get":{"operationId":"getAccountantTransactionsReview","summary":"Read transactions review","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact row shape. `meta.scopeTruncated` is authoritative (#1959): true means an assigned customer's scope lookup could not be evaluated and its rows are missing from `data`. `meta.truncated` is also true when a customer is listed in `meta.rowCappedCustomers` (#1958).","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"limit","in":"query","description":"Rows per response page. The total covers all rows matching the filters across the selected companies.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":500}},{"name":"offset","in":"query","description":"Use meta.nextOffset from the preceding page while meta.hasMore is true. Keep all filters unchanged.","schema":{"type":"integer","minimum":0,"default":0}},{"name":"classId","in":"query","schema":{"type":"string"}},{"name":"tagId","in":"query","description":"Accounting tag filter (#1166), repeated or comma-separated, up to 50 UUIDs; ANY listed tag (existence test). ORed with `untagged`.","schema":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50}]}},{"name":"untagged","in":"query","description":"When `true`, include transactions with no tag (ORed with `tagId`).","schema":{"type":"string","enum":["true","false"]}},{"name":"tier","in":"query","schema":{"type":"string","enum":["all","escalated","review","auto_approved"]}},{"name":"transferAction","in":"query","schema":{"type":"string","enum":["pending","proposed","approved","applied","none"]}},{"name":"postedToGlAccountId","in":"query","description":"#1166 E1: only transactions with at least one posted, non-deleted journal entry of this company that has a line on this GL account (the entry's transaction source or a line's transaction). Combines with every other filter. Not a UUID: 422.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success envelope; `meta.scopeTruncated` reports scope completeness; `meta.rowCappedCustomers` lists customers to continue","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/AccountantQueueMeta"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"409":{"description":"Offset pagination state conflicts with the preceding page."},"422":{"$ref":"#/components/responses/ValidationError"},"500":{"description":"A company fetch failed. No partial queue is returned."}}}},"/accountant/transactions/metrics":{"get":{"operationId":"getAccountantTransactionsMetrics","summary":"Read transactions metrics","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. `data.truncated` is authoritative (#1945, #1959): true means at least one in-scope customer's rows are missing from every figure below — either its per-company aggregate failed, or its client-status lookup could not be evaluated — so a 0 here may be a gap rather than a real zero. A customer deliberately excluded by `?clientStatuses=` is not a gap and does not raise it.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; `data.truncated` reports whether every in-scope customer was counted","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":true,"properties":{"truncated":{"$ref":"#/components/schemas/AccountantScopeTruncated"}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/companies/{customerId}/transactions/metrics":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdTransactionsMetrics","summary":"Read companies transactions metrics","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/transactions/auto-approved":{"get":{"operationId":"getAccountantTransactionsAutoApproved","summary":"Read transactions auto approved","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact row shape. `meta.scopeTruncated` is authoritative (#1959): true means an assigned customer's scope lookup could not be evaluated and its rows are missing from `data`. `meta.truncated` is also true when a customer is listed in `meta.rowCappedCustomers` (#1958).","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"limit","in":"query","description":"Rows per response page. The total covers all rows matching the filters across the selected companies.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":500}},{"name":"offset","in":"query","description":"Use meta.nextOffset from the preceding page while meta.hasMore is true. Keep all filters unchanged.","schema":{"type":"integer","minimum":0,"default":0}},{"name":"classId","in":"query","schema":{"type":"string"}},{"name":"tagId","in":"query","description":"Accounting tag filter (#1166), repeated or comma-separated, up to 50 UUIDs; ANY listed tag (existence test). ORed with `untagged`.","schema":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50}]}},{"name":"untagged","in":"query","description":"When `true`, include transactions with no tag (ORed with `tagId`).","schema":{"type":"string","enum":["true","false"]}},{"name":"tier","in":"query","schema":{"type":"string","enum":["all","escalated","review","auto_approved"]}},{"name":"transferAction","in":"query","schema":{"type":"string","enum":["pending","proposed","approved","applied","none"]}},{"name":"postedToGlAccountId","in":"query","description":"#1166 E1: only transactions with at least one posted, non-deleted journal entry of this company that has a line on this GL account (the entry's transaction source or a line's transaction). Combines with every other filter. Not a UUID: 422.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success envelope; `meta.scopeTruncated` reports scope completeness; `meta.rowCappedCustomers` lists customers to continue","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/AccountantQueueMeta"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"409":{"description":"Offset pagination state conflicts with the preceding page."},"422":{"$ref":"#/components/responses/ValidationError"},"500":{"description":"A company fetch failed. No partial queue is returned."}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/timeline":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdTransactionsTransactionIdTimeline","summary":"Read companies transactions timeline","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/approve":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdTransactionsTransactionIdApprove","summary":"Create or run companies transactions approve","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"categoryGlAccountId":{"type":"string","format":"uuid"},"notes":{"type":"string","maxLength":2000},"reason":{"type":"string","minLength":1,"maxLength":1000,"description":"#3046: why the category was changed. One line of plain text (trimmed; no control, line-separator or text-direction characters, no HTML markup, and not the text '| Recategorization reason:'). Stored as the reasoning of the decision on the transaction timeline and appended to the replacement journal entry's description as ' | Recategorization reason: <reason>'. Absent leaves the decision as before and removes a reason left on the description by an earlier recategorize; a description that never carried one is unchanged. The reason is not sent to QuickBooks."},"learnMerchantRule":{"type":"boolean","description":"#3041: whether this approval writes or repoints the merchant rule for this transaction's merchant. true: a changed category does. Absent: a changed category, including the first category on an uncategorized transaction, applies to this transaction only and the rule is left alone; an approval that leaves the category unchanged writes a rule only when it confirms a Stripe counterparty-history suggestion. false: no rule is written in any case. Stripe revenue transactions (a Stripe charge, invoice or subscription payment, or a Stripe counterparty-history suggestion) are outside this choice: a category change on one always writes its exact company rule, because that rule is what lets the revenue entry post. The bookkeeping engine's feedback run is queued whatever the value; its output is a proposal for review."}}}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"description":"Insufficient permissions or not assigned to the company. Also returned, before anything is written, when a service API key sends learnMerchantRule: true: the service token cannot create or retrain a merchant rule (#2383, #3039). Also returned to a service API key, before anything is written, when the request changes the category of a Stripe revenue row (a Stripe charge, invoice or subscription payment, or a row suggested from Stripe counterparty history): that change writes the customer's merchant rule whatever learnMerchantRule says, so an accountant must make the correction (#3039, J-413). Also returned to a service API key, before anything is written, when it approves a row suggested from Stripe counterparty history without changing its category, whether learnMerchantRule is absent or false: that approval writes the customer's merchant rule, and with false the row would be categorized while its Stripe revenue entry stays held, so an accountant must confirm it (#3039, J-417).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"description":"Business rule error; nothing is written. `error.title` is `TRANSACTION_CATEGORY_IS_BANK_ACCOUNT` when the approved category (explicit or the existing suggestion) is the GL account of the transaction's own bank or card account, `TRANSACTION_APPLIED_TRANSFER_MATCH_ACTIVE` or `TRANSACTION_BANK_OFFSET_UNIDENTIFIED` as on the accountant PATCH.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/reject":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdTransactionsTransactionIdReject","summary":"Create or run companies transactions reject","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/transfer-match/approve":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdTransactionsTransactionIdTransferMatchApprove","summary":"Create or run companies transactions transfer match approve","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/transfer-match/reject":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdTransactionsTransactionIdTransferMatchReject","summary":"Create or run companies transactions transfer match reject","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transactions/bulk-approve":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdTransactionsBulkApprove","summary":"Create or run companies transactions bulk approve","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope. `data` is the bulk summary (`requested`, `processed`, `skipped`, `failed`, `results` with one item per distinct id) plus `stripeRevenueStillHeld` (#3039): the ids of Stripe counterparty-history suggestions that this request approved, or found already categorized on their suggested account, and whose Stripe revenue entry still has no account to post to after the request tried to write their merchant rule (the write failed, or the merchant or account cannot carry a rule). Those rows read categorized while their revenue stays held; send the same request again (a signed-in accountant's request writes the missing rule of an already categorized suggestion and reports the row as `skipped`), or use the single approve route. Empty when there is none. An already categorized suggestion whose revenue account resolves is left alone and its existing rule is not changed. Split rows are approved status-only, get no rule and are never listed here. Bulk-approve never changes an existing merchant rule (decided before any row is written): a suggestion still in review whose Stripe revenue account already resolves is approved with no rule write when that account is the suggested one, and comes back as a `failed` result, untouched, with reason `This Stripe revenue row's customer already has a rule or revenue account that differs from the suggested one; review it individually` when it is another account. The same `failed` result is returned, on the in-review path and on the already-categorized retry path, when the customer's exact merchant rule already exists and names another account of any type (for example an expense account, which gives no revenue authority); when that rule names the suggested account, no rule is written. A rule is never moved to another account by this route: it is created, or rewritten with the account it already names. A row whose account, merchant rule or revenue authority cannot be read is likewise not approved: `failed`, reason \"This Stripe revenue row's merchant rule could not be checked; it was not approved. Try again\". Selected suggestions that would write the same merchant rule with different suggested accounts all come back `failed`, untouched, with reason `Selected Stripe revenue rows from the same customer suggest different accounts; approve them individually`; with the same account they are approved and share one rule.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"data":{"type":"object","additionalProperties":true,"properties":{"stripeRevenueStillHeld":{"type":"array","description":"Transaction ids of approved Stripe counterparty-history suggestions whose revenue is still held because no merchant rule could be written (#3039). Empty when none.","items":{"type":"string","format":"uuid"}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"description":"Insufficient permissions or not assigned to the company. Also returned to a service API key, before any row is written, when the request would write a merchant rule: a selected row is a Stripe counterparty-history suggestion (categorizationSource stripe_counterparty_history, not split, with a suggested category) that is either still in review, or already categorized while its Stripe revenue entry has no account to post to. Approving such a row writes the customer's merchant rule, which is what lets its Stripe revenue entry post, and the service token never writes a rule. The whole request is refused and `detail` names the transaction ids (the first 20, then `and N more`); resend without them and leave those rows to an accountant. An already categorized suggestion whose revenue account resolves is not refused (it is skipped). A split suggestion is outside this check: the token approves it status-only, as any split row, no rule is written and its Stripe revenue stays held. If a selected row cannot be read, the service key's request fails as a whole with the read error and nothing is written. The service key is refused for every such suggestion still in review, including one whose revenue account already resolves (no rule would be written): confirming a history suggestion is refused for it on the single approve route as well. A signed-in accountant's bulk-approve approves a suggestion at its suggested category and writes that rule, as the single approve route does (#3039, J-417).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transactions/bulk-recategorize":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdTransactionsBulkRecategorize","summary":"Create or run companies transactions bulk recategorize","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"required":["transactionIds","categoryGlAccountId"],"properties":{"transactionIds":{"type":"array","minItems":1,"maxItems":500,"items":{"type":"string","format":"uuid"}},"categoryGlAccountId":{"type":"string","format":"uuid"},"reason":{"type":"string","minLength":1,"maxLength":1000,"description":"#3046: why the category was changed. One line of plain text (trimmed; no control, line-separator or text-direction characters, no HTML markup, and not the text '| Recategorization reason:'). Stored as the reasoning of each recategorized row's decision on the transaction timeline and appended to the replacement journal entry's description as ' | Recategorization reason: <reason>'. Absent leaves the decision as before and removes a reason left on the description by an earlier recategorize; a description that never carried one is unchanged. The reason is not sent to QuickBooks."},"learnMerchantRule":{"type":"boolean","default":false,"description":"#3041: true also writes or repoints the merchant rule for the selected transactions' merchants. Absent or false applies the category to the selected transactions only and the rule is left alone. Stripe revenue transactions (a Stripe charge, invoice or subscription payment, or a Stripe counterparty-history suggestion) are outside this choice: a category change on one always writes its exact company rule, because that rule is what lets the revenue entry post. The bookkeeping engine's feedback run is queued whatever the value; its output is a proposal for review."}}}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"description":"Insufficient permissions or not assigned to the company. Also returned, before anything is written, when a service API key sends learnMerchantRule: true: the service token cannot create or retrain a merchant rule (#2383, #3039). Also returned to a service API key, before any row is written, when any selected row is a Stripe revenue row that the request would process, that is every such row except one already categorized on the target category (which is skipped): processing it writes the customer's merchant rule whatever learnMerchantRule says, whether or not its category changes. The whole request is refused and `detail` names the transaction ids (the first 20 of the rows whose category would change, and the first 20 of the rows in review already on the target); resend without them and leave those rows to an accountant (#3039, J-413, J-417).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transactions/bulk-reject":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdTransactionsBulkReject","summary":"Create or run companies transactions bulk reject","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transactions/bulk-assign-class":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdTransactionsBulkAssignClass","summary":"Assign one accounting class to a batch of transactions, posted rows included","description":"Sets the class on up to 100 transactions per request (#2125; each row is its own database transaction, and a batch must finish inside the 30s request timeout). Each row goes through the same audited assignment as PATCH /accountant/companies/{customerId}/transactions/{transactionId} with only classId: the transaction and its owned journal_lines get the class and one transaction.class_assignment audit_logs row is written, in one database transaction per row. Amounts, accounts, dates and posting status never change, and nothing is voided. A row in a filing-locked period, a reconciled row, or a row whose journal entry has an ambiguous source is reported as failed with the reason, and the rest of the batch still runs. Rows already on the class are skipped, so re-running a request is safe. An inactive or foreign classId is refused with 404 before any row is touched. To class a date range (for example the last N months), page transaction ids with GET /accountant/companies/{customerId}/transactions?dateFrom=&dateTo= and send them in batches of 100 or fewer. To clear a class, use the single-row PATCH.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["transactionIds","classId"],"properties":{"transactionIds":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","format":"uuid"},"description":"Duplicates are ignored."},"classId":{"type":"string","format":"uuid","description":"An active class of this company."}}}}}},"responses":{"200":{"description":"Per-row outcome. Same summary shape as bulk-approve, bulk-recategorize and bulk-reject.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["requested","processed","skipped","failed","results"],"properties":{"requested":{"type":"integer"},"processed":{"type":"integer"},"skipped":{"type":"integer"},"failed":{"type":"integer"},"results":{"type":"array","items":{"type":"object","required":["transactionId","status"],"properties":{"transactionId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["processed","skipped","failed"]},"reason":{"type":"string"}}}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"description":"Validation error (empty or more than 100 transactionIds, non-uuid ids)"}}}},"/accountant/companies/{customerId}/statement-diagnostics":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdStatementDiagnostics","summary":"Create or run companies statement diagnostics","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/metrics/practice":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdMetricsPractice","summary":"Read companies metrics practice","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/metrics/revenue-by-product":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdMetricsRevenueByProduct","summary":"Read companies metrics revenue by product","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/metrics/expense-breakdown":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdMetricsExpenseBreakdown","summary":"Read companies metrics expense breakdown","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/metrics/net-burn":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdMetricsNetBurn","summary":"Read companies metrics net burn","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/metrics/revenue-mix/billing-types":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdMetricsRevenueMixBillingTypes","summary":"Read companies metrics revenue mix billing types","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/receivables/aging":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdReceivablesAging","summary":"Read companies receivables aging","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/documents/queue":{"get":{"operationId":"getAccountantDocumentsQueue","summary":"Read documents queue","description":"One offset-paged page of the documents queue across every assigned customer, newest upload first by default (#2015). `data` is a bare array of at most `meta.limit` rows; page with `offset`.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Rows per page. Defaults to 200 and is capped at 500; an out-of-range or non-numeric value falls back to the 200-row default rather than erroring.","schema":{"type":"integer","minimum":1,"maximum":500,"default":200}},{"name":"offset","in":"query","required":false,"description":"Rows to skip before the page. Defaults to 0; a negative or non-numeric value falls back to 0.","schema":{"type":"integer","minimum":0,"default":0}},{"name":"search","in":"query","required":false,"description":"Case-insensitive substring match applied before `status`, so the status counts in `meta.totalByStatus` reflect it.","schema":{"type":"string"}},{"name":"type","in":"query","required":false,"description":"Filters on the queue's normalized document type. Applied before `status`, so it is reflected in `meta.totalByStatus`. An unrecognized value is ignored rather than erroring.","schema":{"type":"string","enum":["invoice","bill","receipt","contract","statement"]}},{"name":"status","in":"query","required":false,"description":"Filters on the queue's display status. Applied AFTER the counts, so `meta.total` narrows with it while `meta.totalByStatus` and `meta.metrics` do not. An unrecognized value is ignored rather than erroring.","schema":{"type":"string","enum":["needs_review","pending_payment","reviewed","paid","processed","archived"]}},{"name":"sort","in":"query","required":false,"description":"Orders the whole filtered queue before the page is sliced, so sorting and paging compose. Defaults to uploaded_desc. An unrecognized value falls back to the default rather than erroring.","schema":{"type":"string","enum":["uploaded_desc","uploaded_asc","doc_desc","doc_asc"],"default":"uploaded_desc"}},{"name":"clientStatuses","in":"query","required":false,"description":"Comma-separated customer lifecycle tiers to include. Practice-wide route only; the customer-scoped route ignores it.","schema":{"type":"string","example":"active,test"}}],"responses":{"200":{"description":"One page of the documents queue. `meta.total` is the row count AFTER the `status` filter; `meta.totalByStatus` and `meta.metrics` are counted BEFORE it, so the summary cards stay populated while a status is selected. The two denominators answer different questions and are expected to differ (#2015).","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"possibleDuplicateOf":{"type":["object","null"],"description":"The earlier document this one repeats: same type, counterparty (vendor, else customer), invoice number, document date and amount (#2738). Null when there is none, or when the earlier document is not listed in the queue. Informational; no status or count depends on it.","required":["id","fileName"],"properties":{"id":{"type":"string","format":"uuid"},"fileName":{"type":"string","description":"The earlier document's file name as the queue shows it for that row."}}}}}},"meta":{"type":"object","properties":{"total":{"type":"integer","description":"Rows matching every filter including `status`. This is the denominator the table pages through."},"limit":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"},"totalByStatus":{"type":"object","additionalProperties":{"type":"integer"},"description":"Per-status counts over the search/type-filtered queue, NOT narrowed by `status`."},"metrics":{"type":"object","additionalProperties":{"type":"integer"},"description":"Summary-card totals derived from `totalByStatus`; likewise not narrowed by `status`."}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/documents/metrics":{"get":{"operationId":"getAccountantDocumentsMetrics","summary":"Read documents metrics","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/threads/metrics":{"get":{"operationId":"getAccountantThreadsMetrics","summary":"Read threads metrics","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/threads":{"get":{"operationId":"getAccountantThreads","summary":"Read threads","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}},"post":{"operationId":"postAccountantThreads","summary":"Create a thread, with an optional first message and attachments","description":"Creates an accountant-owned thread. When `content` is non-empty or `attachments` are present, the first message is written with it: thread, message and attachments are stored together or not at all. Attachments with empty `content` become an attachment-only first message. Every attached document or transaction is admitted against the company named in the body and the caller's authority before anything is written. When an open thread already exists for one of `transactionIds`, that thread is returned with 200 and nothing is written.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountantThreadInput"}}}},"responses":{"200":{"description":"An open thread already existed for the given transactions; it is returned unchanged","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantThreadSummaryResponse"}}}},"201":{"description":"Thread created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantThreadSummaryResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"description":"An attached document or transaction does not resolve for the caller in this company. A reference that belongs to another company, one that does not exist and one the caller has no authority over get the same answer. Nothing is written.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation error, or `THREAD_ATTACHMENT_NOT_ACCEPTED`: an attached document the caller may see has no stored file or its scan verdict is not clean. Nothing is written.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/threads/{threadId}/messages":{"parameters":[{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantThreadsThreadIdMessages","summary":"List messages in a thread (chronological ASC)","description":"Each attachment is resolved for the caller on every read. A `document` or `file` attachment that resolves inside the thread's company, under the caller's own authority, with a servable stored file, is `available` and carries a `downloadUrl` minted for this caller; otherwise it is `available: false` with no link, whatever the reason.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Messages with their attachments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantThreadMessagesListResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"post":{"operationId":"postAccountantThreadsThreadIdMessages","summary":"Reply in a thread (with optional attachments)","description":"Every attached document or transaction is admitted against the thread's company and the caller's authority before anything is written; the message and its attachments are stored together or not at all.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateThreadMessageInput"}}}},"responses":{"201":{"description":"Message created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantThreadMessageResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"description":"The thread was not found, or an attached document or transaction does not resolve for the caller in this company. A reference that belongs to another company, one that does not exist and one the caller has no authority over get the same answer. Nothing is written.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation error, or `THREAD_ATTACHMENT_NOT_ACCEPTED`: an attached document the caller may see has no stored file or its scan verdict is not clean. Nothing is written.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/daily-close/status":{"get":{"operationId":"getAccountantDailyCloseStatus","summary":"Read daily close status","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/daily-close/metrics":{"get":{"operationId":"getAccountantDailyCloseMetrics","summary":"Read daily close metrics","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/companies/{customerId}/daily-close/start":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdDailyCloseStart","summary":"Create or run companies daily close start","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/daily-close/complete":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdDailyCloseComplete","summary":"Create or run companies daily close complete","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/month-end-close":{"get":{"operationId":"getAccountantMonthEndClose","summary":"Read month end close","description":"Month-end checklist aggregated across the accountant's companies. Each company counts on its own close target: the oldest open GL period that has ended, the period readiness, the closing-entry preview and lock use. `period`, `periodKey` and `deadline` are set only when every targeted company shares one target; companies with nothing to close are left out of the counts.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Portfolio month-end progress on each company's close target","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":true,"properties":{"period":{"type":["string","null"],"description":"Label of the close target, e.g. \"August 2026\". Null when there is nothing to close."},"periodKey":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}$","description":"YYYY-MM of the close target. Null exactly when `period` is."},"status":{"type":"string","enum":["completed","in_progress","not_started","nothing_to_close"],"description":"`nothing_to_close` when no open GL period has ended. The calendar month is never substituted."},"deadline":{"type":["string","null"],"format":"date","description":"The 10th of the month after the close target. Null when there is nothing to close."},"overallProgress":{"type":"integer","minimum":0,"maximum":100},"startedAt":{"type":["string","null"]},"sections":{"type":"array","description":"The close target's checklist steps. Empty when there is nothing to close.","items":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string"},"title":{"type":"string"},"status":{"type":"string"},"progress":{"type":"integer"}}}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/month-end-close/by-customer":{"get":{"operationId":"getAccountantMonthEndCloseByCustomer","summary":"Read month end close by customer","description":"One row per assigned company, each on that company's own close target (the oldest open GL period that has ended), so the list agrees with the customer page. Companies with no ended open period report `nothing_to_close`.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Per-company month-end progress on each company's close target","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"customerId":{"type":"string"},"customerName":{"type":"string"},"period":{"type":["string","null"],"description":"This company's close target label. Null when it has nothing to close."},"periodKey":{"type":["string","null"],"description":"YYYY-MM of the close target. Null exactly when `period` is."},"progress":{"type":"integer"},"totalSections":{"type":"integer"},"completedSections":{"type":"integer"},"needsReview":{"type":"integer"},"status":{"type":"string","enum":["completed","in_progress","not_started","nothing_to_close"]}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/companies/{customerId}/month-end-close":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdMonthEndClose","summary":"Read companies month end close","description":"The customer's month-end checklist for its close target: the oldest open GL period that has ended, the same period readiness, the closing-entry preview and lock use. Steps are created for that period. With no ended open period the response is `status: nothing_to_close` with null `period`, `periodKey` and `deadline` and no sections; the calendar month is never substituted.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"The customer's month-end checklist for its close target","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":true,"properties":{"period":{"type":["string","null"],"description":"Label of the close target, e.g. \"August 2026\". Null when there is nothing to close."},"periodKey":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}$","description":"YYYY-MM of the close target. Null exactly when `period` is."},"status":{"type":"string","enum":["completed","in_progress","not_started","nothing_to_close"],"description":"`nothing_to_close` when no open GL period has ended. The calendar month is never substituted."},"deadline":{"type":["string","null"],"format":"date","description":"The 10th of the month after the close target. Null when there is nothing to close."},"overallProgress":{"type":"integer","minimum":0,"maximum":100},"startedAt":{"type":["string","null"]},"sections":{"type":"array","description":"The close target's checklist steps. Empty when there is nothing to close.","items":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string"},"title":{"type":"string"},"status":{"type":"string"},"progress":{"type":"integer"}}}},"preChecks":{"type":"object","additionalProperties":true,"description":"Omitted when there is nothing to close."}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/month-end-close/readiness":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdMonthEndCloseReadiness","summary":"Read companies month end close readiness","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/month-end-close/period-issues":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdMonthEndClosePeriodIssues","summary":"Read companies month end close period issues","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/month-end-close/reconciliation-status":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdMonthEndCloseReconciliationStatus","summary":"Read companies month end close reconciliation status","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker. Lists every active bank account, plus disconnected accounts whose GL account has a non-zero balance at the period end or posted activity in the period (#2874).","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/month-end-close/transaction-review-status":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdMonthEndCloseTransactionReviewStatus","summary":"Read companies month end close transaction review status","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/month-end-close/closing-entry-preview":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdMonthEndCloseClosingEntryPreview","summary":"Read companies month end close closing entry preview","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/month-end-close/lock":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdMonthEndCloseLock","summary":"Create or run companies month end close lock","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/month-end-close/run-detection":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"runMonthEndCloseDetection","summary":"Run the accrual detector for a period before locking it","description":"The month-end close page's \"Run detection\" step (#1266). Runs the period-aware accrual detector for one GL period of this customer; the deferral detector is not run here (it runs on every sync). The lock does not depend on this call, and a successful lock starts the same sweep for its period in the background afterwards.\n\nIt never posts a journal entry, creates a schedule, approves a proposal, or changes close or period state. It can create proposals (some created `blocked` by the QA gate), supersede an older live proposal for the same candidate when its inputs changed or its real charge has posted, move an approved-but-unposted proposal to `blocked` when its real charge has posted, close the low-confidence review task of a proposal it supersedes, and write decision-manifest rows and audit events. If the detector fails midway, the proposals that run created are expired.\n\nBounded by a 20-second budget; a sweep that runs past it is reported as `timed_out` and may still finish afterwards. `detection_off` when `accruals_deferrals_detection` is off for the company (nothing runs). `partial` when some candidates could not be judged; `skipped` says why. A filing-locked period is refused with 422; open and closed periods are accepted.","tags":["Accountant Portal","Schedule Proposals"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonthEndRunDetectionInput"}}}},"responses":{"200":{"description":"What the detection run did","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonthEndRunDetectionResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"Detection is already running for this company and period","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Invalid body, or the period is filing-locked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"The accountant's assignment could not be verified right now","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/month-end-close/steps/{stepId}/complete":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"stepId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdMonthEndCloseStepsStepIdComplete","summary":"Create or run companies month end close steps complete","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/health/close-metrics":{"get":{"operationId":"getAccountantHealthCloseMetrics","summary":"Read health close metrics","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/client-actions":{"get":{"operationId":"getAccountantClientActions","summary":"Read client actions","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/client-actions/{actionId}/approve":{"parameters":[{"name":"actionId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantClientActionsActionIdApprove","summary":"Create or run client actions approve","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/client-actions/{actionId}/reject":{"parameters":[{"name":"actionId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantClientActionsActionIdReject","summary":"Create or run client actions reject","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/client-actions/{actionId}/message-client":{"parameters":[{"name":"actionId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantClientActionsActionIdMessageClient","summary":"Create or run client actions message client","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/chart-of-accounts":{"get":{"operationId":"getAccountantChartOfAccounts","summary":"Read chart of accounts","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact row shape. `meta.truncated` is authoritative (#1959): true means an assigned customer's report-access lookup could not be evaluated and its accounts are missing from `data`.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; `meta.truncated` reports scope completeness","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/AccountantScopeMeta"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/general-ledger":{"get":{"operationId":"getAccountantGeneralLedger","summary":"Read general ledger","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact row shape. `meta.truncated` is authoritative (#1959): true means an assigned customer's report-access lookup could not be evaluated and its ledger lines are missing from `data`.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; `meta.truncated` reports scope completeness","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/AccountantScopeMeta"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/journal-entries":{"get":{"operationId":"getAccountantJournalEntries","summary":"Read journal entries","description":"Posted journal entries across every assigned customer the accountant may view reports for (up to `limit` rows per customer, 500 by default), newest entry date first (#1703). `data` is a bare array. `meta.hasMore` is true when any customer had more rows than `limit`; `meta.nextCursor` is always null here because cursor paging is customer-scoped only — page one customer via /accountant/companies/{customerId}/journal-entries. `meta.truncated` is true when a customer's report-access lookup could not be evaluated and its entries are missing (#1959).","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"dateFrom","in":"query","required":false,"description":"Inclusive journal entry date lower bound. Invalid dates or an inverted range return 422.","schema":{"type":"string","format":"date"}},{"name":"dateTo","in":"query","required":false,"description":"Inclusive journal entry date upper bound. Omit bounds to retain the unfiltered list.","schema":{"type":"string","format":"date"}},{"name":"limit","in":"query","required":false,"description":"Rows per assigned customer. Defaults to and is capped at 500; an out-of-range or non-numeric value falls back to the 500-row default rather than erroring.","schema":{"type":"integer","minimum":1,"maximum":500,"default":500}},{"name":"cursor","in":"query","required":false,"description":"Not supported on the cross-customer route — any value is rejected with 400. Use the customer-scoped route to page.","schema":{"type":"string"}}],"responses":{"200":{"description":"Journal entries across assigned customers; `meta.nextCursor` is always null on this route","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"nextCursor":{"type":["string","null"]},"hasMore":{"type":"boolean"},"truncated":{"$ref":"#/components/schemas/AccountantScopeTruncated"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/reports":{"get":{"operationId":"getAccountantReports","summary":"Read reports","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BasisQueryParam"}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"data":{"$ref":"#/components/schemas/AccountantReportsBundle"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"422":{"description":"`basis` is not `accrual` or `cash`. A cash statement that cannot be produced is not a 422 on this route: it is an unavailable statement inside the 200.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/business-events":{"get":{"operationId":"getAccountantBusinessEvents","summary":"Read business events","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"}}}},"/accountant/companies/{customerId}/financials":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdFinancials","summary":"Read companies financials","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/activity":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdActivity","summary":"Read companies activity","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker. `meta.limit` reports the row cap actually applied.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Maximum rows to return, capped at 100. With no value the feed keeps its historical shape (10 transactions plus up to 5 threads, merged and cut at 20). The applied cap is echoed in `meta.limit`.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/ai-metrics":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdAiMetrics","summary":"Read companies ai metrics","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"503":{"description":"Transaction review metrics could not be completely aggregated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/integrations/health":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdIntegrationsHealth","summary":"Read companies integrations health","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/integrations/credentials":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdIntegrationsCredentials","summary":"Read companies integrations credentials","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/integrations/reconciliations":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdIntegrationsReconciliations","summary":"Read companies integrations reconciliations","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/integrations/{provider}/{integrationId}/accounts/{accountId}/statements":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"provider","in":"path","required":true,"schema":{"type":"string"}},{"name":"integrationId","in":"path","required":true,"schema":{"type":"string"}},{"name":"accountId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdIntegrationsProviderIntegrationIdAccountsAccountIdStatements","summary":"Read companies integrations accounts statements","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/integrations/{provider}/resync":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"provider","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdIntegrationsProviderResync","summary":"Create or run companies integrations resync","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/sync-health":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdSyncHealth","summary":"Read companies sync health","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/workflow-traces":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdWorkflowTraces","summary":"Read companies workflow traces","description":"The newest `limit` workflow runs for a customer, newest first. `data` is a page by design; the summary counts belong in `meta`, which is counted over EVERY run for the customer (#2014). Do not derive totals from `data` — that is the defect this contract exists to prevent.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Runs returned in `data`. Clamped to [1, 50]; defaults to 20. Does not affect `meta`.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"One page of workflow runs, with counts over all of them in `meta`","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"returned":{"type":"integer","description":"Runs in `data`. Never a total."},"total":{"type":["integer","null"],"description":"Distinct runs for the customer, all statuses. Null when the count could not be computed; render it as unavailable rather than falling back to `returned`."},"byStatus":{"type":["object","null"],"additionalProperties":{"type":"integer"},"description":"Runs per terminal status (running, completed, partial, failed, action_required), counted from each run's latest audit row."}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transactions":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdTransactions","summary":"Read companies transactions","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker. This list is keyset-paged with `limit` and `cursor`; `page` and `offset` are rejected with 422 rather than accepted and ignored.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Maximum rows per page, 1 through 100. Out-of-range values return 422. Follow meta.nextCursor while meta.hasMore is true.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","required":false,"description":"Opaque meta.nextCursor from the previous page. Keep the same sort and filters; a cursor from another sort returns 422.","schema":{"type":"string"}},{"name":"sort","in":"query","required":false,"description":"Stable order on every page. Amount and confidence ties use occurredOn then ID descending; date ties follow date direction. Null confidence sorts last.","schema":{"type":"string","default":"date_desc","enum":["date_asc","date_desc","amount_asc","amount_desc","confidence_asc","confidence_desc"]}},{"name":"page","in":"query","required":false,"description":"Not supported. Present only so the rejection is explicit; this list pages with `limit` and `cursor`. Any value returns 422.","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Not supported. Present only so the rejection is explicit; this list pages with `limit` and `cursor`. Any value returns 422.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/transactions/review":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdTransactionsReview","summary":"Read companies transactions review","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact row shape. `meta.truncated` is true when this customer has more than 5,000 matching rows; continue with `?segmentCursor=` from `meta.rowCappedCustomers`.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"limit","in":"query","description":"Rows per response page. The total covers all rows matching the filters across the selected companies.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":500}},{"name":"offset","in":"query","description":"Use meta.nextOffset from the preceding page while meta.hasMore is true. Keep all filters unchanged.","schema":{"type":"integer","minimum":0,"default":0}},{"name":"classId","in":"query","schema":{"type":"string"}},{"name":"tagId","in":"query","description":"Accounting tag filter (#1166), repeated or comma-separated, up to 50 UUIDs; ANY listed tag (existence test). ORed with `untagged`.","schema":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50}]}},{"name":"untagged","in":"query","description":"When `true`, include transactions with no tag (ORed with `tagId`).","schema":{"type":"string","enum":["true","false"]}},{"name":"tier","in":"query","schema":{"type":"string","enum":["all","escalated","review","auto_approved"]}},{"name":"transferAction","in":"query","schema":{"type":"string","enum":["pending","proposed","approved","applied","none"]}},{"name":"postedToGlAccountId","in":"query","description":"#1166 E1: only transactions with at least one posted, non-deleted journal entry of this company that has a line on this GL account (the entry's transaction source or a line's transaction). Combines with every other filter. Not a UUID: 422.","schema":{"type":"string","format":"uuid"}},{"name":"segmentCursor","in":"query","description":"Continue a row-capped customer's queue from meta.rowCappedCustomers[].segmentCursor. Customer routes only (400 without a customer).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success envelope; `meta.truncated` is true when this customer has more than 5,000 matching rows; continue with `?segmentCursor=` from `meta.rowCappedCustomers`","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/AccountantQueueMeta"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"Offset pagination state conflicts with the preceding page."},"422":{"$ref":"#/components/responses/ValidationError"},"500":{"description":"A company fetch failed. No partial queue is returned."}}}},"/accountant/companies/{customerId}/transactions/auto-approved":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdTransactionsAutoApproved","summary":"Read companies transactions auto approved","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact row shape. `meta.truncated` is true when this customer has more than 5,000 matching rows; continue with `?segmentCursor=` from `meta.rowCappedCustomers`.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"limit","in":"query","description":"Rows per response page. The total covers all rows matching the filters across the selected companies.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":500}},{"name":"offset","in":"query","description":"Use meta.nextOffset from the preceding page while meta.hasMore is true. Keep all filters unchanged.","schema":{"type":"integer","minimum":0,"default":0}},{"name":"classId","in":"query","schema":{"type":"string"}},{"name":"tagId","in":"query","description":"Accounting tag filter (#1166), repeated or comma-separated, up to 50 UUIDs; ANY listed tag (existence test). ORed with `untagged`.","schema":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50}]}},{"name":"untagged","in":"query","description":"When `true`, include transactions with no tag (ORed with `tagId`).","schema":{"type":"string","enum":["true","false"]}},{"name":"tier","in":"query","schema":{"type":"string","enum":["all","escalated","review","auto_approved"]}},{"name":"transferAction","in":"query","schema":{"type":"string","enum":["pending","proposed","approved","applied","none"]}},{"name":"postedToGlAccountId","in":"query","description":"#1166 E1: only transactions with at least one posted, non-deleted journal entry of this company that has a line on this GL account (the entry's transaction source or a line's transaction). Combines with every other filter. Not a UUID: 422.","schema":{"type":"string","format":"uuid"}},{"name":"segmentCursor","in":"query","description":"Continue a row-capped customer's queue from meta.rowCappedCustomers[].segmentCursor. Customer routes only (400 without a customer).","schema":{"type":"string"}}],"responses":{"200":{"description":"Success envelope; `meta.truncated` is true when this customer has more than 5,000 matching rows; continue with `?segmentCursor=` from `meta.rowCappedCustomers`","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/AccountantQueueMeta"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"Offset pagination state conflicts with the preceding page."},"422":{"$ref":"#/components/responses/ValidationError"},"500":{"description":"A company fetch failed. No partial queue is returned."}}}},"/accountant/companies/{customerId}/bank-accounts":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdBankAccounts","summary":"Create a manual reconcilable bank account","description":"Creates a manual bank account (no integration, no provider) on an existing GL account so a bank, card or processor account that exists only in the chart of accounts can be reconciled (#2874). The GL account must belong to the customer, be active and postable, resolve to a cash, treasury, clearing or credit-card detail type, and not be a Median system account (1080 Transfer Clearing). Posts nothing to the ledger. `entityId` and `currency` default from the company's one legal entity. Service-principal access reviewed 2026-10-01 (#2874).","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateManualBankAccountInput"}}}},"responses":{"201":{"description":"Manual bank account created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BankAccountResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"An active bank account already posts to this GL account (`BANK_ACCOUNT_GL_ALREADY_MAPPED`), or an account with the same institution, type and last 4 already exists (`MANUAL_BANK_ACCOUNT_DUPLICATE`)"},"422":{"description":"Validation error, including a GL account that is not the customer's, is inactive or non-postable, or is not a bank, cash, clearing or credit-card account"}}}},"/accountant/companies/{customerId}/accounts":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdAccounts","summary":"List the accounts a CSV import can post to","description":"The \"deposit to\" accounts the accountant portal's CSV import modal offers for this customer, as one flat list: connected accounts (`integration`), bank accounts not already surfaced by a connected account (`bank`), and the active Asset and Liability Chart-of-Accounts rows (`gl_account`). A bank or connected row carries the currency it gives imported rows that have none; a Chart-of-Accounts row reports the currency the importer would resolve for it as `importCurrency` (#2162).\n","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"The accounts in the order the modal lists them (connected, bank, Chart of Accounts).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantCustomerAccountsResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transactions/{transactionId}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdTransactionsTransactionId","summary":"Read companies transactions","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"patch":{"operationId":"patchAccountantCompaniesCustomerIdTransactionsTransactionId","summary":"Update companies transactions","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"description":"Validation or business rule error; nothing is written. `error.title` carries the rule: `TRANSACTION_CATEGORY_IS_BANK_ACCOUNT` (the category is the GL account of the transaction's own bank or card account), `TRANSACTION_APPLIED_TRANSFER_MATCH_ACTIVE` (the journal entry is consolidated with another transaction; unmatch first), `TRANSACTION_BANK_OFFSET_UNIDENTIFIED` (the journal entry debits and credits one account; run the bank-offset repair first). Also returned, with no `error.title` code, when the body sets `categoryGlAccountId` on a Stripe revenue row (an inbound Stripe charge, invoice payment or subscription payment, or a row with categorizationSource stripe_counterparty_history): a category set here would not write the merchant rule its Stripe revenue entry needs, so the revenue would stay held. Two exceptions are let through: the row is already categorized on that account (nothing changes), or the row was categorized by hand (categorizationSource manual) and the new account is a usable Stripe revenue account of the company, in which case the row's own category is its revenue authority and stays so. Otherwise use POST .../transactions/{transactionId}/approve or .../transactions/bulk-recategorize instead (#3039).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"delete":{"operationId":"deleteAccountantCompaniesCustomerIdTransactionsTransactionId","summary":"Delete companies transactions","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/soft-delete":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdTransactionsTransactionIdSoftDelete","summary":"Create or run companies transactions soft delete","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/bank-offset-repair":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"repairAccountantTransactionBankOffset","summary":"Repair a transaction journal entry that debits and credits the same account","description":"#2912. For one transaction whose single posted journal entry has both lines on one GL account (balanced, and booking nothing): void-and-replaces it with the canonical two-line posting -- the bank or card offset rebuilt from the transaction's own bank account and direction (money in debits the bank GL, money out credits it), the counterpart on `categoryGlAccountId` -- and sets the transaction's category to match as a manual decision. The replacement inherits the voided entry's date, period, entity, source, description and posting key; both entries are linked to each other and an audit row records the actor, reason and before/after lines. Dry run by default: it returns the exact before and after lines and writes nothing. An apply (`dryRun: false`) must name the journal entry the dry run showed. Every eligibility check runs before any write; anything that is not exactly that shape is refused without a guessed replacement. A replay of an applied repair returns `already_repaired` and writes nothing. Human accountants only: the service token gets 404, and the accountant's assignment is re-read from the database before the request body is parsed.\n","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepairTransactionBankOffsetRequest"}}}},"responses":{"200":{"description":"Dry-run plan, applied repair, or already-repaired replay","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BankOffsetRepairResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"Refused, nothing written. `error.title` is one of `BANK_OFFSET_REPAIR_JOURNAL_COUNT` (not exactly one posted transaction journal entry), `BANK_OFFSET_REPAIR_JOURNAL_CHANGED` (`expectedJournalEntryId` is not the posted entry), `BANK_OFFSET_REPAIR_NOT_SELF_CANCELLING`, `BANK_OFFSET_REPAIR_SHAPE_AMBIGUOUS`, `BANK_OFFSET_REPAIR_BANK_MAPPING_CHANGED`, `BANK_OFFSET_REPAIR_RACE`, `JOURNAL_ENTRY_SHARED_AUTHORITY` (consolidated with another transaction), `JOURNAL_ENTRY_ENTITY_AUTHORITY_CONFLICT`, `TRANSACTION_DOCUMENT_MATCH_ACTIVE`, `TRANSACTION_APPLIED_TRANSFER_MATCH_ACTIVE` or `TRANSACTION_CATEGORY_ACCOUNTING_INCOMPLETE`.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Request validation failed, or refused with nothing written. `error.title` is one of `TRANSACTION_CATEGORY_IS_BANK_ACCOUNT`, `TRANSACTION_RECONCILED`, `JOURNAL_ENTRY_RECONCILED`, `JOURNAL_ENTRY_PERIOD_LOCKED` (filing-locked; a closed, unfiled period is allowed), `BANK_OFFSET_REPAIR_EXCLUDED_FROM_BOOKS` (no business bank account mapped to a postable GL account), `BANK_OFFSET_REPAIR_SPLIT`, `BANK_OFFSET_REPAIR_NATIVE_STRIPE`, `BANK_OFFSET_REPAIR_CURRENCY`, or a category account that cannot be posted to.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/splits":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"listAccountantTransactionSplits","summary":"List a customer transaction's split legs","description":"#876. Split legs (GL account, amount in minor units, optional class and memo) for one transaction. Empty array when the transaction is not split.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of splits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionSplitsListResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"put":{"operationId":"replaceAccountantTransactionSplits","summary":"Split a customer transaction (create or replace its legs)","description":"#876. Replaces every split leg and void-and-replaces the posted transaction journal entry with one category line per leg (the bank/card offset leg is preserved). Legs must sum exactly to the transaction amount; at least 2 legs. Legs may carry a classId. Acts as the accountant: no client action is queued for review. 422 when the transaction is reconciled, has an applied transfer/credit-card match, is matched to a bill/document, is on a personal bank account, or its entry is in a filing-locked period.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplaceSplitsInput"}}}},"responses":{"200":{"description":"Splits replaced","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionSplitsListResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"description":"Validation or business rule error. `error.title` is `TRANSACTION_CATEGORY_IS_BANK_ACCOUNT` when a leg is the transaction's own bank or card GL account, and `TRANSACTION_BANK_OFFSET_UNIDENTIFIED` when the posted journal entry debits and credits one account off the bank GL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"delete":{"operationId":"unsplitAccountantTransaction","summary":"Un-split a customer transaction back to one category","description":"#876. Deletes the split legs, clears isSplit, sets the parent category, and void-and-replaces the posted journal entry with a single category line. Same 422 guards as the PUT.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"categoryGlAccountId","in":"query","required":true,"description":"GL account the whole transaction amount reposts to.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success envelope with the updated transaction","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"description":"Validation or business rule error. Same `TRANSACTION_CATEGORY_IS_BANK_ACCOUNT` and `TRANSACTION_BANK_OFFSET_UNIDENTIFIED` refusals as the PUT.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/engine-decisions":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdTransactionsTransactionIdEngineDecisions","summary":"Read companies transactions engine decisions","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/documents/queue":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdDocumentsQueue","summary":"Read companies documents queue","description":"One offset-paged page of a single customer's documents queue, newest upload first by default (#2015). `data` is a bare array of at most `meta.limit` rows; page with `offset`.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Rows per page. Defaults to 200 and is capped at 500; an out-of-range or non-numeric value falls back to the 200-row default rather than erroring.","schema":{"type":"integer","minimum":1,"maximum":500,"default":200}},{"name":"offset","in":"query","required":false,"description":"Rows to skip before the page. Defaults to 0; a negative or non-numeric value falls back to 0.","schema":{"type":"integer","minimum":0,"default":0}},{"name":"search","in":"query","required":false,"description":"Case-insensitive substring match applied before `status`, so the status counts in `meta.totalByStatus` reflect it.","schema":{"type":"string"}},{"name":"type","in":"query","required":false,"description":"Filters on the queue's normalized document type. Applied before `status`, so it is reflected in `meta.totalByStatus`. An unrecognized value is ignored rather than erroring.","schema":{"type":"string","enum":["invoice","bill","receipt","contract","statement"]}},{"name":"status","in":"query","required":false,"description":"Filters on the queue's display status. Applied AFTER the counts, so `meta.total` narrows with it while `meta.totalByStatus` and `meta.metrics` do not. An unrecognized value is ignored rather than erroring.","schema":{"type":"string","enum":["needs_review","pending_payment","reviewed","paid","processed","archived"]}},{"name":"sort","in":"query","required":false,"description":"Orders the whole filtered queue before the page is sliced, so sorting and paging compose. Defaults to uploaded_desc. An unrecognized value falls back to the default rather than erroring.","schema":{"type":"string","enum":["uploaded_desc","uploaded_asc","doc_desc","doc_asc"],"default":"uploaded_desc"}}],"responses":{"200":{"description":"One page of the documents queue. `meta.total` is the row count AFTER the `status` filter; `meta.totalByStatus` and `meta.metrics` are counted BEFORE it, so the summary cards stay populated while a status is selected. The two denominators answer different questions and are expected to differ (#2015).","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"possibleDuplicateOf":{"type":["object","null"],"description":"The earlier document this one repeats: same type, counterparty (vendor, else customer), invoice number, document date and amount (#2738). Null when there is none, or when the earlier document is not listed in the queue. Informational; no status or count depends on it.","required":["id","fileName"],"properties":{"id":{"type":"string","format":"uuid"},"fileName":{"type":"string","description":"The earlier document's file name as the queue shows it for that row."}}}}}},"meta":{"type":"object","properties":{"total":{"type":"integer","description":"Rows matching every filter including `status`. This is the denominator the table pages through."},"limit":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"},"totalByStatus":{"type":"object","additionalProperties":{"type":"integer"},"description":"Per-status counts over the search/type-filtered queue, NOT narrowed by `status`."},"metrics":{"type":"object","additionalProperties":{"type":"integer"},"description":"Summary-card totals derived from `totalByStatus`; likewise not narrowed by `status`."}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/documents/{documentId}/extraction":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"documentId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdDocumentsDocumentIdExtraction","summary":"Read companies documents extraction","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/documents/{documentId}/extractions":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"documentId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdDocumentsDocumentIdExtractions","summary":"Read companies documents extractions","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/documents/{documentId}/contract-schedule":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"documentId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdDocumentsDocumentIdContractSchedule","summary":"Read companies documents contract schedule","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/documents/{documentId}/contract-schedule/approve":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"documentId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdDocumentsDocumentIdContractScheduleApprove","summary":"Create or run companies documents contract schedule approve","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/documents/{documentId}/contract-schedule/reject":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"documentId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdDocumentsDocumentIdContractScheduleReject","summary":"Create or run companies documents contract schedule reject","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/google-workspace/backfill-missing-documents":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdGoogleWorkspaceBackfillMissingDocuments","summary":"Create or run companies google workspace backfill missing documents","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/document-artifacts/backfill":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdDocumentArtifactsBackfill","summary":"Create or run companies document artifacts backfill","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/document-artifacts/quarantine":{"get":{"operationId":"getAccountantDocumentArtifactsQuarantine","summary":"Read document artifacts quarantine","description":"Quarantined Google Workspace ingestion artifacts across the accountant's assigned companies, newest first. `data.artifacts` is capped at 200 and so can never report the queue's size; `meta.total` counts every artifact matching the same filters (#2014).","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Artifacts returned. Clamped to [1, 200]; defaults to 50. Does not affect `meta.total`.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"clientStatuses","in":"query","required":false,"description":"Comma-separated customer lifecycle tiers to include. Applied to BOTH the list and the count, so the badge and the table describe one population. Ignored when `customerId` is given.","schema":{"type":"string","example":"active,test"}},{"name":"reason","in":"query","required":false,"description":"#2591: only artifacts quarantined for this hygiene reason (`metadata.hygieneReason`). Applied to BOTH the list and the count. Any other value is rejected with 422.","schema":{"type":"string","enum":["gmail_other_client_document","gmail_staff_mailbox_non_billing","gmail_ambiguous_attachment_dropped"]}},{"name":"customerId","in":"query","required":false,"description":"#2591: only this customer's artifacts. Must be one of the accountant's own assigned companies (403 otherwise); a malformed id is rejected with 422.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"One page of the quarantine queue, with the queue's true size in `meta`","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"artifacts":{"type":"array","items":{"type":"object","additionalProperties":true}},"unavailable":{"type":"boolean"}}},"meta":{"type":"object","properties":{"limit":{"type":"integer"},"returned":{"type":"integer","description":"Artifacts in `data.artifacts`. Never a total."},"total":{"type":["integer","null"],"description":"Artifacts matching the same filters, ignoring `limit`. Null when the count could not be computed."},"truncated":{"type":"boolean","description":"True when a company's lifecycle status could not be evaluated and its artifacts are therefore missing from both the list and the count."}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/document-artifacts/{artifactId}":{"parameters":[{"name":"artifactId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantDocumentArtifactsArtifactId","summary":"Read document artifacts","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/document-artifacts/{artifactId}/promote":{"parameters":[{"name":"artifactId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantDocumentArtifactsArtifactIdPromote","summary":"Create or run document artifacts promote","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"The artifact is no longer in the review queue (already promoted, archived, rejected, or marked as a repeat), or a live document already exists for the same attachment (#3198). Nothing is written.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/document-artifacts/{artifactId}/archive":{"parameters":[{"name":"artifactId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantDocumentArtifactsArtifactIdArchive","summary":"Create or run document artifacts archive","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"The artifact is no longer in the review queue (already promoted, archived, rejected, or marked as a repeat) (#3198). Nothing is written.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/document-artifacts/{artifactId}/reject":{"parameters":[{"name":"artifactId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantDocumentArtifactsArtifactIdReject","summary":"Create or run document artifacts reject","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"The artifact is no longer in the review queue (already promoted, archived, rejected, or marked as a repeat) (#3198). Nothing is written.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/documents/upload/init":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdDocumentsUploadInit","summary":"Create or run companies documents upload init","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/documents":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdDocuments","summary":"Create or run companies documents","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/threads":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdThreads","summary":"Read companies threads","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"post":{"operationId":"postAccountantCompaniesCustomerIdThreads","summary":"Create a thread, with an optional first message and attachments","description":"Creates an accountant-owned thread. When `content` is non-empty or `attachments` are present, the first message is written with it: thread, message and attachments are stored together or not at all. Attachments with empty `content` become an attachment-only first message. Every attached document or transaction is admitted against the path's company and the caller's authority before anything is written. When an open thread already exists for one of `transactionIds`, that thread is returned with 200 and nothing is written.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountantThreadInput"}}}},"responses":{"200":{"description":"An open thread already existed for the given transactions; it is returned unchanged","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantThreadSummaryResponse"}}}},"201":{"description":"Thread created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantThreadSummaryResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"description":"An attached document or transaction does not resolve for the caller in this company. A reference that belongs to another company, one that does not exist and one the caller has no authority over get the same answer. Nothing is written.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation error, or `THREAD_ATTACHMENT_NOT_ACCEPTED`: an attached document the caller may see has no stored file or its scan verdict is not clean. Nothing is written.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/threads/{threadId}/messages":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdThreadsThreadIdMessages","summary":"List messages in a thread (chronological ASC)","description":"Each attachment is resolved for the caller on every read. A `document` or `file` attachment that resolves inside the thread's company, under the caller's own authority, with a servable stored file, is `available` and carries a `downloadUrl` minted for this caller; otherwise it is `available: false` with no link, whatever the reason.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"Messages with their attachments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantThreadMessagesListResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"post":{"operationId":"postAccountantCompaniesCustomerIdThreadsThreadIdMessages","summary":"Reply in a thread (with optional attachments)","description":"Every attached document or transaction is admitted against the thread's company and the caller's authority before anything is written; the message and its attachments are stored together or not at all.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateThreadMessageInput"}}}},"responses":{"201":{"description":"Message created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountantThreadMessageResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"description":"The thread was not found, or an attached document or transaction does not resolve for the caller in this company. A reference that belongs to another company, one that does not exist and one the caller has no authority over get the same answer. Nothing is written.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation error, or `THREAD_ATTACHMENT_NOT_ACCEPTED`: an attached document the caller may see has no stored file or its scan verdict is not clean. Nothing is written.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/threads/{threadId}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"patch":{"operationId":"patchAccountantCompaniesCustomerIdThreadsThreadId","summary":"Update companies threads","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/client-actions":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdClientActions","summary":"Read companies client actions","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/client-actions/{actionId}/message-client":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"actionId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdClientActionsActionIdMessageClient","summary":"Create or run companies client actions message client","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/general-ledger":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdGeneralLedger","summary":"Read companies general ledger","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact row shape. `meta.truncated` is emitted for parity with the practice-wide read (#1959) and is always false on this customer-scoped route, which never fans out; its ledger lines are never dropped by a scope lookup.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; `meta.truncated` is present for parity with the practice-wide read and is always false here","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/AccountantScopeMeta"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/merchant-rules":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdMerchantRules","summary":"Read learned merchant rules for an assigned customer","description":"#2383 read route for the bookkeeping service token. Lists every rule that can categorize this customer's transactions: its company rules first, then the global rules, paged (follow meta.nextCursor while meta.hasMore is true; scope=company or scope=global narrows it). Does not create or update a rule. Assignment is required; an unassigned company is forbidden.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope of merchant rules for this customer only","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"post":{"operationId":"postAccountantCompaniesCustomerIdMerchantRules","summary":"Create a merchant rule for this customer","description":"#3039. Accountant login only: the service token is refused. Creates a company rule, which outranks a global rule for the same merchant. glAccountCode must be an active account in this customer's chart (422 otherwise); the rule's account name and type are taken from that account. merchantPattern needs at least 3 characters, cannot contain %, _, a backslash or a control character, and cannot consist only of generic words such as fee or payment (422). A pattern and match field another rule of this customer already has is 409. Rows already categorized are not changed; rows still in needs_review with no category are categorized by it on the next sync, and an exact rule with a Revenue target releases that customer's held Stripe revenue on the next posting attempt. Writes an audit_logs row (entity_type merchant_rule, action create).","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["merchantPattern","glAccountCode"],"properties":{"merchantPattern":{"type":"string","minLength":1,"maxLength":500},"matchField":{"type":"string","enum":["merchant_name","description"],"default":"merchant_name"},"glAccountCode":{"type":"string","minLength":1,"maxLength":20},"priority":{"type":"integer","minimum":0,"maximum":1000,"default":100}}}}}},"responses":{"201":{"description":"The created rule","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":true}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"409":{"description":"Another rule of this customer already has that pattern and match field"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/merchant-rules/{id}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"patchAccountantCompaniesCustomerIdMerchantRulesId","summary":"Edit one of this customer's merchant rules","description":"#3039. Accountant login only: the service token is refused, because a repointed rule categorizes every later matching row at 99% without review. Only a rule that belongs to this customer can be edited; another company's rule and a global rule are 404. When glAccountCode is sent it must be an active account in this customer's chart (400 otherwise), and the rule's glAccountName and glAccountType are taken from that account; values sent for those two fields are ignored. merchantPattern needs at least 3 characters, cannot contain %, _, a backslash or a control character, and cannot consist only of generic words such as fee or payment (422 otherwise); a pattern and match field another rule of this customer already has is 409. A non-UUID path id is 422. Writes an audit_logs row (entity_type merchant_rule, action update) with the rule before and after; a PATCH that changes nothing writes none.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"merchantPattern":{"type":"string","minLength":1,"maxLength":500},"matchField":{"type":"string","enum":["merchant_name","description"]},"glAccountCode":{"type":"string","minLength":1,"maxLength":20},"priority":{"type":"integer","minimum":0,"maximum":1000}}}}}},"responses":{"200":{"description":"The updated rule","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":["string","null"],"format":"uuid","description":"null for a global rule"},"merchantPattern":{"type":"string"},"matchField":{"type":"string","enum":["merchant_name","description"]},"glAccountCode":{"type":"string"},"glAccountName":{"type":"string"},"glAccountType":{"type":"string"},"scope":{"type":"string","enum":["company","global"]},"priority":{"type":"integer"}}}}}}}},"400":{"description":"glAccountCode is not an active account in this customer's chart"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"operationId":"deleteAccountantCompaniesCustomerIdMerchantRulesId","summary":"Delete one of this customer's merchant rules","description":"#3039. Accountant login only: the service token is refused. Later rows the rule would have matched fall back to the other rules and the engine, and so to review. Only a rule that belongs to this customer can be deleted; another company's rule and a global rule are 404. Writes an audit_logs row (entity_type merchant_rule, action delete) with the rule as it was.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Deleted"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transactions/{transactionId}/merchant-rule":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"transactionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdTransactionsTransactionIdMerchantRule","summary":"Which merchant rule categorized this transaction","description":"#3039. recordedRuleId is the rule the latest merchant-rule categorization of this transaction named when it ran; it is null for a transaction no rule categorized and for one categorized before #3039 shipped. recordedRule is that rule as it is now, or null when it has been deleted. recordedRuleId is also null when a person recategorized the transaction after the rule ran. matchingRules are the company and global rules whose pattern matches the transaction's merchant and description today, in rule order; other categorization steps (vendor patterns, transfers, Stripe rows) can take a row before any of them, so the first entry is not proof of what categorized this transaction or what will categorize the next one. A non-UUID path id is 422.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"The recorded rule and today's matching rules","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["recordedRuleId","recordedRule","matchingRules"],"properties":{"recordedRuleId":{"type":["string","null"],"description":"A rule row id (UUID), or a built-in global rule id such as global-vocab:slack"},"recordedRule":{"type":["object","null"],"additionalProperties":true},"matchingRules":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdChartOfAccounts","summary":"Read companies chart of accounts","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact row shape. `meta.truncated` is emitted for parity with the practice-wide read (#1959) and is always false on this customer-scoped route, which never fans out; its accounts are never dropped by a scope lookup.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; `meta.truncated` is present for parity with the practice-wide read and is always false here","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"$ref":"#/components/schemas/AccountantScopeMeta"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"post":{"operationId":"postAccountantCompaniesCustomerIdChartOfAccounts","summary":"Create or run companies chart of accounts","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker. Service-principal access reviewed 2026-09-10 (#1982).","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Exact replay (#2883): an active account with the same code, name, type, detail type, subtype, parent and normal balance already exists; it is returned and nothing is written","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"201":{"description":"GL account created, audited with the acting accountant","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"Account code already exists with different fields (GL_ACCOUNT_CODE_CONFLICT) or belongs to a retired account (GL_ACCOUNT_CODE_RETIRED)","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/chart-of-accounts/detail-types":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdChartOfAccountsDetailTypes","summary":"Read companies chart of accounts detail types","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts/templates":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdChartOfAccountsTemplates","summary":"Read companies chart of accounts templates","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts/templates/preview":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdChartOfAccountsTemplatesPreview","summary":"Create or run companies chart of accounts templates preview","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts/templates/commit":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdChartOfAccountsTemplatesCommit","summary":"Create or run companies chart of accounts templates commit","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts/import/preview":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdChartOfAccountsImportPreview","summary":"Create or run companies chart of accounts import preview","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts/import/commit":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdChartOfAccountsImportCommit","summary":"Create or run companies chart of accounts import commit","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts/import/opening-balance-proposals":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdChartOfAccountsImportOpeningBalanceProposals","summary":"Read companies chart of accounts import opening balance proposals","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"post":{"operationId":"postAccountantCompaniesCustomerIdChartOfAccountsImportOpeningBalanceProposals","summary":"Create or run companies chart of accounts import opening balance proposals","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts/import/opening-balance-proposals/{proposalId}/post":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"proposalId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdChartOfAccountsImportOpeningBalanceProposalsProposalIdPost","summary":"Create or run companies chart of accounts import opening balance proposals post","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts/import/opening-balance-proposals/{proposalId}/reject":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"proposalId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdChartOfAccountsImportOpeningBalanceProposalsProposalIdReject","summary":"Create or run companies chart of accounts import opening balance proposals reject","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts/{accountId}/register":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"accountId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdChartOfAccountsAccountIdRegister","summary":"Read companies chart of accounts register","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BasisQueryParam"}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"data":{"type":"object","additionalProperties":true,"properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"cashBasisSource":{"$ref":"#/components/schemas/CashBasisLineProvenance"}}}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"$ref":"#/components/responses/ReportBasisUnprocessable"}}}},"/accountant/companies/{customerId}/chart-of-accounts/{accountId}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"accountId","in":"path","required":true,"schema":{"type":"string"}}],"patch":{"operationId":"patchAccountantCompaniesCustomerIdChartOfAccountsAccountId","summary":"Update companies chart of accounts","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts/{accountId}/lock":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"accountId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdChartOfAccountsAccountIdLock","summary":"Create or run companies chart of accounts lock","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts/{accountId}/unlock":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"accountId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdChartOfAccountsAccountIdUnlock","summary":"Create or run companies chart of accounts unlock","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts/{accountId}/deactivate":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"accountId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdChartOfAccountsAccountIdDeactivate","summary":"Create or run companies chart of accounts deactivate","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker. Service-principal access reviewed 2026-09-10 (#1982).","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts/{accountId}/reactivate":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"accountId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdChartOfAccountsAccountIdReactivate","summary":"Create or run companies chart of accounts reactivate","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker. Service-principal access reviewed 2026-09-10 (#1982).","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/chart-of-accounts/{accountId}/identity":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"accountId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"editAccountantGlAccountIdentity","summary":"Change only the code and/or name of an existing GL account, keeping its id (#2883)","description":"The identity-preserving chart edit. It writes ONLY `code`, `name` and `updated_at` on the account, so the id is unchanged and every journal line, bank or integration mapping, QuickBooks account mapping, role and schedule stays attached. It cannot change type, subtype, detail type, report section, description, parent, normal balance, isActive, isLocked, isPostable, provenance or any classification: any other body key is a 422, never an ignored field. It has no posting cutoff, automatic mapping, automatic sync or QuickBooks write side effect, and it creates, deactivates and retires nothing.\n`expected` is the code and name the caller last read; the edit lands only on exactly that row. A request whose target code and name are already on the account replays: 200 with `meta.replayed: true`, no write and no audit record. A successful edit writes one audit record (action `update`, entity `gl_account`, `lifecycleAction: identity_edit`) with the reason, the before and after snapshot, the acting user and, for the service token, its API key id. The edit and its audit record commit in one database transaction: neither lands without the other, so a 500 or 503 means nothing was written and the request can be retried unchanged. A feed-created bank or card account (`source: integration`) is relabelled like any other, since its feed links by id.\nConflicts are reported, never resolved: a code held by another account (active, inactive or retired), an active name held by another active account, a company merchant rule that targets the code being left or taken, or a live QuickBooks create-account write-back item for the account return 409 `GL_ACCOUNT_IDENTITY_CONFLICT` with every conflict in `error.extensions.conflicts`. Nothing is overwritten, swapped, deactivated or retired to make room. Service-principal access reviewed 2026-10-02 (#2883); the full `PATCH .../chart-of-accounts/{accountId}` stays bearer-only.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditGlAccountIdentityInput"}}}},"responses":{"200":{"description":"The account after the edit, or the unchanged account when the request replays","content":{"application/json":{"schema":{"type":"object","required":["success","data","meta"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/GlAccount"},"meta":{"type":"object","required":["replayed"],"properties":{"replayed":{"type":"boolean","description":"True when the account already carried the requested code and name; nothing was written."}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"`GL_ACCOUNT_IDENTITY_CONFLICT`: the target code or name is held or referenced elsewhere; `error.extensions.conflicts` is an array of GlAccountIdentityConflict. `GL_ACCOUNT_IDENTITY_STALE`: the account no longer carries the `expected` code and name; `error.extensions.current` is its `{ code, name }` now. Re-read and retry.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiErrorResponse"},{"type":"object","properties":{"error":{"type":"object","properties":{"extensions":{"type":"object","properties":{"conflicts":{"type":"array","description":"GL_ACCOUNT_IDENTITY_CONFLICT only. Every conflict of the request, in one response.","items":{"$ref":"#/components/schemas/GlAccountIdentityConflict"}},"current":{"type":"object","description":"GL_ACCOUNT_IDENTITY_STALE only. The code and name the account carries now.","required":["code","name"],"properties":{"code":{"type":"string"},"name":{"type":"string"}}}}}}}}}]}}}},"422":{"description":"`Validation error`: the body or a path id failed validation (an unknown key, a missing reason or `expected`, a code that is not 1-7 letters, digits, dots or dashes, a name QuickBooks would rewrite). `GL_ACCOUNT_IDENTITY_PROTECTED`: the route refuses this account or target, with `error.extensions.reason` one of `system_account` (a required system account), `reserved_code` (the account's code or the target code is reserved for a system or Stripe account; `extensions.code`), `seed_template_code` (the account sits on a code Median's default chart seeds, which the next sync would re-create), `seed_template_code_meaning` (the target is a default-chart code and the account is a different type or detail type), `seed_template_name` (the target name is a default-chart name whose code the company does not hold), `engine_pinned_code` (the target is a code posting resolves by code for another account type, or the account is the type posting binds to its current code; `extensions.code` and `extensions.pinnedType`), `classification_change` (a report, cash, revenue, sub-ledger, posting-role or QuickBooks classification would change; `extensions.differences` lists each key with its before and after) or `filing_locked_history` (the account has posted lines in a filing-locked period). Also 422 when `reason` carries a control character or lone surrogate, which the audit record cannot store.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"Service key write rate limit exceeded (the edit counts against the service principal's write budget)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"The accountant assignment could not be re-read before the write. Nothing was written; retry unchanged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/journal-entries/by-source":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdJournalEntriesBySource","summary":"Read companies journal entries by source","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/journal-entries/{id}/source":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdJournalEntriesIdSource","summary":"Read companies journal entries source","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/journal-entries":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"createAccountantCompanyJournalEntry","summary":"Create a balanced journal entry for an assigned customer","description":"Uses the same validation and posting guards as the company journal-entry route. Service principals are admitted as an ordinary audited write; void and date correction remain high-impact operations.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJournalEntryInput"}}}},"responses":{"201":{"description":"Journal entry created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JournalEntryResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"$ref":"#/components/responses/ValidationError"}}},"get":{"operationId":"getAccountantCompaniesCustomerIdJournalEntries","summary":"Read companies journal entries","description":"Posted journal entries for one customer as a keyset-paged list, newest entry date first (#1703). `data` is a bare array; `meta.nextCursor` and `meta.hasMore` drive paging — pass `meta.nextCursor` back as `cursor` until `hasMore` is false.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"dateFrom","in":"query","required":false,"description":"Inclusive journal entry date lower bound. Invalid dates or an inverted range return 422.","schema":{"type":"string","format":"date"}},{"name":"dateTo","in":"query","required":false,"description":"Inclusive journal entry date upper bound. Omit bounds to retain the unfiltered list.","schema":{"type":"string","format":"date"}},{"name":"limit","in":"query","required":false,"description":"Page size. Defaults to and is capped at 500; an out-of-range or non-numeric value falls back to the 500-row default rather than erroring.","schema":{"type":"integer","minimum":1,"maximum":500,"default":500}},{"name":"cursor","in":"query","required":false,"description":"Opaque keyset cursor from the previous page's `meta.nextCursor`. A malformed cursor is rejected with 400 rather than answered as an empty final page.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Restrict the page to one journal status. Omit for every status. A value outside the enum is rejected with 400; it used to be accepted and ignored, which answered a question about voided entries with posted ones.","schema":{"type":"string","enum":["posted","void"]}}],"responses":{"200":{"description":"One page of journal entries","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"nextCursor":{"type":["string","null"]},"hasMore":{"type":"boolean"},"truncated":{"$ref":"#/components/schemas/AccountantScopeTruncated"},"ledgerRevision":{"$ref":"#/components/schemas/LedgerRevision"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/audit-logs":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantListAuditLogs","summary":"List mutation audit rows for one customer","description":"Accountant-scoped read of `audit_logs` for journal entries, business events, GL periods, and explicitly requested reconciliation events. Other entity types are rejected with 422. Newest first. Requires assignment to the customer (403 otherwise). This lists rows that were written; it does not create the missing journal-create trail (#1986).\n","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Page size. Defaults to 50; rejected outside 1-200.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"entityTypes","in":"query","required":false,"description":"Comma-separated subset of `journal_entry`, `business_event`, `gl_period`, `reconciliation`. Default is the first three. Any other value is 422.\n","schema":{"type":"string","maxLength":500}}],"responses":{"200":{"description":"Newest-first audit rows","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogEntry"}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/phi-screen/held-messages":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"accountantGetPhiHeldMessageSummary","summary":"Counts of one customer's mail held by the PHI screen","description":"#1122. For a PHI-bounded customer, how many Gmail messages the PHI screen holds now, by held reason and by the UTC week (Monday) each was received over the last eight weeks, and how many a later sync released. Counts only: held rows store no sender, subject or file name. Any other customer answers `bounded: false`. Requires assignment to the customer (403 otherwise). A failed read of the flag or the rows is 503, never an empty answer.\n","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Held-mail counts","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["bounded","held","released","byReason","byWeek"],"properties":{"bounded":{"type":"boolean","description":"Whether the customer is PHI-bounded now."},"held":{"type":"integer","minimum":0,"description":"Messages held now."},"released":{"type":"integer","minimum":0,"description":"Messages held earlier and released by a later sync."},"byReason":{"type":"array","description":"Messages held now by reason, most first. `not_recorded` for rows written before reasons were stored.","items":{"type":"object","required":["reason","messages"],"properties":{"reason":{"type":"string"},"messages":{"type":"integer","minimum":0}}}},"byWeek":{"type":"array","description":"Messages held now by received week, the last eight weeks, oldest first, zero-filled.","items":{"type":"object","required":["weekStart","messages"],"properties":{"weekStart":{"type":"string","format":"date"},"messages":{"type":"integer","minimum":0}}}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"503":{"$ref":"#/components/responses/ServiceUnavailableJson"}}}},"/accountant/companies/{customerId}/reports":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdReports","summary":"Read companies reports","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BasisQueryParam"},{"name":"type","in":"query","description":"Return one statement of the bundle instead of all of them.","schema":{"type":"string","enum":["profit-and-loss","balance-sheet","cash-flow","trial-balance","ar-aging","ap-aging"]}},{"name":"tagId","in":"query","description":"Accounting tag filter (#1166), P&L only: requires `type=profit-and-loss`. Comma-separated or repeated (max 50); keeps the posted lines owned by a transaction carrying ANY listed tag, each line once, and echoes `profitAndLoss.tagFilter`. Refused with 400 on the full bundle, every other type, with `groupBy=class`, with a consolidated scope, and on the general-ledger routes. `untagged` is refused on reports.\n","schema":{"oneOf":[{"type":"string","format":"uuid"},{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50}]}}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"data":{"$ref":"#/components/schemas/AccountantReportsBundle"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"description":"`basis` is not `accrual` or `cash`. A cash statement that cannot be produced is not a 422 on this route: it is an unavailable statement inside the 200.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/reports/gl-activity":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdReportsGlActivity","summary":"Read companies reports gl activity","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BasisQueryParam"}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"data":{"type":"object","additionalProperties":true,"properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"cashBasisSource":{"$ref":"#/components/schemas/CashBasisLineProvenance"}}}},"ledgerRevision":{"$ref":"#/components/schemas/LedgerRevision"}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"$ref":"#/components/responses/ReportBasisUnprocessable"}}}},"/accountant/companies/{customerId}/reports/general-ledger/{glAccountId}/entries":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"glAccountId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdReportsGeneralLedgerGlAccountIdEntries","summary":"Read companies reports general ledger entries","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/BasisQueryParam"}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"data":{"type":"object","additionalProperties":true,"properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"cashBasisSource":{"$ref":"#/components/schemas/CashBasisLineProvenance"}}}},"ledgerRevision":{"$ref":"#/components/schemas/LedgerRevision"}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"$ref":"#/components/responses/ReportBasisUnprocessable"}}}},"/accountant/companies/{customerId}/transactions/transfer-match":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdTransactionsTransferMatch","summary":"Create or run companies transactions transfer match","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transactions/transfer-match/propose":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdTransactionsTransferMatchPropose","summary":"Create or run companies transactions transfer match propose","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transfer-diagnostics":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdTransferDiagnostics","summary":"Read companies transfer diagnostics","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transactions/transfer-matches/{matchId}/unwind":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"matchId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdTransactionsTransferMatchesMatchIdUnwind","summary":"Create or run companies transactions transfer matches unwind","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transfer-matches":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdTransferMatches","summary":"Read companies transfer matches","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/transfer-matches/bulk-approve":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdTransferMatchesBulkApprove","summary":"Approve and apply a batch of transfer proposals","description":"#2303 reviewed lane. Approves and applies each proposed/approved transfer match through the same writer as the single apply (intra-cash transfer or credit-card payment). Per-item outcomes: `applied`, `skipped` (already applied/rejected, investing activity, a leg consumed by another applied match) or `failed` (the writer's refusal message; the match stays proposed).","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["transferMatchIds"],"properties":{"transferMatchIds":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"string","format":"uuid"}}}}}}},"responses":{"200":{"description":"Per-item bulk outcome summary","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"processed":{"type":"integer"},"skipped":{"type":"integer"},"failed":{"type":"integer"},"results":{"type":"array","items":{"type":"object","required":["matchId","outcome"],"properties":{"matchId":{"type":"string","format":"uuid"},"outcome":{"type":"string","enum":["applied","skipped","failed"]},"consolidatedJeId":{"type":"string"},"reason":{"type":"string"}}}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"422":{"description":"Validation error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}}}},"/accountant/companies/{customerId}/transactions/credit-card-payment-match":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdTransactionsCreditCardPaymentMatch","summary":"Create or run companies transactions credit card payment match","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/close-blockers":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdCloseBlockers","summary":"Read companies close blockers","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/stripe-posting-holds":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdStripePostingHolds","summary":"List Stripe balance transactions held off the ledger by a review-required posting guard","description":"Open holds for the customer, newest refusal first (cap 200): hold code, balance transaction summary, and for a payout overlap the conflicting posted journal entry and its bank transaction. Human accountant only.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope with `items` and `total`","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/stripe-posting-holds/retry":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdStripePostingHoldsRetry","summary":"Re-run the customer's Stripe sync so resolved holds post","description":"Runs the normal idempotent Stripe App sync for the customer. A hold clears when its row posts. The sync completes past a recorded hold, so the result reads the queue afterwards: ok=false with openHolds and the newest hold's guard code while any hold is still open. Human accountant only.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope with ok, synced, failed, openHolds, errorCode and errorMessage (newest open hold), syncErrorCode and syncErrorMessage (a sync failure, kept apart from the holds)","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"503":{"description":"Stripe sync is not configured on this API","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/accountant/companies/{customerId}/contract-schedules/{scheduleId}/apply":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"scheduleId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdContractSchedulesScheduleIdApply","summary":"Create or run companies contract schedules apply","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/business-events/preview":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdBusinessEventsPreview","summary":"Create or run companies business events preview","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/business-events/supported-types":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdBusinessEventsSupportedTypes","summary":"Read companies business events supported types","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/business-events/vendor-bill-candidates":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdBusinessEventsVendorBillCandidates","summary":"List a vendor's open Payables bills that a vendor bill can post","description":"Read-only pick list for the accountant vendor-bill form (#2741). Returns the customer's open Payables bills for the named vendor (case- and whitespace-insensitive name match) in the primary entity's functional currency that have no posting source yet: no journal entry, no source business event and no bill document. Pass a returned id as `parameters.apItemId` on the `vendor_bill` business event to post that bill instead of creating a second one. Void, paid and already-posted bills are never returned.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"parameters":[{"name":"vendor","in":"query","required":true,"description":"Vendor name as typed on the bill form.","schema":{"type":"string","minLength":1,"maxLength":500}}],"responses":{"200":{"description":"Candidate bills, newest bill date first","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["candidates"],"properties":{"candidates":{"type":"array","items":{"type":"object","required":["id","vendor","amountCents","currency","issueDate","dueDate","billNumber"],"properties":{"id":{"type":"string","format":"uuid"},"vendor":{"type":"string"},"amountCents":{"type":"integer","description":"Bill amount in integer minor units."},"currency":{"type":"string","example":"USD"},"issueDate":{"type":"string","format":"date"},"dueDate":{"type":["string","null"],"format":"date"},"billNumber":{"type":["string","null"]}}}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/accountant/companies/{customerId}/event-schedules":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdEventSchedules","summary":"Read companies event schedules","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/event-schedules/{id}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdEventSchedulesId","summary":"Read companies event schedules","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"patch":{"operationId":"patchAccountantCompaniesCustomerIdEventSchedulesId","summary":"Update companies event schedules","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/event-schedules/{id}/void":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdEventSchedulesIdVoid","summary":"Create or run companies event schedules void","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/{id}/items/{itemId}/include":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdReconciliationsIdItemsItemIdInclude2","summary":"Create or run companies reconciliations items include","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/{id}/items/{itemId}/exclude":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdReconciliationsIdItemsItemIdExclude2","summary":"Create or run companies reconciliations items exclude","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/gl-integrity":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdGlIntegrity","summary":"Read companies gl integrity","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdReconciliations","summary":"Create or run companies reconciliations ","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"get":{"operationId":"getAccountantCompaniesCustomerIdReconciliations","summary":"Read companies reconciliations ","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/quick-complete":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"post":{"operationId":"postAccountantCompaniesCustomerIdReconciliationsQuickComplete","summary":"Create or run companies reconciliations quick complete","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/validate-beginning-balance":{"parameters":[{"$ref":"#/components/parameters/customerId"}],"get":{"operationId":"getAccountantCompaniesCustomerIdReconciliationsValidateBeginningBalance","summary":"Read companies reconciliations validate beginning balance","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/{id}":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdReconciliationsId","summary":"Read companies reconciliations","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"patch":{"operationId":"patchAccountantCompaniesCustomerIdReconciliationsId","summary":"Update companies reconciliations","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}},"delete":{"operationId":"deleteAccountantCompaniesCustomerIdReconciliationsId","summary":"Delete companies reconciliations","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/{id}/candidates":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdReconciliationsIdCandidates","summary":"Read companies reconciliations candidates","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/{id}/events":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdReconciliationsIdEvents","summary":"Read companies reconciliations events","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/{id}/report":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdReconciliationsIdReport","summary":"Read companies reconciliations report","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"description":"The report is blocked (#2882). `title` RECONCILIATION_REPORT_INVALID_REFERENCES means a matched book reference is no longer a posted, live entry in the reconciliation's entity; `extensions` carries reconciliationId, reconciliationStatus and invalidReferences[] (matchId, bankTransactionId, bookReference, condition not_found|deleted|void|not_posted|outside_entity, requiredAction rerun_matching|reject_match|reopen_then_rematch). Identifiers only, no amounts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/accountant/companies/{customerId}/reconciliations/{id}/auto-match":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdReconciliationsIdAutoMatch","summary":"Create or run companies reconciliations auto match","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/{id}/matches":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdReconciliationsIdMatches","summary":"Read companies reconciliations matches","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/{id}/matches/{matchId}/confirm":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"matchId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdReconciliationsIdMatchesMatchIdConfirm","summary":"Create or run companies reconciliations matches confirm","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/{id}/matches/{matchId}/reject":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"matchId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdReconciliationsIdMatchesMatchIdReject","summary":"Create or run companies reconciliations matches reject","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/{id}/manual-match":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdReconciliationsIdManualMatch","summary":"Create or run companies reconciliations manual match","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/{id}/unmatched":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getAccountantCompaniesCustomerIdReconciliationsIdUnmatched","summary":"Read companies reconciliations unmatched","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/{id}/unmatched/{itemId}/resolve":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdReconciliationsIdUnmatchedItemIdResolve","summary":"Create or run companies reconciliations unmatched resolve","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}},"/accountant/companies/{customerId}/reconciliations/{id}/complete":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdReconciliationsIdComplete","summary":"Complete a reconciliation against imported rows or a reviewed zero-activity statement","description":"Statement evidence is a human review of stored source bytes. Service principals cannot submit human review evidence. Source identity, account, period, currency, current candidates and posted balance are rechecked before completion.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","maxLength":2000},"forceCompleteReason":{"type":"string","maxLength":2000},"statementEvidence":{"type":"object","additionalProperties":false,"required":["mode","documentId","contentSha256","bankAccountId","currency","periodStart","periodEnd","openingBalanceCents","endingBalanceCents","transactionCount","sourcePageReference","reviewReason"],"properties":{"mode":{"type":"string","enum":["human_reviewed_zero_activity_statement","human_reviewed_statement_activity"],"description":"Zero-activity attests no bank money movements (#1793). Statement-activity attests feed-empty periods whose statement PDF shows activity matching book entries (#2246).\n"},"documentId":{"type":"string","format":"uuid"},"contentSha256":{"type":"string","pattern":"^[a-f0-9]{64}$"},"bankAccountId":{"type":"string","format":"uuid"},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"openingBalanceCents":{"type":"integer"},"endingBalanceCents":{"type":"integer"},"transactionCount":{"type":"integer","minimum":0,"maximum":100000,"description":"0 for zero-activity mode; positive count of statement movements for statement-activity mode.\n"},"sourcePageReference":{"type":"string","minLength":1,"maxLength":200},"reviewReason":{"type":"string","minLength":10,"maxLength":2000}}}}}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"409":{"description":"Source or journal candidates changed before completion"},"422":{"description":"Invalid or contradictory statement evidence"}}}},"/accountant/companies/{customerId}/reconciliations/{id}/reopen":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdReconciliationsIdReopen","summary":"Reopen a completed reconciliation with an audited reason","description":"Unlocks records belonging to this company-scoped reconciliation atomically with its lifecycle audit. Service principals require substantive correction-source evidence and use the high-impact route policy. Unmatch remains human-only.","tags":["Accountant Portal"],"security":[{"bearerAuth":[]},{"serviceApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","minLength":1,"maxLength":2000},"evidence":{"type":"string","minLength":10,"maxLength":2000,"description":"Correction-source reference and explanation; required for service principals."}}}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"422":{"description":"Missing reason or invalid correction evidence"}}}},"/accountant/companies/{customerId}/reconciliations/{id}/unmatch":{"parameters":[{"$ref":"#/components/parameters/customerId"},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"postAccountantCompaniesCustomerIdReconciliationsIdUnmatch","summary":"Create or run companies reconciliations unmatch","description":"Generated minimal contract (#1940): parameters, auth, and status codes are authoritative; see the route handler for the exact body/response shape. Enrichment tracked by the x-median-spec-stage marker.","x-median-spec-stage":"generated-1940","tags":["Accountant Portal"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Success envelope; see the route handler for the payload shape","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"403":{"$ref":"#/components/responses/ForbiddenJson"},"404":{"$ref":"#/components/responses/NotFoundJson"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"},"serviceApiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Persistent credential for the configured cloud-bookkeeping service principal. The key must carry accountant:* and is accepted only on accountant operations that explicitly list this scheme. Ordinary API keys, and service keys presented to bearer-only operations, are denied.\n"},"refreshSessionCookie":{"type":"apiKey","in":"cookie","name":"__Secure-median_refresh","description":"Exact production HttpOnly refresh-session cookie. Local non-secure development uses median_refresh.\n"},"passkeyEnrollmentGrantCookie":{"type":"apiKey","in":"cookie","name":"__Secure-median_passkey_enrollment","description":"Exact production HttpOnly passkey-enrollment grant cookie. Local non-secure development uses median_passkey_enrollment.\n"},"webAuthnCeremonyCookie":{"type":"apiKey","in":"cookie","name":"__Secure-median_webauthn","description":"Exact production HttpOnly WebAuthn ceremony cookie. Local non-secure development uses median_webauthn.\n"}},"parameters":{"companyId":{"name":"companyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"demoParityCustomerAppSurface":{"name":"X-Median-App-Surface","in":"header","required":false,"description":"Optional customer-app bundle marker for production-promoted demo-parity routes. Production customer calls omit this header. When present, qa selects the QA bundle and the server additionally requires an allowlisted test company with persisted client_status=test.\n","schema":{"type":"string","const":"qa"}},"qaAppSurface":{"name":"X-Median-App-Surface","in":"header","required":true,"description":"Customer-app QA bundle marker. This is necessary but not sufficient; the server also requires a JWT-authenticated member, an allowlisted company id, and persisted client_status=test.\n","schema":{"type":"string","const":"qa"}},"onboardingV3QaSurface":{"name":"X-Median-App-Surface","in":"header","required":false,"description":"Bundle marker selecting the temporary /qa onboarding surface. Optional on this promoted deployment (ONBOARDING_V3_QA_ONLY=false): unmarked requests are served, and a qa value is accepted and ignored. Still required on any deployment running ONBOARDING_V3_QA_ONLY=true, where an unmarked request receives the hidden-resource 404. On neither setting is it a tenant authorization credential.\n","schema":{"type":"string","const":"qa"}},"modelAIntercompanyGlPeriodId":{"name":"glPeriodId","in":"query","required":true,"description":"Exact closed GL period used for review and rollforward authority.","schema":{"type":"string","format":"uuid"}},"fxAccountingRole":{"name":"role","in":"path","required":true,"schema":{"type":"string","enum":["TRANSFER_CLEARING","REALIZED_FX_GAIN_LOSS","UNREALIZED_FX_GAIN_LOSS"]}},"customerId":{"name":"customerId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"transactionId":{"name":"transactionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"documentId":{"name":"documentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"matchId":{"name":"matchId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"jobId":{"name":"jobId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"resourceId":{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"threadId":{"name":"threadId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"limit":{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},"integrationId":{"name":"integrationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"accountId":{"name":"accountId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"cursor":{"name":"cursor","in":"query","schema":{"type":"string"}},"reportStartDate":{"name":"startDate","in":"query","description":"Inclusive period start (YYYY-MM-DD). Must be supplied together with `endDate`.","schema":{"type":"string","format":"date"}},"reportEndDate":{"name":"endDate","in":"query","description":"Inclusive period end (YYYY-MM-DD). Must be supplied together with `startDate`.","schema":{"type":"string","format":"date"}},"reportComparePeriod":{"name":"comparePeriod","in":"query","description":"Comparison mode. `prior-period` shifts back by the range length (snapped to full calendar months when the range is month-aligned). `prior-year` shifts both dates back 12 months. `none` (default) returns no comparison.\n","schema":{"type":"string","enum":["none","prior-period","prior-year"],"default":"none"}},"reportGranularity":{"name":"granularity","in":"query","description":"Override inferred granularity. Advisory; the service still validates the actual range.","schema":{"type":"string","enum":["month","quarter","year"]}},"reportClassId":{"name":"classId","in":"query","description":"Optional class filter for class-aware report endpoints. Pass a company-scoped accounting class UUID, or `unassigned` for journal lines with no class. Customer-facing use returns data only for active approved company classes.\n","schema":{"type":"string"}},"reportGroupBy":{"name":"groupBy","in":"query","description":"Add a grouped class breakdown where supported.","schema":{"type":"string","enum":["class"]}},"reportAllTime":{"name":"allTime","in":"query","description":"`true` reports from the first through the last posted month on the P&L and cash flow, where omitting `startDate`/`endDate` still returns only the latest posted month, so \"all time\" must be requested by name. The general ledger reads an omitted range as the whole ledger either way. Cannot be combined with `startDate`/`endDate`, `month` or a `comparePeriod` other than `none` (400).\n","schema":{"type":"string","enum":["true"]}},"BasisQueryParam":{"name":"basis","in":"query","required":false,"description":"Basis the statements are calculated on (#2911). Omitted or `accrual`: the accrual calculation, unchanged. `cash`: a cash-basis view built at read time from the posted ledger under recognition policy `cash-basis-v1`; nothing is written to the ledger. The company's configured basis (`configuredBasis`) never selects this; only this parameter does. A cash statement is returned only when it can be proven: otherwise it is refused with `CASH_BASIS_UNAVAILABLE` and its reasons, and accrual figures are never returned in its place. Until the policy's review is recorded, every `cash` request is refused with reason `policy_unreviewed`. Accepted on the accountant reports bundle and the accountant general-ledger drill-downs only; no customer route takes it. Any other value is a 422.\n","schema":{"type":"string","enum":["accrual","cash"],"default":"accrual"}},"reportEntityId":{"name":"entityId","in":"query","description":"Concrete legal entity to read. Mutually exclusive with `reportingScopeId`/`scopeAsOf`. Omission is accepted only when the actor is authorized to exactly one concrete entity.\n","schema":{"type":"string","format":"uuid"}},"homeEntityId":{"name":"entityId","in":"query","description":"Concrete legal entity to read on Home. Omission is accepted only when the actor is authorized to exactly one concrete entity. Consolidated or group scope is not silently collapsed to an arbitrary entity.\n","schema":{"type":"string","format":"uuid"}},"homeOptionalEntityId":{"name":"entityId","in":"query","description":"Optional concrete legal-entity scope for entity-scopable Home reads. Omitted means company-wide; when present it must be a legal entity the actor is authorized to read (the raw value is never trusted).\n","schema":{"type":"string","format":"uuid"}},"financialEntityId":{"name":"entityId","in":"query","description":"Concrete legal entity that owns this AR/AP request. Omission is accepted only when the actor is authorized to exactly one concrete entity; consolidated scope cannot mutate or serve these entity-only resources.\n","schema":{"type":"string","format":"uuid"}},"intelligenceEntityId":{"name":"entityId","in":"query","description":"Concrete authorized legal entity for Intelligence metrics, briefs, and Ask history. Omission is accepted only when the actor is authorized to exactly one concrete entity; consolidated scope is not supported.\n","schema":{"type":"string","format":"uuid"}},"reportReportingScopeId":{"name":"reportingScopeId","in":"query","description":"Immutable within-company consolidated reporting-scope identity. Must be supplied with `scopeAsOf` and cannot be combined with `entityId`.\n","schema":{"type":"string","format":"uuid"}},"reportScopeAsOf":{"name":"scopeAsOf","in":"query","description":"ISO date used to pin the effective sealed reporting-scope hierarchy version. Must be supplied with `reportingScopeId`.\n","schema":{"type":"string","format":"date"}}},"responses":{"ReportBasisUnprocessable":{"description":"`basis` is not `accrual` or `cash` (a validation error naming the field), or `basis=cash` was asked and the cash-basis view cannot be produced for this request (`CASH_BASIS_UNAVAILABLE`, with the reasons at `error.extensions.cashBasis`). No rows are returned in either case. Other business-rule refusals of the read use the same envelope.\n","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CashBasisUnavailable"},{"$ref":"#/components/schemas/ApiErrorResponse"}]}}}},"StripeGlAccountRebindRequired":{"description":"The Stage-A Stripe GL compatibility guard refused the call (STRIPE_GL_ACCOUNT_REBIND_REQUIRED). No connection, account, or journal entry was changed. `extensions.accountCodes` lists the codes an accountant must review and rebind; `extensions.adoptableCodes` lists codes that conform on accounting shape and self-heal on the next sync.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"ConflictJson":{"description":"Request conflicts with the durable onboarding state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"ServiceUnavailableJson":{"description":"Required sandbox provider configuration or service is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"InboundEmailBadRequest":{"description":"The signed multipart body, envelope, message headers, recipient, or attachment metadata is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"InboundEmailUnauthorized":{"description":"The provider signature headers are missing, invalid, or stale","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"InboundEmailNotFound":{"description":"The gated route or exact allowlisted company alias is not available","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"InboundEmailPayloadTooLarge":{"description":"The raw body, a field, an attachment, or the multipart field, file, or part count exceeds its configured limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"InboundEmailUnsupportedMedia":{"description":"The body is not raw multipart/form-data or uses a non-identity content encoding","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"InboundEmailUnprocessableEntity":{"description":"An attachment was rejected after malware scanning","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"InboundEmailServiceUnavailable":{"description":"Inbound intake is temporarily at its bounded concurrency capacity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"OnboardingV3InvalidJson":{"description":"Onboarding request body is not valid JSON","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"OnboardingV3UnsupportedBodyEncoding":{"description":"Onboarding request charset or content encoding is unsupported","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"OnboardingV3PricingPayloadTooLarge":{"description":"Onboarding pricing request exceeds the 4096-byte route limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"OnboardingV3SetupPayloadTooLarge":{"description":"Onboarding setup request exceeds the 32768-byte route limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"PasswordlessInvalidJson":{"description":"Request body is not valid JSON","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"PasswordlessUnsupportedBodyEncoding":{"description":"Request body charset or content encoding is unsupported","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"OnboardingV3Hidden":{"description":"Onboarding v3 is disabled; the route is hidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"PasswordlessUnauthorized":{"description":"The credential or one-shot ceremony is invalid, expired, or already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"PasswordlessRecaptchaForbidden":{"description":"reCAPTCHA verification is required, unavailable, or failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"ValidationProblem":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"PasswordlessRateLimited":{"description":"Retry after the indicated number of seconds","headers":{"Retry-After":{"schema":{"type":"integer","minimum":0},"description":"Whole seconds until retry is allowed"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"PasswordlessPayloadTooLarge":{"description":"Request body exceeds the passwordless route limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"Unauthorized":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"Forbidden":{"description":"Insufficient permissions or not a company member","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"NotFound":{"description":"Resource not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"UnprocessableEntity":{"description":"Validation error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"UnauthorizedJson":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"ForbiddenJson":{"description":"Insufficient permissions or not a company member","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"NotFoundJson":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"CreditNotesUnavailable":{"description":"Durable Model A credit-note persistence is not available. The request creates no credit note, journal entry, reversal, or balance change.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"},"example":{"success":false,"error":{"title":"Service Unavailable","status":503,"detail":"Durable credit-note persistence is unavailable; no credit note or accounting entry was created."}}}}},"BadRequest":{"description":"Request failed validation","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}},"ValidationError":{"description":"Request failed validation","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"}}}}},"schemas":{"UnlinkedAccountantEntries":{"type":"object","description":"#1417: posted accountant invoice, bill or payment entries (business-event journal entries on the receivables or payables side of the conversion ownership map) that have no AR/AP item linked to the entry or its event. They are in the general ledger but not in this aging. Present only when the company reads AR/AP from the items tables; absent otherwise. `count` is exact; `items` is capped at 50, newest first.\n","required":["count","items"],"properties":{"count":{"type":"integer","minimum":0},"items":{"type":"array","maxItems":50,"items":{"$ref":"#/components/schemas/UnlinkedAccountantEntry"}}}},"UnlinkedAccountantEntry":{"type":"object","required":["journalEntryId","entryDate","eventType","amountCents","currency"],"properties":{"journalEntryId":{"type":"string","format":"uuid"},"entryDate":{"type":"string","format":"date"},"eventType":{"type":"string","description":"Stored business-event type, e.g. vendor_bill"},"amountCents":{"type":["integer","null"],"description":"Total debits in minor units; null when the entry has no single-currency lines."},"currency":{"type":["string","null"]}}},"QuickBooksSourceStatus":{"type":"object","required":["connectionId","sourceRunId","state","latestAttemptAt","lastSuccessfulSourceReadAt","objectsSeen","byType","glPostingState","errorCode"],"properties":{"connectionId":{"type":"string","format":"uuid"},"sourceRunId":{"type":["string","null"],"format":"uuid"},"state":{"type":"string","enum":["disabled","connected_no_import","importing","source_ready","failed","stale"]},"latestAttemptAt":{"type":["string","null"],"format":"date-time"},"lastSuccessfulSourceReadAt":{"type":["string","null"],"format":"date-time"},"objectsSeen":{"type":"integer","minimum":0},"byType":{"type":"object","additionalProperties":{"type":"integer","minimum":0}},"glPostingState":{"type":"string","enum":["pending_mapping_and_reconciliation"]},"errorCode":{"type":["string","null"]}}},"QuickBooksCustomerStatus":{"type":"object","additionalProperties":false,"required":["readState","lastSuccessfulReadAt","latestAttemptAt","readFailure","coverage","booksState","gaps"],"properties":{"readState":{"type":"string","enum":["disabled","connected_no_import","importing","source_ready","failed","stale"]},"lastSuccessfulReadAt":{"type":["string","null"],"format":"date-time"},"latestAttemptAt":{"type":["string","null"],"format":"date-time"},"readFailure":{"oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"required":["code","reason"],"properties":{"code":{"type":"string"},"reason":{"type":"string","description":"Plain-language reason shown to the customer"}}}]},"coverage":{"type":"object","additionalProperties":false,"required":["byType","bankAndCardAccounts","bankFeedReviewQueue"],"properties":{"byType":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["objectType","count","earliestTxnDate","latestTxnDate"],"properties":{"objectType":{"type":"string","enum":["Account","JournalEntry","Purchase","Deposit","Transfer","Payment","BillPayment","Bill","Invoice","SalesReceipt","CreditMemo","RefundReceipt","VendorCredit","Item","TaxCode","TaxRate","TaxAgency"]},"count":{"type":"integer","minimum":0},"earliestTxnDate":{"type":["string","null"],"format":"date"},"latestTxnDate":{"type":["string","null"],"format":"date"}}}},"bankAndCardAccounts":{"type":"integer","minimum":0,"description":"QuickBooks Bank and Credit Card accounts read"},"bankFeedReviewQueue":{"type":"object","additionalProperties":false,"required":["available","note"],"properties":{"available":{"type":"boolean","enum":[false]},"note":{"type":"string"}}}}},"booksState":{"type":"object","additionalProperties":false,"required":["state","cutoffDate","postedThrough","pendingBatches","openChangeReviews"],"properties":{"state":{"type":"string","enum":["not_started","held_for_review","posted_through"],"description":"not_started - no posting cutoff; held_for_review - a batch awaits the accountant, a change review is open, items are blocked, or nothing is posted yet; posted_through - the latest posted batch's end date with nothing held."},"cutoffDate":{"type":["string","null"],"format":"date"},"postedThrough":{"type":["string","null"],"format":"date"},"pendingBatches":{"type":"integer","minimum":0},"openChangeReviews":{"type":"integer","minimum":0}}},"gaps":{"type":"object","additionalProperties":false,"required":["blockedItems","byCode"],"properties":{"blockedItems":{"type":"integer","minimum":0},"byCode":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["code","label","count"],"properties":{"code":{"type":"string"},"label":{"type":"string"},"count":{"type":"integer","minimum":0}}}}}}}},"QuickBooksManifestInput":{"type":"object","additionalProperties":false,"required":["manifestSha256"],"properties":{"manifestSha256":{"type":"string","pattern":"^[a-f0-9]{64}$"}}},"QuickBooksTrialBalanceSnapshot":{"type":"object","required":["id","asOfDate","reportBasis","payloadSha256","fetchedByUserId","fetchedAt","currency","totalDebitCents","totalCreditCents","balanced","rows"],"properties":{"id":{"type":"string","format":"uuid"},"asOfDate":{"type":"string","format":"date"},"reportBasis":{"type":"string","enum":["Accrual","Cash"]},"payloadSha256":{"type":"string"},"fetchedByUserId":{"type":["string","null"],"format":"uuid"},"fetchedAt":{"type":"string","format":"date-time"},"currency":{"type":"string"},"totalDebitCents":{"type":"integer"},"totalCreditCents":{"type":"integer"},"balanced":{"type":"boolean"},"rows":{"type":"array","items":{"type":"object","required":["qboAccountId","name","netCents"],"properties":{"qboAccountId":{"type":["string","null"]},"name":{"type":"string"},"netCents":{"type":"integer","description":"Debit minus credit in integer cents"}}}}}},"QuickBooksParityLine":{"type":"object","required":["section","kind","glAccountId","glAccountCode","glAccountName","normalBalance","qboAccounts","qboNetCents","medianNetCents","differenceCents","matches"],"properties":{"section":{"type":"string","enum":["balance_sheet","profit_and_loss"]},"kind":{"type":"string","enum":["mapped","retained_earnings","unmapped_with_balance","median_only_balance"],"description":"`retained_earnings` compares Retained Earnings plus every income/expense account on each side (QuickBooks keeps the fiscal year on the P&L rows; Median's opening rolled pre-cutoff P&L into Retained Earnings). `unmapped_with_balance`: a QuickBooks account with a balance and no Median mapping. `median_only_balance`: a Median account with a balance and no QuickBooks counterpart."},"glAccountId":{"type":["string","null"],"format":"uuid"},"glAccountCode":{"type":["string","null"]},"glAccountName":{"type":["string","null"]},"normalBalance":{"type":"string","enum":["debit","credit"],"description":"Display hint only; amounts are debit minus credit"},"qboAccounts":{"type":"array","description":"QuickBooks accounts compared in aggregate on this line (several may map to one Median account).","items":{"type":"object","required":["qboAccountId","name","netCents"],"properties":{"qboAccountId":{"type":["string","null"]},"name":{"type":"string"},"netCents":{"type":"integer","description":"Debit minus credit in integer cents"}}}},"qboNetCents":{"type":"integer","description":"Debit minus credit in integer cents"},"medianNetCents":{"type":"integer","description":"Debit minus credit in integer cents"},"differenceCents":{"type":"integer","description":"medianNetCents minus qboNetCents"},"matches":{"type":"boolean"}}},"QuickBooksParityResult":{"type":"object","required":["status","asOfDate","cutoffDate","toleranceCents","counts","balanceSheet","profitAndLoss","clearingAccounts","checkId","trigger","checkedAt"],"properties":{"status":{"type":"string","enum":["matches","differs","not_applicable"],"description":"`not_applicable` when asOfDate is before the posting cutoff (nothing is read or stored)."},"asOfDate":{"type":"string","format":"date"},"cutoffDate":{"type":"string","format":"date"},"toleranceCents":{"type":"integer","enum":[0]},"counts":{"type":"object","required":["compared","differing","unmappedWithBalance","medianOnlyBalance"],"properties":{"compared":{"type":"integer","minimum":0},"differing":{"type":"integer","minimum":0},"unmappedWithBalance":{"type":"integer","minimum":0},"medianOnlyBalance":{"type":"integer","minimum":0}}},"balanceSheet":{"type":"array","description":"QuickBooks TrialBalance as of asOfDate against Median's ending balances.","items":{"$ref":"#/components/schemas/QuickBooksParityLine"}},"profitAndLoss":{"type":"array","description":"QuickBooks ProfitAndLoss for cutoffDate..asOfDate against Median's period activity.","items":{"$ref":"#/components/schemas/QuickBooksParityLine"}},"clearingAccounts":{"type":"array","description":"Median-internal clearing accounts (1050, 1080, 4999), listed beside the lines.","items":{"type":"object","required":["glAccountId","code","name","endingNetCents","periodNetCents"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"code":{"type":"string"},"name":{"type":"string"},"endingNetCents":{"type":"integer"},"periodNetCents":{"type":"integer"}}}},"outstanding":{"type":"object","description":"#2642: QuickBooks objects dated on/after the cutoff that automatic posting could not post (blocked, failed, or changed and awaiting review), by code. Absent on checks stored before automatic posting.","required":["count","byCode"],"properties":{"count":{"type":"integer","minimum":0},"byCode":{"type":"object","additionalProperties":{"type":"integer","minimum":0}}}},"checkId":{"type":["string","null"],"format":"uuid"},"trigger":{"type":["string","null"],"enum":["daily","on_demand",null]},"checkedAt":{"type":["string","null"],"format":"date-time"}}},"QuickBooksParitySummary":{"type":"object","description":"Latest parity check shown beside import-batch review. Information only; approval never depends on it.","required":["status","asOfDate","differing","checkedAt"],"properties":{"status":{"type":"string","enum":["matches","differs"]},"asOfDate":{"type":"string","format":"date"},"differing":{"type":"integer","minimum":0},"checkedAt":{"type":"string","format":"date-time"},"outstanding":{"type":"integer","minimum":0,"description":"QuickBooks objects automatic posting could not post yet; absent when unknown."}}},"QuickBooksImportBatch":{"type":"object","required":["id","companyId","entityId","connectionId","realmId","kind","cutoffId","sourceRunId","trialBalanceSnapshotId","trueUpOfBatchId","dateFrom","dateTo","status","manifestSha256","preparedByUserId","approvedByUserId","approvedAt","postedByUserId","postedAt","cancelledByUserId","cancelledAt","errorCode","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"connectionId":{"type":"string","format":"uuid"},"realmId":{"type":"string"},"kind":{"type":"string","enum":["opening_balance","activity"]},"cutoffId":{"type":"string","format":"uuid"},"sourceRunId":{"type":["string","null"],"format":"uuid"},"trialBalanceSnapshotId":{"type":["string","null"],"format":"uuid"},"trueUpOfBatchId":{"type":["string","null"],"format":"uuid"},"dateFrom":{"type":"string","format":"date"},"dateTo":{"type":"string","format":"date"},"status":{"type":"string","enum":["draft","approved","posting","posted","failed","cancelled"]},"manifestSha256":{"type":["string","null"]},"preparedByUserId":{"type":"string","format":"uuid"},"approvedByUserId":{"type":["string","null"],"format":"uuid"},"approvedAt":{"type":["string","null"],"format":"date-time"},"postedByUserId":{"type":["string","null"],"format":"uuid"},"postedAt":{"type":["string","null"],"format":"date-time"},"cancelledByUserId":{"type":["string","null"],"format":"uuid"},"cancelledAt":{"type":["string","null"],"format":"date-time"},"errorCode":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"QuickBooksImportItem":{"type":"object","required":["id","batchId","objectType","providerId","txnDate","totalCents","currency","decision","blockCode","duplicateTransactionId","duplicateJournalEntryId","applyQboCategory","result","journalEntryId","transactionId","errorCode"],"properties":{"id":{"type":"string","format":"uuid"},"batchId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"objectType":{"type":"string"},"providerId":{"type":"string"},"sourceObjectId":{"type":["string","null"],"format":"uuid"},"payloadSha256":{"type":"string"},"economicSha256":{"type":"string"},"txnDate":{"type":"string","format":"date"},"totalCents":{"type":"integer"},"currency":{"type":"string"},"decision":{"type":"string","enum":["post","duplicate","skip","blocked"]},"blockCode":{"type":["string","null"]},"duplicateTransactionId":{"type":["string","null"],"format":"uuid"},"duplicateJournalEntryId":{"type":["string","null"],"format":"uuid"},"applyQboCategory":{"type":"boolean"},"decidedByUserId":{"type":["string","null"],"format":"uuid"},"decidedAt":{"type":["string","null"],"format":"date-time"},"result":{"type":["string","null"],"enum":["posted","replayed","linked","skipped","failed",null]},"journalEntryId":{"type":["string","null"],"format":"uuid"},"transactionId":{"type":["string","null"],"format":"uuid"},"arItemId":{"type":["string","null"],"format":"uuid"},"apItemId":{"type":["string","null"],"format":"uuid"},"errorCode":{"type":["string","null"]}}},"QuickBooksChangeReview":{"type":"object","required":["id","companyId","entityId","realmId","linkId","objectType","providerId","changeKind","beforeSourceObjectId","beforeEconomicSha256","afterSourceObjectId","afterEconomicSha256","detectedRunId","lastDetectedRunId","status","resolutionReason","resolvedByUserId","resolvedAt","followupStatus","followupReason","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"realmId":{"type":"string"},"linkId":{"type":"string","format":"uuid"},"objectType":{"type":"string"},"providerId":{"type":"string"},"changeKind":{"type":"string","enum":["changed","deleted"]},"beforeSourceObjectId":{"type":["string","null"],"format":"uuid"},"beforeEconomicSha256":{"type":"string"},"afterSourceObjectId":{"type":["string","null"],"format":"uuid"},"afterEconomicSha256":{"type":["string","null"]},"detectedRunId":{"type":"string","format":"uuid"},"lastDetectedRunId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["open","resolved_take_qbo","resolved_keep_median","dismissed"]},"resolutionReason":{"type":["string","null"]},"resolvedByUserId":{"type":["string","null"],"format":"uuid"},"resolvedAt":{"type":["string","null"],"format":"date-time"},"followupStatus":{"type":"string","enum":["none","reversal_pending","reversed","writeback_pending","writeback_requested"]},"followupReason":{"type":["string","null"],"enum":["client_must_correct_quickbooks","writeback_not_possible",null],"description":"Why a keep_median restore stays writeback_pending. client_must_correct_quickbooks — QuickBooks changed an amount, date, bank/card line, counterparty or other field post-back never writes, or deleted the object. writeback_not_possible — only account/class/memo changed but the write-back rules refused the correction. writeback_requested means a draft write-back batch was prepared; it still needs approval and posting."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"QuickBooksChangeReviewSummary":{"allOf":[{"$ref":"#/components/schemas/QuickBooksChangeReview"},{"type":"object","required":["before","after"],"properties":{"before":{"type":"object","required":["txnDate","totalAmt"],"properties":{"txnDate":{"type":["string","null"]},"totalAmt":{"type":["string","null"]}}},"after":{"type":"object","required":["txnDate","totalAmt"],"properties":{"txnDate":{"type":["string","null"]},"totalAmt":{"type":["string","null"]}}}}}]},"QuickBooksChangeReviewDetail":{"allOf":[{"$ref":"#/components/schemas/QuickBooksChangeReview"},{"type":"object","required":["link","diff"],"properties":{"link":{"type":"object","required":["direction","active","journalEntryId","transactionId","arItemId","apItemId"],"properties":{"direction":{"type":"string","enum":["pull","push"]},"active":{"type":"boolean"},"journalEntryId":{"type":["string","null"],"format":"uuid"},"transactionId":{"type":["string","null"],"format":"uuid"},"arItemId":{"type":["string","null"],"format":"uuid"},"apItemId":{"type":["string","null"],"format":"uuid"}}},"diff":{"type":"array","items":{"type":"object","required":["path","category","before","after"],"properties":{"path":{"type":"string"},"category":{"type":"string","enum":["date","amount","account","counterparty","currency","other"]},"before":{"type":["string","number","boolean","null"]},"after":{"type":["string","number","boolean","null"]},"beforeName":{"type":["string","null"]},"afterName":{"type":["string","null"]}}}}}}]},"QuickBooksWritebackBlock":{"type":"object","required":["code","detail"],"properties":{"code":{"type":"string"},"detail":{"type":"string"}}},"QuickBooksWritebackManifestInput":{"type":"object","additionalProperties":false,"required":["manifestSha256"],"properties":{"manifestSha256":{"type":"string","pattern":"^[a-f0-9]{64}$"}}},"QuickBooksWritebackBatch":{"type":"object","required":["id","companyId","entityId","connectionId","realmId","cutoffId","dateFrom","dateTo","status","manifestSha256","preparedByUserId","preparedAt","approvedByUserId","approvedAt","postedByUserId","postingStartedAt","postedAt","cancelledByUserId","cancelledAt","errorCode"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"connectionId":{"type":"string","format":"uuid"},"realmId":{"type":"string"},"cutoffId":{"type":"string","format":"uuid"},"dateFrom":{"type":["string","null"],"format":"date"},"dateTo":{"type":["string","null"],"format":"date"},"status":{"type":"string","enum":["draft","approved","posting","posted","failed","cancelled"]},"manifestSha256":{"type":"string","pattern":"^[a-f0-9]{64}$"},"preparedByUserId":{"type":"string","format":"uuid"},"preparedAt":{"type":"string","format":"date-time"},"approvedByUserId":{"type":["string","null"],"format":"uuid"},"approvedAt":{"type":["string","null"],"format":"date-time"},"postedByUserId":{"type":["string","null"],"format":"uuid"},"postingStartedAt":{"type":["string","null"],"format":"date-time"},"postedAt":{"type":["string","null"],"format":"date-time"},"cancelledByUserId":{"type":["string","null"],"format":"uuid"},"cancelledAt":{"type":["string","null"],"format":"date-time"},"errorCode":{"type":["string","null"]}}},"QuickBooksWritebackItem":{"type":"object","required":["id","batchId","kind","journalEntryId","linkId","glAccountId","transactionId","requestId","requestSha256","payload","expected","status","blockCode","qboObjectType","qboId","qboSyncToken","readbackSha256","pushLinkId","attempts","lastErrorCode"],"properties":{"id":{"type":"string","format":"uuid"},"batchId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["create_journal_entry","sparse_update","create_account","create_transaction","delete_transaction"],"description":"create_transaction and delete_transaction are the automatic bank-feed push (#2642 phase 2)"},"journalEntryId":{"type":["string","null"],"format":"uuid"},"linkId":{"type":["string","null"],"format":"uuid"},"glAccountId":{"type":["string","null"],"format":"uuid","description":"The Median GL account a create_account (chart push) item creates, maps or skips; null for other kinds"},"transactionId":{"type":["string","null"],"format":"uuid","description":"The native bank-feed transaction a bank-feed push item (create_transaction, delete_transaction, or a sparse_update of a pushed object) concerns; null otherwise"},"requestId":{"type":"string","format":"uuid","description":"Intuit requestid idempotency key"},"requestSha256":{"type":"string","pattern":"^[a-f0-9]{64}$"},"payload":{"type":"object","additionalProperties":true,"description":"The exact QuickBooks request body (amounts as decimal strings; sent as JSON numbers)"},"expected":{"type":"object","additionalProperties":true,"description":"What the read-back must show (or the block reasons of a blocked item)"},"status":{"type":"string","enum":["pending","approved","sending","sent","verified","failed","blocked","cancelled"]},"blockCode":{"type":["string","null"]},"qboObjectType":{"type":"string","enum":["JournalEntry","Purchase","Deposit","Account"]},"qboId":{"type":["string","null"]},"qboSyncToken":{"type":["string","null"]},"readbackSha256":{"type":["string","null"]},"pushLinkId":{"type":["string","null"],"format":"uuid"},"attempts":{"type":"integer","minimum":0},"lastErrorCode":{"type":["string","null"]},"preparedByUserId":{"type":"string","format":"uuid"},"preparedAt":{"type":"string","format":"date-time"},"approvedByUserId":{"type":["string","null"],"format":"uuid"},"approvedAt":{"type":["string","null"],"format":"date-time"},"sentAt":{"type":["string","null"],"format":"date-time"},"verifiedAt":{"type":["string","null"],"format":"date-time"}}},"QuickBooksChartPushPreview":{"type":"object","required":["state","cutoffDate","sourceRunId","unverifiedInventory","transactionCount","transactions","entries"],"properties":{"state":{"type":"string","enum":["new","established","unclassified","inventory_unverified","no_inventory"]},"cutoffDate":{"type":["string","null"],"format":"date","description":"The posting cutoff; null before one is set (#2883)"},"sourceRunId":{"type":["string","null"],"format":"uuid","description":"The latest completed QuickBooks read the state is judged from"},"unverifiedInventory":{"type":"array","description":"The failed prerequisite of `inventory_unverified` (#2883), one item per transaction type whose census does not match the rows the read stored. Empty in every other state.","items":{"type":"object","required":["objectType","reason","expectedCount","storedCount"],"properties":{"objectType":{"type":"string","enum":["JournalEntry","Purchase","Deposit","Transfer","SalesReceipt","RefundReceipt","Invoice","Bill","Payment","BillPayment","CreditMemo","VendorCredit"]},"reason":{"type":"string","enum":["census_missing","count_mismatch"],"description":"`census_missing`: the read recorded no QuickBooks count for the type; `count_mismatch`: it stored a different number of rows"},"expectedCount":{"type":["integer","null"],"minimum":0,"description":"QuickBooks' count of the type during the read; null when missing"},"storedCount":{"type":"integer","minimum":0}}}},"transactionCount":{"type":"integer","minimum":0,"description":"Every QuickBooks transaction Median has read (latest completed read plus newer read attempts)"},"transactions":{"type":"array","maxItems":50,"description":"Those transactions, undated first and then by date, capped at 50. The warning list of an `unclassified` file (#2883).","items":{"type":"object","required":["objectType","txnDate","amountCents","currency"],"properties":{"objectType":{"type":"string","enum":["JournalEntry","Purchase","Deposit","Transfer","SalesReceipt","RefundReceipt","Invoice","Bill","Payment","BillPayment","CreditMemo","VendorCredit"]},"txnDate":{"type":["string","null"],"format":"date","description":"QuickBooks TxnDate; null when the object has none"},"amountCents":{"type":["integer","null"],"description":"QuickBooks TotalAmt (Amount for a transfer) in integer minor units of `currency`; null when absent or not exactly representable"},"currency":{"type":["string","null"],"description":"The object's CurrencyRef, or the entity's functional currency when QuickBooks omits it"}}}},"entries":{"type":"array","items":{"type":"object","required":["glAccountId","code","name","action","reason","detail","qboAccountId","sourceObjectId","accountType","accountSubType","parentGlAccountId","parentQboAccountId","depth"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"code":{"type":"string"},"name":{"type":"string"},"action":{"type":"string","enum":["create","map","skip"]},"reason":{"type":"string"},"detail":{"type":"string"},"qboAccountId":{"type":["string","null"],"description":"The QuickBooks account a map entry maps to"},"sourceObjectId":{"type":["string","null"],"format":"uuid"},"accountType":{"type":"string","description":"QuickBooks AccountType Median would create it with"},"accountSubType":{"type":"string"},"parentGlAccountId":{"type":["string","null"],"format":"uuid","description":"Parent created by the same chart push"},"parentQboAccountId":{"type":["string","null"],"description":"Parent already in QuickBooks"},"depth":{"type":"integer","minimum":0}}}}}},"QuickBooksWritebackBatchDetail":{"type":"object","required":["batch","items"],"properties":{"batch":{"$ref":"#/components/schemas/QuickBooksWritebackBatch"},"items":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksWritebackItem"}}}},"QuickBooksPostingCutoff":{"type":"object","required":["id","companyId","entityId","connectionId","realmId","cutoffDate","reason","setByUserId","supersedesId","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"connectionId":{"type":"string","format":"uuid"},"realmId":{"type":"string"},"cutoffDate":{"type":"string","format":"date"},"reason":{"type":"string"},"setByUserId":{"type":"string","format":"uuid"},"supersedesId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"}}},"QuickBooksAccountMapping":{"type":"object","required":["id","companyId","entityId","connectionId","realmId","qboAccountId","sourceObjectId","glAccountId","cashSource","approvedByUserId","supersedesId","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"connectionId":{"type":"string","format":"uuid"},"realmId":{"type":"string"},"qboAccountId":{"type":"string"},"sourceObjectId":{"type":"string","format":"uuid"},"glAccountId":{"type":"string","format":"uuid"},"cashSource":{"type":"string","enum":["quickbooks","median"]},"approvedByUserId":{"type":"string","format":"uuid"},"supersedesId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"}}},"QuickBooksAutoMapException":{"type":"object","required":["qboAccountId","name","reason"],"properties":{"qboAccountId":{"type":["string","null"],"description":"Null for a Median account with no QuickBooks counterpart"},"glAccountId":{"type":"string","format":"uuid"},"name":{"type":"string"},"reason":{"type":"string","enum":["multiple_for_system_role","ambiguous","unknown_type","no_match","name_conflict","no_free_code","create_failed","median_account_not_in_quickbooks","quickbooks_account_inactive","quickbooks_account_reactivated"]},"candidates":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksAutoMapGlAccountRef"}}}},"QuickBooksAutoMapGlAccountRef":{"type":"object","required":["glAccountId","code","name"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"code":{"type":"string"},"name":{"type":"string"}}},"QuickBooksAutoMapSummary":{"type":"object","required":["mode","mapped","created","deactivated","renamed","exceptions","medianSystemAccountsKept"],"properties":{"mode":{"type":"string","enum":["established","new_file"]},"mapped":{"type":"integer","minimum":0},"created":{"type":"integer","minimum":0},"deactivated":{"type":"integer","minimum":0},"renamed":{"type":"integer","minimum":0},"exceptions":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksAutoMapException"}},"medianSystemAccountsKept":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksAutoMapGlAccountRef"}}}},"QuickBooksPostingSetup":{"type":"object","required":["connectionId","realmId","cutoff","cutoffHistory","sourceRunId","accounts","unmappedActiveAccounts","autoMap","arApEnablement","askMyAccountant"],"properties":{"arApEnablement":{"description":"Whether QuickBooks invoices and bills can post; null when the server has no database.","oneOf":[{"$ref":"#/components/schemas/QuickBooksArApEnablementStatus"},{"type":"null"}]},"connectionId":{"type":"string","format":"uuid"},"realmId":{"type":"string"},"cutoff":{"oneOf":[{"$ref":"#/components/schemas/QuickBooksPostingCutoffView"},{"type":"null"}]},"cutoffHistory":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksPostingCutoffView"}},"sourceRunId":{"type":["string","null"],"format":"uuid"},"unmappedActiveAccounts":{"type":"integer","minimum":0},"askMyAccountant":{"description":"#2642: the Ask My Accountant GL account automatic posting sends unmapped accounts and unreadable QuickBooks objects to; everything in it needs an accountant's categorization. Null before the account exists.","oneOf":[{"type":"object","required":["glAccountId","code","name","balanceCents","entryCount"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"code":{"type":"string"},"name":{"type":"string"},"balanceCents":{"type":"integer","description":"Debit minus credit over posted journal lines, integer cents"},"entryCount":{"type":"integer","minimum":0,"description":"Posted journal entries touching the account"}}},{"type":"null"}]},"autoMap":{"oneOf":[{"type":"object","required":["mode","exceptions","medianSystemAccountsKept","deactivated"],"properties":{"mode":{"type":"string","enum":["established","new_file"]},"exceptions":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksAutoMapException"}},"medianSystemAccountsKept":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksAutoMapGlAccountRef"}},"deactivated":{"type":"integer","minimum":0,"description":"Median accounts auto-map has deactivated so far"}}},{"type":"null"}]},"accounts":{"type":"array","items":{"type":"object","required":["qboAccountId","sourceObjectId","name","accountType","accountSubType","active","mapping"],"properties":{"qboAccountId":{"type":"string"},"sourceObjectId":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"accountType":{"type":["string","null"]},"accountSubType":{"type":["string","null"]},"active":{"type":"boolean"},"activeKnown":{"type":"boolean","description":"True only when the stored source contains an explicit Boolean Active field; unknown activity state cannot authorize a transfer."},"fullyQualifiedName":{"type":["string","null"]},"acctNum":{"type":["string","null"]},"parentQboAccountId":{"type":["string","null"]},"mapping":{"oneOf":[{"type":"object","required":["id","glAccountId","cashSource","approvedByUserId","approvedAt","automatic"],"properties":{"id":{"type":"string","format":"uuid"},"glAccountId":{"type":"string","format":"uuid"},"cashSource":{"type":"string","enum":["quickbooks","median"]},"approvedByUserId":{"type":"string","format":"uuid"},"approvedAt":{"type":"string","format":"date-time"},"automatic":{"type":"boolean","description":"Recorded by auto-map rather than picked by a person"}}},{"type":"null"}]}}}}}},"QuickBooksArApEnablementStatus":{"type":"object","required":["state","arApItemsEnabled","converted","validated","quickBooksConnected","canEnable","reason"],"properties":{"state":{"type":"string","enum":["off","dual_read","single_write","rolled_back"],"description":"The company's subledger conversion state"},"arApItemsEnabled":{"type":"boolean","description":"True when invoices and bills can post"},"converted":{"type":"boolean","description":"A conversion run completed in the current cycle"},"validated":{"type":"boolean","description":"That run passed INV-1..9 and is stamped"},"quickBooksConnected":{"type":"boolean"},"canEnable":{"type":"boolean"},"reason":{"type":["string","null"],"description":"Why canEnable is false"}}},"QuickBooksArApEnablementResult":{"type":"object","required":["outcome","status","failures"],"properties":{"outcome":{"type":"string","enum":["enabled","already_enabled","validation_failed","conversion_refused"]},"status":{"$ref":"#/components/schemas/QuickBooksArApEnablementStatus"},"failures":{"type":"array","description":"Failed or skipped integrity checks (validation_failed) or refusal reasons (conversion_refused, code CONVERSION_REFUSED)","items":{"type":"object","required":["code","detail","skipped"],"properties":{"code":{"type":"string"},"detail":{"type":"string"},"skipped":{"type":"boolean"}}}}}},"QuickBooksPostingCutoffView":{"type":"object","required":["id","cutoffDate","reason","setByUserId","setAt"],"properties":{"id":{"type":"string","format":"uuid"},"cutoffDate":{"type":"string","format":"date"},"reason":{"type":"string"},"setByUserId":{"type":"string","format":"uuid"},"setAt":{"type":"string","format":"date-time"}}},"QuickBooksSourcePreviewItem":{"type":"object","required":["objectType","providerId","txnDate","accountName","amountText","currency"],"properties":{"objectType":{"type":"string"},"providerId":{"type":"string"},"txnDate":{"type":["string","null"]},"accountName":{"type":["string","null"]},"amountText":{"type":["string","null"],"description":"Exact source amount text, never Median cents or GL authority"},"currency":{"type":["string","null"]}}},"QuickBooksLedgerStatus":{"type":"object","properties":{"status":{"type":"string","enum":["not_connected","connected","realm_mismatch","needs_reauth"]},"realmIdMasked":{"type":["string","null"]},"companyName":{"type":["string","null"]},"verification":{"type":["string","null"],"enum":["verified","unverified","realm_mismatch",null]},"connectedAt":{"type":["string","null"],"format":"date-time"},"connectionId":{"type":["string","null"],"format":"uuid"}},"required":["status","realmIdMasked","companyName","verification","connectedAt","connectionId"]},"PreparedOnboardingRequest":{"type":"object","description":"One outstanding customer request in an accountant-prepared engagement (#2560). Never a mailbox password.","properties":{"id":{"type":"string","pattern":"^[a-z0-9-]{2,40}$"},"label":{"type":"string","maxLength":200},"detail":{"type":"string","maxLength":500},"channel":{"type":"string","enum":["secure_upload","forwarding","share"]}},"required":["id","label","channel"],"additionalProperties":false},"PreparedOnboardingVerifiedAccess":{"type":"object","properties":{"kind":{"type":"string","enum":["qbo_accountant_access","bank_portal_view","payroll_portal_view","other"]},"source":{"type":"string","maxLength":200},"verifiedOn":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"note":{"type":"string","maxLength":300}},"required":["kind","source","verifiedOn"],"additionalProperties":false},"PreparedOnboardingProfileInput":{"type":"object","description":"Accountant-authored engagement setup bound to a custom pricing offer (#2560).","properties":{"engagement":{"type":"object","properties":{"ledger":{"type":"string","enum":["median","quickbooks","xero"]},"serviceStartLabel":{"type":"string","maxLength":120},"closeTargetLabel":{"type":"string","maxLength":200},"summary":{"type":"string","maxLength":600}},"required":["ledger","serviceStartLabel","closeTargetLabel"],"additionalProperties":false},"companyFacts":{"type":"object","properties":{"legalName":{"type":"string","maxLength":200},"qboCompanyName":{"type":"string","maxLength":200}},"required":["legalName"],"additionalProperties":false},"taskIds":{"type":"array","items":{"type":"string","enum":["basics","connect","processors","payroll","documents","books","history"]},"maxItems":7},"verifiedAccess":{"type":"array","items":{"$ref":"#/components/schemas/PreparedOnboardingVerifiedAccess"},"maxItems":20},"requests":{"type":"array","items":{"$ref":"#/components/schemas/PreparedOnboardingRequest"},"maxItems":30},"stripe":{"type":"object","properties":{"expectation":{"type":"string","enum":["connect","none"]}},"required":["expectation"],"additionalProperties":false}},"required":["engagement","companyFacts","taskIds"],"additionalProperties":false},"PreparedOnboardingProfileView":{"type":"object","description":"Customer-facing, read-only view of a prepared engagement (#2560).","properties":{"taskIds":{"type":"array","items":{"type":"string"}},"engagement":{"type":"object","properties":{"ledger":{"type":"string","enum":["median","quickbooks","xero"]},"serviceStartLabel":{"type":"string"},"closeTargetLabel":{"type":"string"},"summary":{"type":"string"},"monthlyPriceCents":{"type":["integer","null"]},"trialDays":{"type":["integer","null"]},"billingInterval":{"type":["string","null"],"enum":["month","year",null],"description":"Paid subscription's interval, else the offer's."},"chargedAmountCents":{"type":["integer","null"],"description":"Amount charged per billing interval (an annual plan's full charge)."},"termStart":{"type":["string","null"],"format":"date","description":"First day of the paid period (America/New_York); null before payment."},"termEnd":{"type":["string","null"],"format":"date","description":"Last day of the paid period; null before payment."}},"required":["ledger","serviceStartLabel","closeTargetLabel","monthlyPriceCents","trialDays"]},"companyFacts":{"type":"object","properties":{"legalName":{"type":"string"},"qboCompanyName":{"type":"string"}},"required":["legalName"]},"verifiedAccess":{"type":"array","items":{"$ref":"#/components/schemas/PreparedOnboardingVerifiedAccess"}},"requests":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/PreparedOnboardingRequest"},{"type":"object","properties":{"status":{"type":"string","enum":["open","submitted","verified"]},"submittedAt":{"type":["string","null"],"format":"date-time"},"verifiedAt":{"type":["string","null"],"format":"date-time"}},"required":["status","submittedAt","verifiedAt"]}]}},"stripe":{"type":"object","properties":{"expectation":{"type":"string","enum":["connect","none"]}},"required":["expectation"]}},"required":["taskIds","engagement","companyFacts","verifiedAccess","requests","stripe"]},"PreparedOnboardingProfile":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"offerId":{"type":"string","format":"uuid"},"companyId":{"type":["string","null"],"format":"uuid"},"profile":{"$ref":"#/components/schemas/PreparedOnboardingProfileInput"},"customerRequests":{"type":"object","additionalProperties":true},"verifiedRequests":{"type":"object","additionalProperties":true},"createdByEmail":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"view":{"$ref":"#/components/schemas/PreparedOnboardingProfileView"},"customerProgress":{"description":"What Median sees of the customer's setup; null until the profile is bound to a company (#2560).","oneOf":[{"type":"null"},{"type":"object","properties":{"doneTaskIds":{"type":"array","items":{"type":"string"}},"documents":{"type":"string","enum":["help_needed"]},"stripe":{"type":"string","enum":["not_attempted","connected","help_needed"]}},"required":["doneTaskIds","stripe"]}]}},"required":["id","offerId","companyId","profile","view","customerProgress","createdAt","updatedAt"]},"McpJsonRpcRequest":{"type":"object","required":["jsonrpc","method"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"oneOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"method":{"type":"string","description":"MCP request or notification method."},"params":{"type":"object","additionalProperties":true}}},"McpJsonRpcResponse":{"type":"object","required":["jsonrpc","id"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"oneOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"result":{"type":"object","additionalProperties":true},"error":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"}}}}},"McpJsonRpcRateLimitError":{"type":"object","required":["jsonrpc","id","error"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"oneOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","enum":[-32000]},"message":{"type":"string"}}}}},"AccountantQueueMeta":{"type":"object","required":["truncated","scopeTruncated","rowCappedCustomers","segment","total","scopedTotal","hasMore","nextOffset"],"properties":{"truncated":{"type":"boolean","description":"True when the page is not the whole queue, for either cause below; `total` is then null."},"scopeTruncated":{"type":"boolean","description":"A customer's scope lookup failed (#1959). Its rows are missing and no request can fill the gap; show the queue as unavailable."},"rowCappedCustomers":{"type":"array","description":"Customers with more than 5,000 matching rows in this request (#1958). Only their first 5,000 rows in sort order are included. Read the rest from /accountant/companies/{customerId}/transactions/{review|auto-approved}?segmentCursor=<segmentCursor> with the same filters and sort, until this list is empty.","items":{"type":"object","required":["customerId","segmentCursor"],"properties":{"customerId":{"type":"string","format":"uuid"},"segmentCursor":{"type":"string"}}}},"segment":{"type":"boolean","description":"True on a response to ?segmentCursor=. Its total covers only the rows after that cursor, not the queue."},"total":{"type":["integer","null"],"description":"Complete filtered total, or null when truncated is true."},"scopedTotal":{"type":"integer","minimum":0,"description":"Filtered count within the successfully resolved scope. Not a complete total when truncated is true."},"hasMore":{"type":"boolean"},"nextOffset":{"type":["integer","null"],"description":"Next queue page offset, null on exhaustion."}}},"AccountantScopeTruncated":{"type":"boolean","description":"True when at least one assigned customer was dropped from this practice-wide read because its client-status / report-access lookup could not be evaluated, so the payload is short that customer's rows (#1959). A customer deliberately excluded by its client status is not a gap and does not raise this. Always false on the customer-scoped route, which never fans out."},"AccountantScopeMeta":{"type":"object","description":"Completeness of a practice-wide accountant read (#1959).","properties":{"truncated":{"$ref":"#/components/schemas/AccountantScopeTruncated"}}},"StripeInstallLinkInput":{"type":"object","properties":{"entityId":{"type":"string","format":"uuid","description":"Model A legal entity to bind the connection to. Omitted when the company has a single entity."},"frontendReturnUri":{"type":"string","description":"Relative app path the install callback returns the user to."}},"additionalProperties":false},"StripeInstallLinkResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["installUrl","authorizationUrl"],"properties":{"installUrl":{"type":"string","format":"uri"},"authorizationUrl":{"type":"string","format":"uri","description":"Alias of installUrl, kept for the generic provider-connect client."}}}}},"StripeDisconnectInput":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid","description":"Which installed Stripe account to disconnect. Omitted disconnects the company's only connection."}},"additionalProperties":false},"StripeDisconnectResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["disconnected"],"properties":{"disconnected":{"type":"boolean","const":true}}}}},"StripeSyncResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["synced","failed"],"properties":{"synced":{"type":"integer","minimum":0},"failed":{"type":"integer","minimum":0}}}}},"StripeConnectionAccountSummary":{"type":"object","required":["connectionId","stripeAccountId","status","livemode","lastSyncAt","errorMessage"],"properties":{"connectionId":{"type":"string","format":"uuid"},"stripeAccountId":{"type":"string"},"status":{"type":"string"},"livemode":{"type":["boolean","null"]},"lastSyncAt":{"type":["string","null"],"format":"date-time"},"errorMessage":{"type":["string","null"]}}},"StripeAccountingBlock":{"type":"object","description":"Stage-A Stripe GL guard state for the company (#1453A). Present only for companies on the guard allowlist.\n","required":["code","action","message","accountCodes","adoptableCodes"],"properties":{"code":{"type":"string","const":"STRIPE_GL_ACCOUNT_REBIND_REQUIRED"},"action":{"type":"string","const":"accountant_review"},"message":{"type":"string"},"accountCodes":{"type":"array","description":"Codes with a blocking collision, or missing while connected. These need accountant review and fail every connect, sync, and post.\n","items":{"type":"string"}},"adoptableCodes":{"type":"array","description":"Codes whose rows conform on accounting shape and name evidence. They are normalized automatically by the audited adoption path on the next connect or sync; no action is required.\n","items":{"type":"string"}}}},"StripeConnectionStatus":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["not_connected","auth_initiated","connected","importing","synced","error"]},"stripeAccountId":{"type":["string","null"]},"livemode":{"type":["boolean","null"]},"importedCount":{"type":"integer","minimum":0},"backfillStartedAt":{"type":["string","null"],"format":"date-time"},"backfillCompletedAt":{"type":["string","null"],"format":"date-time"},"lastSyncAt":{"type":["string","null"],"format":"date-time"},"lastSyncAttemptAt":{"type":["string","null"],"format":"date-time"},"lastWebhookReceivedAt":{"type":["string","null"],"format":"date-time"},"errorMessage":{"type":["string","null"]},"accounts":{"type":"array","items":{"$ref":"#/components/schemas/StripeConnectionAccountSummary"}},"accountingBlock":{"$ref":"#/components/schemas/StripeAccountingBlock"}}},"StripeConnectionStatusResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/StripeConnectionStatus"}}},"MoneyV2":{"type":"object","required":["minorUnits","currency","minorUnit"],"additionalProperties":false,"properties":{"minorUnits":{"type":"string","pattern":"^(0|-?[1-9][0-9]*)$","description":"Signed base-10 minor units; never a JSON number."},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer","minimum":0,"maximum":9},"ledgerDebitCents":{"type":"integer"},"ledgerCreditCents":{"type":"integer"},"ledgerCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"ledgerMinorUnitExponent":{"type":"integer","minimum":0,"maximum":9,"pattern":"^[A-Z]{3}$"},"minorUnit":{"type":"integer","minimum":0,"maximum":9}}},"CurrencyReferenceCurrent":{"type":"object","required":["code","numericCode","name","minorUnit","kind","entities"],"properties":{"code":{"type":"string","pattern":"^[A-Z]{3}$"},"numericCode":{"type":"string","pattern":"^[0-9]{3}$"},"name":{"type":"string"},"minorUnit":{"type":["integer","null"],"minimum":0,"maximum":9},"kind":{"type":"string","enum":["currency","fund","precious_metal","testing","no_currency"]},"entities":{"type":"array","items":{"type":"string"}}}},"CurrencyReferenceHistorical":{"type":"object","required":["code","numericCode","name","entity","withdrawalDate","isFund"],"properties":{"code":{"type":"string","pattern":"^[A-Z]{3}$"},"numericCode":{"type":["string","null"],"pattern":"^[0-9]{3}$"},"name":{"type":"string"},"entity":{"type":"string"},"withdrawalDate":{"type":["string","null"],"description":"Raw SIX withdrawal date or published date range."},"isFund":{"type":"boolean"}}},"CurrencyCapabilities":{"type":"object","required":["provisioning","ledger","presentation","arAp","forecast","providerIngress","legacyCents"],"additionalProperties":false,"properties":{"provisioning":{"type":"boolean"},"ledger":{"type":"boolean"},"presentation":{"type":"boolean"},"arAp":{"type":"boolean"},"forecast":{"type":"boolean"},"providerIngress":{"type":"boolean"},"legacyCents":{"type":"boolean"}}},"CurrencyReference":{"type":"object","required":["code","current","historical","capabilities"],"properties":{"code":{"type":"string","pattern":"^[A-Z]{3}$"},"current":{"oneOf":[{"$ref":"#/components/schemas/CurrencyReferenceCurrent"},{"type":"null"}]},"historical":{"type":"array","items":{"$ref":"#/components/schemas/CurrencyReferenceHistorical"}},"capabilities":{"$ref":"#/components/schemas/CurrencyCapabilities"}}},"CurrencyReferenceData":{"type":"object","required":["publication","currencies"],"properties":{"publication":{"type":"object","required":["current","historical"],"properties":{"current":{"type":"string","format":"date"},"historical":{"type":"string","format":"date"}}},"currencies":{"type":"array","items":{"$ref":"#/components/schemas/CurrencyReference"}}}},"CurrencyReferenceResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/CurrencyReferenceData"}}},"InboundEmailIngestResult":{"type":"object","additionalProperties":false,"properties":{"accepted":{"type":"boolean","const":true},"companyId":{"type":"string","format":"uuid"},"created":{"type":"integer","minimum":0},"duplicates":{"type":"integer","minimum":0}},"required":["accepted","companyId","created","duplicates"]},"InboundEmailIngestApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/InboundEmailIngestResult"}},"required":["success","data"]},"OnboardingV3QuoteRequest":{"type":"object","additionalProperties":false,"properties":{"revenueBand":{"type":"string","minLength":1,"maxLength":64},"expensesBand":{"type":"string","enum":["under-50k","50k-100k","100k-250k","250k-500k","500k-1m","1m-3m","3m-10m","over-10m"]},"accountCount":{"type":"integer","minimum":1,"maximum":40}},"required":["revenueBand","expensesBand","accountCount"]},"OnboardingV3Quote":{"oneOf":[{"type":"object","additionalProperties":false,"properties":{"tier":{"type":"string","const":"200"},"priceMonthlyCents":{"type":"integer","const":20000},"reason":{"type":"string","minLength":1},"planId":{"type":"string","const":"essential"}},"required":["tier","priceMonthlyCents","reason","planId"]},{"type":"object","additionalProperties":false,"properties":{"tier":{"type":"string","const":"500"},"priceMonthlyCents":{"type":"integer","const":50000},"reason":{"type":"string","minLength":1},"planId":{"type":"string","const":"growth"}},"required":["tier","priceMonthlyCents","reason","planId"]},{"type":"object","additionalProperties":false,"properties":{"tier":{"type":"string","const":"sales"},"priceMonthlyCents":{"type":"null"},"reason":{"type":"string","minLength":1},"planId":{"type":"null"}},"required":["tier","priceMonthlyCents","reason","planId"]}]},"OnboardingV3OfferResolveRequest":{"type":"object","additionalProperties":false,"description":"Opaque offer capability submitted in the body. Any unusable string receives the same 404 response as an unknown capability.\n","properties":{"token":{"type":"string"},"billingInterval":{"type":"string","enum":["month","year"],"description":"Interval the customer chose; omitted = the offer's default. month is accepted for an annual offer only when allowMonthly is true (422 otherwise)."}},"required":["token"]},"OnboardingV3Offer":{"type":"object","additionalProperties":false,"properties":{"monthlyPriceCents":{"type":"integer","minimum":1,"maximum":100000000},"trialDays":{"type":"integer","minimum":0,"maximum":365},"billingInterval":{"type":"string","const":"year","description":"Present only for an annual offer (absent = monthly)."},"allowMonthly":{"type":"boolean","description":"Annual offers only: true when the customer may switch to monthly billing."},"annualPriceCents":{"type":"integer","minimum":1,"description":"Annual offers only: the annual charge (monthly band x 10)."}},"required":["monthlyPriceCents","trialDays"]},"OnboardingV3QuoteApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3Quote"}},"required":["success","data"]},"OnboardingV3OfferApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3Offer"}},"required":["success","data"]},"OnboardingV3EmptyBody":{"type":"object","additionalProperties":false,"maxProperties":0},"OnboardingV3WelcomeCallBooking":{"type":"object","additionalProperties":false,"properties":{"start":{"type":"string","format":"date-time"},"timeZone":{"type":"string","minLength":1,"maxLength":100,"pattern":"^(?=[\\s\\S]*\\S)[\\s\\S]+$","description":"Server-validated IANA time zone."}},"required":["start","timeZone"]},"OnboardingV3WelcomeCallEmbeddedBooking":{"type":"object","additionalProperties":false,"description":"Browser callback correlation evidence. These values are persisted as pending and do not establish provider booking authority.","properties":{"providerBookingUid":{"type":"string","minLength":1,"maxLength":255,"pattern":"^(?=[\\s\\S]*\\S)[^\\u0000-\\u001F\\u007F]+$","description":"Browser-provided correlation evidence, not provider authority; trimmed before pending persistence."},"start":{"type":"string","format":"date-time","description":"Browser-reported start used only to correlate server-side provider verification."},"end":{"type":"string","format":"date-time","description":"Browser-reported end used only to validate and correlate the expected twenty-minute call."},"eventTypeId":{"type":"integer","minimum":1,"maximum":2147483647,"description":"Browser-reported event type used only to correlate server-side provider verification."},"status":{"type":"string","const":"accepted","description":"Browser callback claim only; accepted is not treated as verified provider status."}},"required":["providerBookingUid","start","end","eventTypeId","status"]},"OnboardingV3WelcomeCallSlot":{"type":"object","additionalProperties":false,"properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"}},"required":["start","end"]},"OnboardingV3WelcomeCallDay":{"type":"object","additionalProperties":false,"properties":{"date":{"type":"string","format":"date"},"times":{"type":"array","maxItems":3,"items":{"$ref":"#/components/schemas/OnboardingV3WelcomeCallSlot"}}},"required":["date","times"]},"OnboardingV3WelcomeCall":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid"},"scheduledAt":{"type":"string","format":"date-time"},"durationMinutes":{"type":"integer","const":20},"status":{"type":"string","enum":["scheduled","completed"]}},"required":["id","scheduledAt","durationMinutes","status"]},"OnboardingV3WelcomeCallView":{"type":"object","additionalProperties":false,"properties":{"state":{"type":"string","enum":["locked","ready","verifying","booked","reschedule"],"description":"verifying means callback evidence is pending server-side Cal.com verification; that state has no public call or availability slots."},"schedulingMode":{"type":"string","enum":["api","embed","disabled"]},"fullCalendarUrl":{"type":["string","null"],"format":"uri","description":"Booking navigation URL only. It is not booking evidence and becomes null after the provider booking is server-verified."},"slots":{"type":"array","maxItems":5,"items":{"$ref":"#/components/schemas/OnboardingV3WelcomeCallDay"}},"call":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3WelcomeCall"},{"type":"null"}]}},"required":["state","schedulingMode","fullCalendarUrl","slots","call"]},"OnboardingV3WelcomeCallApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3WelcomeCallView"}},"required":["success","data"]},"OnboardingV3AvailableProgressMetric":{"type":"object","additionalProperties":false,"properties":{"available":{"type":"boolean","const":true},"completed":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0}},"required":["available","completed","total"]},"OnboardingV3UnavailableProgressMetric":{"type":"object","additionalProperties":false,"properties":{"available":{"type":"boolean","const":false},"completed":{"type":"null"},"total":{"type":"null"},"reason":{"type":"string","const":"query_failed"}},"required":["available","completed","total","reason"]},"OnboardingV3ProgressMetric":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3AvailableProgressMetric"},{"$ref":"#/components/schemas/OnboardingV3UnavailableProgressMetric"}]},"OnboardingV3BooksProgressMeters":{"type":"object","additionalProperties":false,"properties":{"transactions":{"$ref":"#/components/schemas/OnboardingV3ProgressMetric"},"chartOfAccounts":{"$ref":"#/components/schemas/OnboardingV3ProgressMetric"},"documents":{"$ref":"#/components/schemas/OnboardingV3ProgressMetric"},"monthsClosed":{"$ref":"#/components/schemas/OnboardingV3ProgressMetric"}},"required":["transactions","chartOfAccounts","documents","monthsClosed"]},"OnboardingV3BuildingBooksVeiled":{"type":"object","additionalProperties":false,"properties":{"state":{"type":"string","const":"veiled"}},"required":["state"]},"OnboardingV3BuildingBooksUnavailable":{"type":"object","additionalProperties":false,"properties":{"state":{"type":"string","const":"unavailable"},"reason":{"type":"string","const":"overview_failed"}},"required":["state","reason"]},"OnboardingV3BuildingBooksMetrics":{"type":"object","additionalProperties":false,"properties":{"cashOnHand":{"type":"number"},"netBurnMonthly":{"type":"number"},"revenueLast30Days":{"type":"number"},"runwayMonths":{"type":"number","minimum":0}},"required":["cashOnHand","netBurnMonthly","revenueLast30Days","runwayMonths"]},"OnboardingV3BuildingBooksLive":{"type":"object","additionalProperties":false,"properties":{"state":{"type":"string","const":"live"},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"metrics":{"$ref":"#/components/schemas/OnboardingV3BuildingBooksMetrics"}},"required":["state","currency","metrics"]},"OnboardingV3BuildingBooks":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3BuildingBooksVeiled"},{"$ref":"#/components/schemas/OnboardingV3BuildingBooksUnavailable"},{"$ref":"#/components/schemas/OnboardingV3BuildingBooksLive"}]},"OnboardingV3BooksProgress":{"type":"object","additionalProperties":false,"properties":{"companyId":{"type":"string","format":"uuid"},"companyName":{"type":"string","minLength":1},"metricsEnabled":{"type":"boolean"},"progress":{"$ref":"#/components/schemas/OnboardingV3BooksProgressMeters"},"buildingBooks":{"$ref":"#/components/schemas/OnboardingV3BuildingBooks"}},"required":["companyId","companyName","metricsEnabled","progress","buildingBooks"]},"OnboardingV3BooksProgressApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3BooksProgress"}},"required":["success","data"]},"OnboardingV3BooksOpen":{"type":"object","additionalProperties":false,"properties":{"companyId":{"type":"string","format":"uuid"},"stage":{"type":"string","const":"books"},"opened":{"type":"boolean"}},"required":["companyId","stage","opened"]},"OnboardingV3BooksOpenApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3BooksOpen"}},"required":["success","data"]},"OnboardingV3ReviewItemCreate":{"type":"object","additionalProperties":false,"properties":{"headline":{"type":"string","minLength":1,"maxLength":500,"pattern":"^(?=[\\s\\S]*\\S)[\\s\\S]+$"},"detail":{"type":"string","minLength":1,"maxLength":5000,"pattern":"^(?=[\\s\\S]*\\S)[\\s\\S]+$"},"sort":{"type":"integer","minimum":-10000,"maximum":10000,"default":0}},"required":["headline","detail"]},"OnboardingV3ReviewItemUpdate":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"headline":{"type":"string","minLength":1,"maxLength":500,"pattern":"^(?=[\\s\\S]*\\S)[\\s\\S]+$"},"detail":{"type":"string","minLength":1,"maxLength":5000,"pattern":"^(?=[\\s\\S]*\\S)[\\s\\S]+$"},"sort":{"type":"integer","minimum":-10000,"maximum":10000}}},"OnboardingV3ReviewItem":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"headline":{"type":"string"},"detail":{"type":"string"},"sort":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","companyId","headline","detail","sort","createdAt","updatedAt"]},"OnboardingV3ReviewItems":{"type":"array","items":{"$ref":"#/components/schemas/OnboardingV3ReviewItem"}},"OnboardingV3ReviewItemApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3ReviewItem"}},"required":["success","data"]},"OnboardingV3ReviewItemsApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3ReviewItems"}},"required":["success","data"]},"OnboardingV3QuestionTransactionRef":{"type":"object","additionalProperties":false,"properties":{"account":{"type":"string","minLength":1,"maxLength":255,"pattern":"^(?=[\\s\\S]*\\S)(?![\\s\\S]*(?:^|[^0-9])(?:[0-9]{2}-[0-9]{7}|[0-9]{9})(?:[^0-9]|$))[\\s\\S]+$"},"date":{"type":"string","format":"date"},"amountCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":{"type":"string","minLength":1,"maxLength":500,"pattern":"^(?=[\\s\\S]*\\S)(?![\\s\\S]*(?:^|[^0-9])(?:[0-9]{2}-[0-9]{7}|[0-9]{9})(?:[^0-9]|$))[\\s\\S]+$"}},"required":["account","date","amountCents","description"]},"OnboardingV3QuestionCreate":{"type":"object","additionalProperties":false,"properties":{"ask":{"type":"string","minLength":1,"maxLength":1000,"pattern":"^(?=[\\s\\S]*\\S)(?![\\s\\S]*(?:^|[^0-9])(?:[0-9]{2}-[0-9]{7}|[0-9]{9})(?:[^0-9]|$))[\\s\\S]+$"},"chips":{"type":"array","maxItems":12,"uniqueItems":true,"default":[],"description":"Values are trimmed and must remain unique after trimming.","items":{"type":"string","minLength":1,"maxLength":120,"pattern":"^(?=[\\s\\S]*\\S)(?![\\s\\S]*(?:^|[^0-9])(?:[0-9]{2}-[0-9]{7}|[0-9]{9})(?:[^0-9]|$))[\\s\\S]+$"}},"transactionRef":{"$ref":"#/components/schemas/OnboardingV3QuestionTransactionRef"}},"required":["ask"]},"OnboardingV3QuestionChoiceAnswer":{"type":"object","additionalProperties":false,"properties":{"choice":{"type":"string","minLength":1,"maxLength":120,"pattern":"^(?=[\\s\\S]*\\S)(?![\\s\\S]*(?:^|[^0-9])(?:[0-9]{2}-[0-9]{7}|[0-9]{9})(?:[^0-9]|$))[\\s\\S]+$"}},"required":["choice"]},"OnboardingV3QuestionTextAnswer":{"type":"object","additionalProperties":false,"properties":{"text":{"type":"string","minLength":1,"maxLength":5000,"pattern":"^(?=[\\s\\S]*\\S)(?![\\s\\S]*(?:^|[^0-9])(?:[0-9]{2}-[0-9]{7}|[0-9]{9})(?:[^0-9]|$))[\\s\\S]+$"}},"required":["text"]},"OnboardingV3QuestionSkippedAnswer":{"type":"object","additionalProperties":false,"properties":{"skipped":{"type":"boolean","const":true}},"required":["skipped"]},"OnboardingV3QuestionAnswer":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3QuestionChoiceAnswer"},{"$ref":"#/components/schemas/OnboardingV3QuestionTextAnswer"},{"$ref":"#/components/schemas/OnboardingV3QuestionSkippedAnswer"}]},"OnboardingV3QuestionChoiceAnswerRecord":{"type":"object","additionalProperties":false,"properties":{"kind":{"type":"string","const":"choice"},"value":{"type":"string"},"answeredAt":{"type":"string","format":"date-time"}},"required":["kind","value","answeredAt"]},"OnboardingV3QuestionTextAnswerRecord":{"type":"object","additionalProperties":false,"properties":{"kind":{"type":"string","const":"text"},"value":{"type":"string"},"answeredAt":{"type":"string","format":"date-time"}},"required":["kind","value","answeredAt"]},"OnboardingV3QuestionSkippedAnswerRecord":{"type":"object","additionalProperties":false,"properties":{"kind":{"type":"string","const":"skipped"},"value":{"type":"null"},"answeredAt":{"type":"string","format":"date-time"}},"required":["kind","value","answeredAt"]},"OnboardingV3QuestionAnswerRecord":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3QuestionChoiceAnswerRecord"},{"$ref":"#/components/schemas/OnboardingV3QuestionTextAnswerRecord"},{"$ref":"#/components/schemas/OnboardingV3QuestionSkippedAnswerRecord"}]},"OnboardingV3Question":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid"},"threadId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"ask":{"type":"string"},"chips":{"type":"array","items":{"type":"string"}},"transactionRef":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3QuestionTransactionRef"},{"type":"null"}]},"sourceKind":{"type":"string","enum":["accountant","business_basics_deferred"]},"sourceFieldId":{"type":["string","null"]},"status":{"type":"string","enum":["open","answered","skipped","withdrawn"]},"answer":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3QuestionAnswerRecord"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","threadId","companyId","ask","chips","transactionRef","sourceKind","sourceFieldId","status","answer","createdAt","updatedAt"]},"OnboardingV3QuestionsInbox":{"type":"object","additionalProperties":false,"properties":{"questions":{"type":"array","items":{"$ref":"#/components/schemas/OnboardingV3Question"}},"summary":{"type":"object","additionalProperties":false,"properties":{"answered":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0}},"required":["answered","total"]}},"required":["questions","summary"]},"OnboardingV3QuestionApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3Question"}},"required":["success","data"]},"OnboardingV3QuestionsInboxApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3QuestionsInbox"}},"required":["success","data"]},"OnboardingV3FlowPatch":{"type":"object","additionalProperties":false,"properties":{"stage":{"type":"string","const":"price"}},"required":["stage"]},"OnboardingV3Flow":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":["string","null"],"format":"uuid"},"stage":{"type":"string","enum":["auth","price","sales","subscribe","setup","books"]},"revenueBand":{"type":["string","null"]},"expensesBand":{"type":["string","null"]},"accountCount":{"type":["integer","null"],"minimum":1,"maximum":40},"priceTier":{"type":["string","null"],"enum":["200","500","custom","sales",null]},"priceMonthlyCents":{"type":["integer","null"],"minimum":1},"pricePlanId":{"type":["string","null"],"enum":["essential","growth","custom",null]},"trialDays":{"type":"integer","minimum":0,"maximum":365},"billingInterval":{"type":"string","const":"year","description":"Present only when the customer chose annual billing on a custom offer (absent = monthly)."},"welcomeCall":{"type":["object","null"]},"accountName":{"type":"string","minLength":1,"maxLength":254},"accountEmail":{"type":"string","format":"email","maxLength":254},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","companyId","stage","revenueBand","expensesBand","accountCount","priceTier","priceMonthlyCents","pricePlanId","trialDays","welcomeCall","accountName","accountEmail","createdAt","updatedAt"]},"OnboardingV3FlowApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3Flow"}},"required":["success","data"]},"OnboardingV3SetupIntent":{"type":"object","additionalProperties":false,"properties":{"clientSecret":{"type":"string","minLength":1},"publishableKey":{"type":"string","pattern":"^pk_test_[A-Za-z0-9_]+$"}},"required":["clientSecret","publishableKey"]},"OnboardingV3SetupIntentApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3SetupIntent"}},"required":["success","data"]},"OnboardingV3SubscribeResult":{"oneOf":[{"type":"object","additionalProperties":false,"properties":{"flow":{"$ref":"#/components/schemas/OnboardingV3Flow"}},"required":["flow"]},{"type":"object","additionalProperties":false,"properties":{"actionRequired":{"type":"object","additionalProperties":false,"properties":{"clientSecret":{"type":"string","minLength":1}},"required":["clientSecret"]}},"required":["actionRequired"]}]},"OnboardingV3SubscribeApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3SubscribeResult"}},"required":["success","data"]},"OnboardingV3CheckoutComplete":{"type":"object","additionalProperties":false,"properties":{"sessionId":{"type":"string","maxLength":255,"pattern":"^cs_[A-Za-z0-9_]+$"}},"required":["sessionId"]},"OnboardingV3CheckoutSession":{"type":"object","additionalProperties":false,"properties":{"url":{"type":"string","format":"uri","maxLength":2048,"description":"Hosted Stripe Checkout URL (always https on checkout.stripe.com)."}},"required":["url"]},"OnboardingV3CheckoutSessionApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3CheckoutSession"}},"required":["success","data"]},"OnboardingV3SetupTaskId":{"type":"string","enum":["authority","basics","connect","processors","payroll","documents","books","history","median-work","call"]},"OnboardingV3DelegatedTaskId":{"type":"string","description":"Tasks a delegate can complete without owner-only bank or history authority. Connect and history remain assigned to the signed-in owner.","enum":["processors","payroll","documents","books"]},"OnboardingV3SetupTaskState":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"status":{"type":"string","const":"done"},"owner":{"type":"string","maxLength":100}}},"OnboardingV3SetupDataSlice":{"type":"object","description":"Task-local JSON data, limited by the runtime validator to 24KB, 32 levels of nesting, and 4,096 JSON nodes.","additionalProperties":true},"OnboardingV3AuthorityDelegateInput":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","minLength":2,"maxLength":100,"pattern":"^(?![\\s\\S]*</?[A-Za-z][^>]*>)[\\s\\S]*$"},"email":{"type":"string","format":"email","maxLength":254}},"required":["name","email"]},"OnboardingV3AuthorityIntent":{"description":"Owner intent only. Invite lifecycle metadata is server-managed and cannot be supplied through the setup-state patch.","oneOf":[{"type":"object","additionalProperties":false,"properties":{"isAuthority":{"type":"boolean","const":true},"delegate":{"type":"null"}},"required":["isAuthority"]},{"type":"object","additionalProperties":false,"properties":{"isAuthority":{"type":"boolean","const":false},"delegate":{"$ref":"#/components/schemas/OnboardingV3AuthorityDelegateInput"}},"required":["isAuthority","delegate"]}]},"OnboardingV3BusinessBasicsDeferredInput":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","enum":["entityType","state","yearFounded","ein","industry","fiscalYearEnd"]},"label":{"type":"string","minLength":1,"maxLength":120,"pattern":"^(?![\\s\\S]*</?[A-Za-z][^>]*>)[\\s\\S]*$"},"ask":{"type":"string","minLength":1,"maxLength":500,"pattern":"^(?![\\s\\S]*</?[A-Za-z][^>]*>)[\\s\\S]*$"}},"required":["id","label"]},"OnboardingV3BusinessBasicsData":{"type":"object","additionalProperties":false,"properties":{"legalName":{"type":"string","maxLength":255,"pattern":"^(?![\\s\\S]*</?[A-Za-z][^>]*>)[\\s\\S]*$","description":"Required and at least two non-whitespace characters when completing."},"entityType":{"type":"string","maxLength":50,"pattern":"^(?![\\s\\S]*</?[A-Za-z][^>]*>)[\\s\\S]*$"},"state":{"type":"string","maxLength":50,"pattern":"^(?![\\s\\S]*</?[A-Za-z][^>]*>)[\\s\\S]*$"},"yearFounded":{"type":"string","pattern":"^(?:|18[0-9]{2}|19[0-9]{2}|20[0-9]{2}|2100)$"},"fiscalYearEnd":{"type":"string","pattern":"^(?:|(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01]))$","description":"Fiscal year end as MM-DD (must be a real date), or empty when not answered. Written to companies.fiscal_year_end on completion (#2019)."},"industry":{"type":"string","maxLength":100,"pattern":"^(?![\\s\\S]*</?[A-Za-z][^>]*>)[\\s\\S]*$"},"industryOther":{"type":"string","maxLength":100,"pattern":"^(?![\\s\\S]*</?[A-Za-z][^>]*>)[\\s\\S]*$"},"books":{"type":"string","maxLength":100,"pattern":"^(?![\\s\\S]*</?[A-Za-z][^>]*>)[\\s\\S]*$"},"ein":{"type":"string","maxLength":20,"pattern":"^[0-9-]*$"},"deferred":{"type":"array","maxItems":6,"items":{"$ref":"#/components/schemas/OnboardingV3BusinessBasicsDeferredInput"}}}},"OnboardingV3DeferredInput":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","minLength":1,"maxLength":64},"label":{"type":"string","minLength":1,"maxLength":120},"ask":{"type":"string","minLength":1,"maxLength":500}},"required":["id","label"]},"OnboardingV3DeferredItem":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","minLength":1,"maxLength":64},"label":{"type":"string","minLength":1,"maxLength":120},"ask":{"type":"string","minLength":1,"maxLength":500},"taskId":{"$ref":"#/components/schemas/OnboardingV3SetupTaskId"}},"required":["id","label","taskId"]},"OnboardingV3SetupTaskRecord":{"type":"object","propertyNames":{"$ref":"#/components/schemas/OnboardingV3SetupTaskId"},"additionalProperties":{"$ref":"#/components/schemas/OnboardingV3SetupTaskState"}},"OnboardingV3SetupDataRecord":{"type":"object","propertyNames":{"$ref":"#/components/schemas/OnboardingV3SetupTaskId"},"additionalProperties":{"$ref":"#/components/schemas/OnboardingV3SetupDataSlice"}},"OnboardingV3DelegateCompletedTaskState":{"type":"object","additionalProperties":false,"properties":{"status":{"type":"string","const":"done"}},"required":["status"]},"OnboardingV3DelegateTaskRecord":{"type":"object","propertyNames":{"$ref":"#/components/schemas/OnboardingV3DelegatedTaskId"},"additionalProperties":{"$ref":"#/components/schemas/OnboardingV3DelegateCompletedTaskState"}},"OnboardingV3DelegateDataRecord":{"type":"object","propertyNames":{"$ref":"#/components/schemas/OnboardingV3DelegatedTaskId"},"additionalProperties":{"$ref":"#/components/schemas/OnboardingV3SetupDataSlice"}},"OnboardingV3DelegateDeferredItem":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","minLength":1,"maxLength":64},"label":{"type":"string","minLength":1,"maxLength":120},"ask":{"type":"string","minLength":1,"maxLength":500},"taskId":{"$ref":"#/components/schemas/OnboardingV3DelegatedTaskId"}},"required":["id","label","taskId"]},"OnboardingV3AuthoritySetupPatch":{"type":"object","additionalProperties":false,"properties":{"taskId":{"type":"string","const":"authority"},"task":{"$ref":"#/components/schemas/OnboardingV3SetupTaskState"},"data":{"$ref":"#/components/schemas/OnboardingV3AuthorityIntent"}},"required":["taskId","data"]},"OnboardingV3BusinessBasicsSetupPatch":{"type":"object","additionalProperties":false,"minProperties":2,"properties":{"taskId":{"type":"string","const":"basics"},"task":{"$ref":"#/components/schemas/OnboardingV3SetupTaskState"},"data":{"$ref":"#/components/schemas/OnboardingV3BusinessBasicsData"}},"required":["taskId"]},"OnboardingV3GenericSetupPatch":{"type":"object","additionalProperties":false,"minProperties":2,"properties":{"taskId":{"type":"string","enum":["processors","payroll"]},"task":{"$ref":"#/components/schemas/OnboardingV3SetupTaskState"},"data":{"$ref":"#/components/schemas/OnboardingV3SetupDataSlice"},"deferred":{"type":"array","maxItems":24,"items":{"$ref":"#/components/schemas/OnboardingV3DeferredInput"}}},"required":["taskId"],"allOf":[{"$ref":"#/components/schemas/OnboardingV3PayrollPatchConstraint"}]},"OnboardingV3PayrollData":{"type":"object","additionalProperties":false,"description":"Payroll answers stored in durable setup state. Provider IDs include gusto, rippling, adp, justworks, square-payroll, none, trinet, and other. With other, providerName is the actual supplied provider name, never mapped to another provider. Strings are trimmed and reject HTML markup and ASCII control characters. Incomplete drafts may have an empty name. Completion validates the merged saved and supplied answer and requires a nonempty providerName when provider is other.","properties":{"provider":{"type":"string","maxLength":100,"pattern":"^(?![\\s\\S]*<[A-Za-z!/?])(?![\\s\\S]*[\\x00-\\x1F\\x7F])[\\s\\S]*$"},"providerName":{"type":"string","maxLength":100,"pattern":"^(?![\\s\\S]*<[A-Za-z!/?])(?![\\s\\S]*[\\x00-\\x1F\\x7F])[\\s\\S]*$"}}},"OnboardingV3PayrollPatchConstraint":{"if":{"properties":{"taskId":{"const":"payroll"}},"required":["taskId"]},"then":{"properties":{"data":{"$ref":"#/components/schemas/OnboardingV3PayrollData"}}}},"OnboardingV3DoneSetupTaskState":{"type":"object","additionalProperties":false,"properties":{"status":{"type":"string","const":"done"},"owner":{"type":"string","maxLength":100}},"required":["status"]},"OnboardingV3ProviderOwnershipTaskState":{"type":"object","additionalProperties":false,"properties":{"owner":{"type":"string","maxLength":100}},"required":["owner"]},"OnboardingV3ConnectCompletionData":{"type":"object","additionalProperties":false,"properties":{"integrationIds":{"type":"array","minItems":1,"maxItems":25,"uniqueItems":true,"items":{"type":"string","format":"uuid"}},"accountIds":{"type":"array","minItems":1,"maxItems":250,"uniqueItems":true,"items":{"type":"string","format":"uuid"}},"personalAccountIds":{"type":"array","maxItems":250,"uniqueItems":true,"items":{"type":"string","format":"uuid"}}},"required":["integrationIds","accountIds","personalAccountIds"]},"OnboardingV3DocumentsCompletionData":{"type":"object","additionalProperties":false,"properties":{"email":{"type":"string","enum":["connected","forwarding","help_needed"]}},"required":["email"]},"QuickBooksReconciliationSnapshotInput":{"type":"object","additionalProperties":false,"required":["bankAccountId","reconciledThroughDate","endingBalanceCents","currency"],"description":"What QuickBooks' Reconcile screen shows for one account (#2873). Who recorded it and when are set by the server and are not accepted here.","properties":{"bankAccountId":{"type":"string","format":"uuid","description":"The Median bank or card account that is reconciled (the id reconciliations use)."},"reconciledThroughDate":{"type":"string","format":"date","description":"From 2000-01-01 to one day after today (UTC); anything else is refused with 422."},"endingBalanceCents":{"type":"integer","format":"int64","description":"Ending balance in integer minor units of `currency`, as shown in QuickBooks. Stored as sent. For a credit card enter the balance owed; the comparison ignores its sign."},"currency":{"type":"string","pattern":"^[A-Z]{3}$","description":"Must be the account's currency."},"note":{"type":"string","minLength":1,"maxLength":2000,"description":"No control characters other than tab and line breaks."}}},"QuickBooksReconciliationSnapshot":{"type":"object","additionalProperties":false,"required":["id","reconciledThroughDate","endingBalanceCents","currency","note","recordedAt","recordedByUserId","recordedByName"],"description":"An accountant-entered QuickBooks snapshot. Not read from QuickBooks.","properties":{"id":{"type":"string","format":"uuid"},"reconciledThroughDate":{"type":"string","format":"date"},"endingBalanceCents":{"type":"integer","format":"int64"},"currency":{"type":"string"},"note":{"type":["string","null"]},"recordedAt":{"type":"string","format":"date-time"},"recordedByUserId":{"type":"string","format":"uuid"},"recordedByName":{"type":["string","null"],"description":"Null when the user can no longer be read."}}},"QuickBooksReconciliationAccountParity":{"type":"object","additionalProperties":false,"required":["bankAccountId","accountName","institutionName","currency","balanceComparison","parity","snapshot","median"],"properties":{"bankAccountId":{"type":"string","format":"uuid"},"accountName":{"type":["string","null"]},"institutionName":{"type":"string"},"currency":{"type":"string"},"balanceComparison":{"type":"string","enum":["signed","magnitude"],"description":"How the two ending balances are compared, exactly to the cent: `signed` as stored; `magnitude` (credit cards) by absolute value, the amount owed regardless of sign."},"parity":{"type":"object","additionalProperties":false,"required":["state","reason"],"properties":{"state":{"type":"string","enum":["not_verified","agree","behind","ahead","balance_differs"]},"reason":{"description":"Why the account is not verified; null for every other state.","oneOf":[{"type":"string","enum":["no_snapshot","stale_snapshot","no_completed_reconciliation","median_reconciliation_not_clean","currency_differs","median_statement_balance_missing"]},{"type":"null"}]}}},"snapshot":{"description":"The current snapshot; null when none was recorded.","oneOf":[{"$ref":"#/components/schemas/QuickBooksReconciliationSnapshot"},{"type":"null"}]},"median":{"description":"Median's latest completed reconciliation of the account (by statement ending date); null when none.","oneOf":[{"type":"object","additionalProperties":false,"required":["reconciliationId","statementEndingDate","statementEndingBalanceCents","currency","completedAt","runningDifferenceCents","forceCompleted"],"properties":{"reconciliationId":{"type":"string","format":"uuid"},"statementEndingDate":{"type":"string","format":"date"},"statementEndingBalanceCents":{"type":["integer","null"],"format":"int64"},"currency":{"type":"string"},"completedAt":{"type":["string","null"],"format":"date-time"},"runningDifferenceCents":{"type":["integer","null"],"format":"int64","description":"Median's own running difference for that reconciliation; anything but 0 makes the account not verified."},"forceCompleted":{"type":"boolean","description":"True when that reconciliation was completed over a difference; the account is then not verified."}}},{"type":"null"}]}}},"QuickBooksReconciliationParityView":{"type":"object","additionalProperties":false,"required":["applicable","reason","accounts"],"properties":{"applicable":{"type":"boolean","description":"False when the company's books are not on QuickBooks; `accounts` is then empty."},"reason":{"oneOf":[{"type":"string","enum":["not_quickbooks_customer"]},{"type":"null"}]},"accounts":{"type":"array","items":{"$ref":"#/components/schemas/QuickBooksReconciliationAccountParity"}}}},"StatementBasisInput":{"type":"object","additionalProperties":false,"required":["basis","effectiveDate","reason","approvalReference"],"description":"The approved statement basis to record (#2911). Actor and timestamp are set by the server and are not accepted here.","properties":{"basis":{"type":"string","enum":["cash","accrual"]},"effectiveDate":{"type":"string","format":"date","description":"The basis applies from this day on. Any calendar date."},"reason":{"type":"string","minLength":1,"maxLength":2000},"approvalReference":{"type":"string","minLength":1,"maxLength":500,"description":"Where the approval is recorded, e.g. an issue reference."},"supersedesId":{"type":"string","format":"uuid","description":"The row this one corrects. Must belong to the same client."}}},"StatementBasisEntry":{"type":"object","additionalProperties":false,"required":["id","companyId","basis","effectiveDate","reason","approvalReference","supersedesId","setByUserId","setByActor","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"basis":{"type":"string","enum":["cash","accrual"]},"effectiveDate":{"type":"string","format":"date"},"reason":{"type":"string"},"approvalReference":{"type":"string"},"supersedesId":{"type":["string","null"],"format":"uuid"},"setByUserId":{"type":["string","null"],"format":"uuid","description":"Null for a service principal, which is then named in setByActor."},"setByActor":{"type":"string","description":"Set by the server, e.g. accountant:<accountantId>."},"createdAt":{"type":"string","format":"date-time"}}},"StatementBasisHistory":{"type":"object","required":["asOf","effective","history"],"properties":{"asOf":{"type":"string","format":"date","description":"The date `effective` was resolved on (today, UTC)."},"effective":{"oneOf":[{"$ref":"#/components/schemas/StatementBasisEntry"},{"type":"null"}]},"history":{"type":"array","items":{"$ref":"#/components/schemas/StatementBasisEntry"},"description":"Every row, latest effective first, then latest created."}}},"DocumentForwardingAddressResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","additionalProperties":false,"required":["status","handle","address","domain"],"properties":{"status":{"type":"string","enum":["assigned","name_pending","needs_accountant"],"description":"name_pending while self-serve onboarding has not named the company; needs_accountant when no handle could be generated safely."},"handle":{"type":["string","null"]},"address":{"type":["string","null"],"format":"email","description":"Null while no mail domain is configured, even when a handle exists."},"domain":{"type":["string","null"]}}}}},"OnboardingV3BooksInvitedCompletionData":{"type":"object","additionalProperties":false,"properties":{"granted":{"type":"boolean","const":true},"method":{"type":"string","const":"invited"}},"required":["granted","method"]},"OnboardingV3BooksConnectedCompletionData":{"type":"object","additionalProperties":false,"properties":{"granted":{"type":"boolean","const":true},"method":{"type":"string","const":"connected"},"provider":{"type":"string","enum":["quickbooks","xero"]},"migrationJobId":{"type":"string","format":"uuid"}},"required":["granted","method","provider","migrationJobId"]},"OnboardingV3BooksCompletionData":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3BooksInvitedCompletionData"},{"$ref":"#/components/schemas/OnboardingV3BooksConnectedCompletionData"}],"discriminator":{"propertyName":"method","mapping":{"invited":"#/components/schemas/OnboardingV3BooksInvitedCompletionData","connected":"#/components/schemas/OnboardingV3BooksConnectedCompletionData"}}},"OnboardingV3HistoryCompletionData":{"type":"object","additionalProperties":false,"properties":{"byInstitution":{"$ref":"#/components/schemas/OnboardingV3HistoryByInstitution"}},"required":["byInstitution"]},"OnboardingV3ConnectCompletionPatch":{"type":"object","additionalProperties":false,"properties":{"taskId":{"type":"string","const":"connect"},"task":{"$ref":"#/components/schemas/OnboardingV3DoneSetupTaskState"},"data":{"$ref":"#/components/schemas/OnboardingV3ConnectCompletionData"}},"required":["taskId","task","data"]},"OnboardingV3DocumentsCompletionPatch":{"type":"object","additionalProperties":false,"properties":{"taskId":{"type":"string","const":"documents"},"task":{"$ref":"#/components/schemas/OnboardingV3DoneSetupTaskState"},"data":{"$ref":"#/components/schemas/OnboardingV3DocumentsCompletionData"}},"required":["taskId","task","data"]},"OnboardingV3BooksCompletionPatch":{"type":"object","additionalProperties":false,"properties":{"taskId":{"type":"string","const":"books"},"task":{"$ref":"#/components/schemas/OnboardingV3DoneSetupTaskState"},"data":{"$ref":"#/components/schemas/OnboardingV3BooksCompletionData"}},"required":["taskId","task","data"]},"OnboardingV3HistoryCompletionPatch":{"type":"object","additionalProperties":false,"properties":{"taskId":{"type":"string","const":"history"},"task":{"$ref":"#/components/schemas/OnboardingV3DoneSetupTaskState"},"data":{"$ref":"#/components/schemas/OnboardingV3HistoryCompletionData"}},"required":["taskId","task","data"]},"OnboardingV3ConnectAdministrativePatch":{"type":"object","additionalProperties":false,"minProperties":2,"properties":{"taskId":{"type":"string","const":"connect"},"task":{"$ref":"#/components/schemas/OnboardingV3ProviderOwnershipTaskState"},"deferred":{"type":"array","maxItems":24,"items":{"$ref":"#/components/schemas/OnboardingV3DeferredInput"}}},"required":["taskId"]},"OnboardingV3DocumentsAdministrativePatch":{"type":"object","additionalProperties":false,"minProperties":2,"properties":{"taskId":{"type":"string","const":"documents"},"task":{"$ref":"#/components/schemas/OnboardingV3ProviderOwnershipTaskState"},"deferred":{"type":"array","maxItems":24,"items":{"$ref":"#/components/schemas/OnboardingV3DeferredInput"}}},"required":["taskId"]},"OnboardingV3BooksAdministrativePatch":{"type":"object","additionalProperties":false,"minProperties":2,"properties":{"taskId":{"type":"string","const":"books"},"task":{"$ref":"#/components/schemas/OnboardingV3ProviderOwnershipTaskState"},"deferred":{"type":"array","maxItems":24,"items":{"$ref":"#/components/schemas/OnboardingV3DeferredInput"}}},"required":["taskId"]},"OnboardingV3HistoryAdministrativePatch":{"type":"object","additionalProperties":false,"minProperties":2,"properties":{"taskId":{"type":"string","const":"history"},"task":{"$ref":"#/components/schemas/OnboardingV3ProviderOwnershipTaskState"},"deferred":{"type":"array","maxItems":24,"items":{"$ref":"#/components/schemas/OnboardingV3DeferredInput"}}},"required":["taskId"]},"OnboardingV3ConnectSetupPatch":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3ConnectCompletionPatch"},{"$ref":"#/components/schemas/OnboardingV3ConnectAdministrativePatch"}]},"OnboardingV3DocumentsSetupPatch":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3DocumentsCompletionPatch"},{"$ref":"#/components/schemas/OnboardingV3DocumentsAdministrativePatch"}]},"OnboardingV3BooksSetupPatch":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3BooksCompletionPatch"},{"$ref":"#/components/schemas/OnboardingV3BooksAdministrativePatch"}]},"OnboardingV3HistorySetupPatch":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3HistoryCompletionPatch"},{"$ref":"#/components/schemas/OnboardingV3HistoryAdministrativePatch"}]},"OnboardingV3SetupPatch":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3AuthoritySetupPatch"},{"$ref":"#/components/schemas/OnboardingV3BusinessBasicsSetupPatch"},{"$ref":"#/components/schemas/OnboardingV3ConnectSetupPatch"},{"$ref":"#/components/schemas/OnboardingV3DocumentsSetupPatch"},{"$ref":"#/components/schemas/OnboardingV3BooksSetupPatch"},{"$ref":"#/components/schemas/OnboardingV3HistorySetupPatch"},{"$ref":"#/components/schemas/OnboardingV3GenericSetupPatch"}],"discriminator":{"propertyName":"taskId","mapping":{"authority":"#/components/schemas/OnboardingV3AuthoritySetupPatch","basics":"#/components/schemas/OnboardingV3BusinessBasicsSetupPatch","connect":"#/components/schemas/OnboardingV3ConnectSetupPatch","processors":"#/components/schemas/OnboardingV3GenericSetupPatch","payroll":"#/components/schemas/OnboardingV3GenericSetupPatch","documents":"#/components/schemas/OnboardingV3DocumentsSetupPatch","books":"#/components/schemas/OnboardingV3BooksSetupPatch","history":"#/components/schemas/OnboardingV3HistorySetupPatch"}}},"OnboardingV3HistoryInviteState":{"type":"object","additionalProperties":false,"properties":{"path":{"type":"string","const":"invite"},"inviteSent":{"type":"boolean","const":true},"deferred":{"type":"boolean","const":false},"documentIds":{"type":"array","maxItems":0}},"required":["path","inviteSent","deferred","documentIds"]},"OnboardingV3HistoryUploadState":{"type":"object","additionalProperties":false,"properties":{"path":{"type":"string","const":"upload"},"inviteSent":{"type":"boolean","const":false},"deferred":{"type":"boolean","const":false},"documentIds":{"type":"array","minItems":2,"maxItems":24,"uniqueItems":true,"items":{"type":"string","format":"uuid"}}},"required":["path","inviteSent","deferred","documentIds"]},"OnboardingV3HistoryLaterState":{"type":"object","additionalProperties":false,"properties":{"path":{"type":"string","const":"later"},"inviteSent":{"type":"boolean","const":false},"deferred":{"type":"boolean","const":true},"documentIds":{"type":"array","maxItems":0}},"required":["path","inviteSent","deferred","documentIds"]},"OnboardingV3HistoryInstitutionState":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3HistoryInviteState"},{"$ref":"#/components/schemas/OnboardingV3HistoryUploadState"},{"$ref":"#/components/schemas/OnboardingV3HistoryLaterState"}],"discriminator":{"propertyName":"path","mapping":{"invite":"#/components/schemas/OnboardingV3HistoryInviteState","upload":"#/components/schemas/OnboardingV3HistoryUploadState","later":"#/components/schemas/OnboardingV3HistoryLaterState"}}},"OnboardingV3HistoryByInstitution":{"type":"object","maxProperties":25,"propertyNames":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[A-Za-z0-9][A-Za-z0-9._:-]{0,254}$"},"additionalProperties":{"$ref":"#/components/schemas/OnboardingV3HistoryInstitutionState"}},"OnboardingV3HistoryCheckpoint":{"type":"object","additionalProperties":false,"properties":{"byInstitution":{"$ref":"#/components/schemas/OnboardingV3HistoryCheckpointByInstitution"}},"required":["byInstitution"]},"OnboardingV3HistoryCheckpointInviteState":{"type":"object","additionalProperties":false,"properties":{"path":{"type":"string","const":"invite"},"inviteSent":{"type":"boolean"},"deferred":{"type":"boolean","const":false},"documentIds":{"type":"array","maxItems":0}},"required":["path","inviteSent","deferred","documentIds"]},"OnboardingV3HistoryCheckpointUploadState":{"type":"object","additionalProperties":false,"properties":{"path":{"type":"string","const":"upload"},"inviteSent":{"type":"boolean","const":false},"deferred":{"type":"boolean","const":false},"documentIds":{"type":"array","maxItems":24,"uniqueItems":true,"items":{"type":"string","format":"uuid"}}},"required":["path","inviteSent","deferred","documentIds"]},"OnboardingV3HistoryCheckpointInstitutionState":{"oneOf":[{"$ref":"#/components/schemas/OnboardingV3HistoryCheckpointInviteState"},{"$ref":"#/components/schemas/OnboardingV3HistoryCheckpointUploadState"},{"$ref":"#/components/schemas/OnboardingV3HistoryLaterState"}],"discriminator":{"propertyName":"path","mapping":{"invite":"#/components/schemas/OnboardingV3HistoryCheckpointInviteState","upload":"#/components/schemas/OnboardingV3HistoryCheckpointUploadState","later":"#/components/schemas/OnboardingV3HistoryLaterState"}}},"OnboardingV3HistoryCheckpointByInstitution":{"type":"object","maxProperties":25,"propertyNames":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[A-Za-z0-9][A-Za-z0-9._:-]{0,254}$"},"additionalProperties":{"$ref":"#/components/schemas/OnboardingV3HistoryCheckpointInstitutionState"}},"OnboardingV3SetupState":{"type":"object","additionalProperties":false,"properties":{"companyId":{"type":"string","format":"uuid"},"tasks":{"$ref":"#/components/schemas/OnboardingV3SetupTaskRecord"},"data":{"$ref":"#/components/schemas/OnboardingV3SetupDataRecord"},"deferred":{"type":"array","items":{"$ref":"#/components/schemas/OnboardingV3DeferredItem"}},"updatedAt":{"type":"string","format":"date-time"}},"required":["companyId","tasks","data","deferred","updatedAt"]},"OnboardingV3DelegateSetupState":{"type":"object","additionalProperties":false,"description":"Every tasks, data, and deferred taskId key belongs to the taskIds advertised by the containing delegate view. Incomplete task records are omitted; completed records expose only status and never owner identity.","properties":{"tasks":{"$ref":"#/components/schemas/OnboardingV3DelegateTaskRecord"},"data":{"$ref":"#/components/schemas/OnboardingV3DelegateDataRecord"},"deferred":{"type":"array","items":{"$ref":"#/components/schemas/OnboardingV3DelegateDeferredItem"}},"updatedAt":{"type":"string","format":"date-time"}},"required":["tasks","data","deferred","updatedAt"]},"OnboardingV3SetupStateApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3SetupState"}},"required":["success","data"]},"OnboardingV3DelegateInviteCreate":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string","minLength":2,"maxLength":100,"pattern":"^(?![\\s\\S]*</?[A-Za-z][^>]*>)[\\s\\S]*$"},"email":{"type":"string","format":"email","maxLength":254}},"required":["name","email"]},"OnboardingV3DelegateResolve":{"type":"object","additionalProperties":false,"properties":{"token":{"type":"string"}},"required":["token"]},"OnboardingV3DelegatePatch":{"type":"object","description":"The task must belong to the resolved capability's current server-owned assignment subset. Other valid setup task IDs return the same 404 shape as an unknown capability.","additionalProperties":false,"properties":{"token":{"type":"string"},"taskId":{"$ref":"#/components/schemas/OnboardingV3SetupTaskId"},"task":{"$ref":"#/components/schemas/OnboardingV3DelegateTaskState"},"data":{"$ref":"#/components/schemas/OnboardingV3SetupDataSlice"},"deferred":{"type":"array","maxItems":24,"items":{"$ref":"#/components/schemas/OnboardingV3DeferredInput"}}},"required":["token","taskId"],"anyOf":[{"required":["task"]},{"required":["data"]},{"required":["deferred"]}],"allOf":[{"$ref":"#/components/schemas/OnboardingV3PayrollPatchConstraint"}]},"OnboardingV3DelegateTaskState":{"type":"object","additionalProperties":false,"properties":{"status":{"type":"string","const":"done"}},"required":["status"]},"OnboardingV3DelegateInviteCreateResult":{"description":"A newly minted capability is returned once with its URL. An identical live retry returns the current public invite without exposing that capability again.","oneOf":[{"$ref":"#/components/schemas/OnboardingV3DelegateInviteCreated"},{"$ref":"#/components/schemas/OnboardingV3DelegateInviteReused"}],"discriminator":{"propertyName":"reused","mapping":{"false":"#/components/schemas/OnboardingV3DelegateInviteCreated","true":"#/components/schemas/OnboardingV3DelegateInviteReused"}}},"OnboardingV3DelegateInviteCreated":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","minLength":1,"maxLength":100},"email":{"type":"string","format":"email","maxLength":254},"taskIds":{"type":"array","items":{"$ref":"#/components/schemas/OnboardingV3DelegatedTaskId"}},"status":{"type":"string","enum":["sent","opened","revoked","done"]},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"reused":{"type":"boolean","const":false},"delegateUrl":{"type":"string","format":"uri","description":"Returned once for a newly minted invite; contains the raw capability."}},"required":["id","name","email","taskIds","status","createdAt","expiresAt","reused","delegateUrl"]},"OnboardingV3DelegateInviteReused":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","minLength":1,"maxLength":100},"email":{"type":"string","format":"email","maxLength":254},"taskIds":{"type":"array","items":{"$ref":"#/components/schemas/OnboardingV3DelegatedTaskId"}},"status":{"type":"string","enum":["sent","opened","revoked","done"]},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"reused":{"type":"boolean","const":true,"description":"An identical live invite was reused without sending email."}},"required":["id","name","email","taskIds","status","createdAt","expiresAt","reused"]},"OnboardingV3DelegateView":{"type":"object","additionalProperties":false,"description":"The state collections are a strict subset of taskIds; recipient identity, invite identifiers, and task owners are never returned.","properties":{"taskIds":{"type":"array","maxItems":4,"uniqueItems":true,"items":{"$ref":"#/components/schemas/OnboardingV3DelegatedTaskId"}},"state":{"$ref":"#/components/schemas/OnboardingV3DelegateSetupState"}},"required":["taskIds","state"]},"OnboardingV3DelegateInviteApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3DelegateInviteCreateResult"}},"required":["success","data"]},"OnboardingV3DelegateViewApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3DelegateView"}},"required":["success","data"]},"OnboardingV3DelegateRevokedApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":false,"properties":{"revoked":{"type":"boolean","const":true}},"required":["revoked"]}},"required":["success","data"]},"OnboardingV3InboundAlias":{"anyOf":[{"type":"string","format":"email","maxLength":320},{"type":"null"}]},"OnboardingV3TaskContextBankAccount":{"type":"object","additionalProperties":false,"properties":{"bankAccountId":{"type":"string","format":"uuid"},"integrationId":{"type":"string","format":"uuid"},"name":{"type":"string","minLength":1,"maxLength":255},"type":{"anyOf":[{"type":"string","enum":["checking","savings","credit","investment","processor"]},{"type":"null"}]},"mask":{"anyOf":[{"type":"string","minLength":1,"maxLength":64},{"type":"null"}]},"balanceCents":{"type":["integer","null"]},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"institutionName":{"type":"string","minLength":1,"maxLength":255},"isPersonal":{"type":"boolean"}},"required":["bankAccountId","integrationId","name","type","mask","balanceCents","currency","institutionName","isPersonal"]},"OnboardingV3OwnerConnectContext":{"type":"object","additionalProperties":false,"description":"integrationIds is the unique set of integrationId values represented by accounts. committedIntegrationIds are ordinary active Plaid connections and already-classified onboarding connections. pendingIntegrationIds are the exact held connections whose encrypted token metadata has onboardingManaged and onboardingClassificationPending set to true. The committed and pending arrays are disjoint and partition integrationIds.","properties":{"accounts":{"type":"array","maxItems":250,"items":{"$ref":"#/components/schemas/OnboardingV3TaskContextBankAccount"}},"integrationIds":{"type":"array","maxItems":25,"uniqueItems":true,"items":{"type":"string","format":"uuid"}},"committedIntegrationIds":{"type":"array","maxItems":25,"uniqueItems":true,"items":{"type":"string","format":"uuid"}},"pendingIntegrationIds":{"type":"array","maxItems":25,"uniqueItems":true,"items":{"type":"string","format":"uuid"}}},"required":["accounts","integrationIds","committedIntegrationIds","pendingIntegrationIds"]},"OnboardingV3GoogleWorkspaceContext":{"type":"object","additionalProperties":false,"properties":{"available":{"type":"boolean"},"connected":{"type":"boolean"}},"required":["available","connected"]},"OnboardingV3OwnerDocumentsContext":{"type":"object","additionalProperties":false,"properties":{"inboundAlias":{"$ref":"#/components/schemas/OnboardingV3InboundAlias"},"googleWorkspace":{"$ref":"#/components/schemas/OnboardingV3GoogleWorkspaceContext"}},"required":["inboundAlias","googleWorkspace"]},"OnboardingV3DelegateBooksContext":{"type":"object","additionalProperties":false,"properties":{"accountingSystemId":{"anyOf":[{"type":"string","enum":["quickbooks","xero"]},{"type":"null"}]},"inboundAlias":{"$ref":"#/components/schemas/OnboardingV3InboundAlias"},"method":{"type":"string","const":"invite"}},"required":["accountingSystemId","inboundAlias","method"]},"OnboardingV3BooksOAuthContext":{"type":"object","additionalProperties":false,"properties":{"available":{"type":"boolean"},"connected":{"type":"boolean"},"migrationJobId":{"type":["string","null"],"format":"uuid"}},"required":["available","connected","migrationJobId"]},"OnboardingV3OwnerBooksContext":{"type":"object","additionalProperties":false,"properties":{"accountingSystemId":{"anyOf":[{"type":"string","enum":["quickbooks","xero"]},{"type":"null"}]},"inboundAlias":{"$ref":"#/components/schemas/OnboardingV3InboundAlias"},"method":{"type":"string","const":"invite"},"ledger":{"description":"#2560: QBO source-ledger facts for prepared quickbooks engagements; null otherwise.","oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"properties":{"status":{"type":"string","enum":["not_connected","connected","realm_mismatch","needs_reauth"]},"verification":{"type":["string","null"],"enum":["verified","unverified","realm_mismatch",null]},"companyName":{"type":["string","null"]},"connectionId":{"type":["string","null"],"format":"uuid"},"accountantAccess":{"oneOf":[{"type":"null"},{"type":"object","additionalProperties":false,"properties":{"source":{"type":"string"},"verifiedOn":{"type":"string"}},"required":["source","verifiedOn"]}]}},"required":["status","verification","companyName","connectionId","accountantAccess"]}]},"oauth":{"$ref":"#/components/schemas/OnboardingV3BooksOAuthContext"}},"required":["accountingSystemId","inboundAlias","method","oauth"]},"OnboardingV3HistoryInstitutionContext":{"type":"object","additionalProperties":false,"description":"haveFrom and haveTo are the conservative common window across every included non-personal account (maximum start and minimum end), and are both null when any account lacks a complete overlapping window. coveredAccountCount counts accounts whose feed reaches needFrom, or all accounts when an invite was sent or two distinct parsed statements provide alternate coverage. feedCovered is true only when every account has live transaction coverage reaching needFrom. covered also includes authoritative invite or statement evidence.","properties":{"institutionId":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[A-Za-z0-9][A-Za-z0-9._:-]{0,254}$"},"institutionName":{"type":"string","minLength":1,"maxLength":255},"needFrom":{"type":"string","format":"date"},"needTo":{"type":"string","format":"date"},"haveFrom":{"type":["string","null"],"format":"date"},"haveTo":{"type":["string","null"],"format":"date"},"accountCount":{"type":"integer","minimum":1,"maximum":250},"coveredAccountCount":{"type":"integer","minimum":0,"maximum":250},"transactionCount":{"type":"integer","minimum":0},"inviteSent":{"type":"boolean"},"statementCount":{"type":"integer","minimum":0},"feedCovered":{"type":"boolean"},"covered":{"type":"boolean"}},"required":["institutionId","institutionName","needFrom","needTo","haveFrom","haveTo","accountCount","coveredAccountCount","transactionCount","inviteSent","statementCount","feedCovered","covered"]},"OnboardingV3OwnerHistoryContext":{"type":"object","additionalProperties":false,"properties":{"inboundAlias":{"$ref":"#/components/schemas/OnboardingV3InboundAlias"},"institutions":{"type":"array","maxItems":25,"items":{"$ref":"#/components/schemas/OnboardingV3HistoryInstitutionContext"}}},"required":["inboundAlias","institutions"]},"OnboardingV3OwnerTaskContext":{"type":"object","additionalProperties":false,"properties":{"connect":{"$ref":"#/components/schemas/OnboardingV3OwnerConnectContext"},"documents":{"$ref":"#/components/schemas/OnboardingV3OwnerDocumentsContext"},"books":{"$ref":"#/components/schemas/OnboardingV3OwnerBooksContext"},"history":{"$ref":"#/components/schemas/OnboardingV3OwnerHistoryContext"},"prepared":{"description":"Accountant-prepared engagement view (#2560); null for default companies.","oneOf":[{"$ref":"#/components/schemas/PreparedOnboardingProfileView"},{"type":"null"}]},"processors":{"type":"object","additionalProperties":false,"properties":{"stripe":{"type":"object","additionalProperties":false,"properties":{"status":{"type":"string","enum":["not_attempted","connected","help_needed"]},"detail":{"type":["string","null"]}},"required":["status","detail"]}},"required":["stripe"]}},"required":["connect","documents","books","history","prepared","processors"]},"OnboardingV3OwnerTaskContextApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3OwnerTaskContext"}},"required":["success","data"]},"OnboardingV3DelegateTaskContextRequest":{"type":"object","additionalProperties":false,"properties":{"token":{"type":"string","pattern":"^[A-Za-z0-9_-]{43}$"}},"required":["token"]},"OnboardingV3DelegateDocumentsContext":{"type":"object","additionalProperties":false,"properties":{"inboundAlias":{"$ref":"#/components/schemas/OnboardingV3InboundAlias"}},"required":["inboundAlias"]},"OnboardingV3DelegateHistoryContext":{"type":"object","additionalProperties":false,"description":"Owner-only account, institution, upload, and coverage data is omitted.","properties":{"inboundAlias":{"$ref":"#/components/schemas/OnboardingV3InboundAlias"},"allowedMethods":{"type":"array","minItems":2,"maxItems":2,"prefixItems":[{"type":"string","const":"invite"},{"type":"string","const":"later"}]},"uploadsAvailable":{"type":"boolean","const":false}},"required":["inboundAlias","allowedMethods","uploadsAvailable"]},"OnboardingV3DelegateTaskContext":{"type":"object","additionalProperties":false,"properties":{"documents":{"$ref":"#/components/schemas/OnboardingV3DelegateDocumentsContext"},"books":{"$ref":"#/components/schemas/OnboardingV3DelegateBooksContext"},"history":{"$ref":"#/components/schemas/OnboardingV3DelegateHistoryContext"}}},"OnboardingV3DelegateTaskContextApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3DelegateTaskContext"}},"required":["success","data"]},"OnboardingV3RedirectUri":{"type":"string","format":"uri","maxLength":2048},"OnboardingV3PlaidLinkTokenRequest":{"type":"object","additionalProperties":false,"properties":{"redirectUri":{"$ref":"#/components/schemas/OnboardingV3RedirectUri"}},"required":["redirectUri"]},"OnboardingV3PlaidLinkToken":{"type":"object","additionalProperties":false,"properties":{"linkToken":{"type":"string","minLength":1,"maxLength":4096},"expiration":{"type":"string","format":"date-time"},"authorizationState":{"type":"string","minLength":1,"maxLength":8192},"authorizationExpiresAt":{"type":"string","format":"date-time"}},"required":["linkToken","expiration","authorizationState","authorizationExpiresAt"]},"OnboardingV3PlaidLinkTokenApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3PlaidLinkToken"}},"required":["success","data"]},"OnboardingV3PlaidExchangeRequest":{"type":"object","additionalProperties":false,"properties":{"publicToken":{"type":"string","minLength":1,"maxLength":4096},"institutionId":{"type":"string","minLength":1,"maxLength":255},"state":{"type":"string","minLength":1,"maxLength":8192},"redirectUri":{"$ref":"#/components/schemas/OnboardingV3RedirectUri"}},"required":["publicToken","institutionId","state","redirectUri"]},"OnboardingV3PlaidAccount":{"type":"object","additionalProperties":false,"properties":{"bankAccountId":{"type":"string","format":"uuid"},"name":{"type":"string","minLength":1,"maxLength":255},"type":{"anyOf":[{"type":"string","enum":["checking","savings","credit","investment"]},{"type":"null"}]},"mask":{"type":["string","null"]},"balanceCents":{"type":["integer","null"]},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"institutionName":{"type":"string","minLength":1,"maxLength":255},"isPersonal":{"type":"boolean"}},"required":["bankAccountId","name","type","mask","balanceCents","currency","institutionName","isPersonal"]},"OnboardingV3PlaidExchange":{"type":"object","additionalProperties":false,"properties":{"integrationId":{"type":"string","format":"uuid"},"accounts":{"type":"array","minItems":1,"maxItems":250,"items":{"$ref":"#/components/schemas/OnboardingV3PlaidAccount"}}},"required":["integrationId","accounts"]},"OnboardingV3PlaidExchangeApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3PlaidExchange"}},"required":["success","data"]},"OnboardingV3PlaidAccountClassification":{"type":"object","additionalProperties":false,"properties":{"bankAccountId":{"type":"string","format":"uuid"},"isPersonal":{"type":"boolean"}},"required":["bankAccountId","isPersonal"]},"OnboardingV3PlaidCommitRequest":{"type":"object","additionalProperties":false,"description":"Every live account must appear once, and at least one account must remain in the business books.","properties":{"integrationId":{"type":"string","format":"uuid"},"accounts":{"type":"array","minItems":1,"maxItems":250,"uniqueItems":true,"items":{"$ref":"#/components/schemas/OnboardingV3PlaidAccountClassification"}}},"required":["integrationId","accounts"]},"OnboardingV3PlaidCommit":{"type":"object","additionalProperties":false,"properties":{"integrationId":{"type":"string","format":"uuid"},"accounts":{"type":"array","minItems":1,"maxItems":250,"items":{"$ref":"#/components/schemas/OnboardingV3PlaidAccount"}},"syncJobId":{"type":["string","null"],"format":"uuid"}},"required":["integrationId","accounts","syncJobId"]},"OnboardingV3PlaidCommitApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3PlaidCommit"}},"required":["success","data"]},"OnboardingV3GoogleAuthorizationRequest":{"type":"object","additionalProperties":false,"properties":{"redirectUri":{"$ref":"#/components/schemas/OnboardingV3RedirectUri"}},"required":["redirectUri"]},"OnboardingV3GoogleAuthorization":{"type":"object","additionalProperties":false,"properties":{"authorizationUrl":{"type":"string","format":"uri","maxLength":4096}},"required":["authorizationUrl"]},"OnboardingV3GoogleAuthorizationApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3GoogleAuthorization"}},"required":["success","data"]},"OnboardingV3GoogleCallbackRequest":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","minLength":1,"maxLength":4096},"state":{"type":"string","minLength":1,"maxLength":8192},"redirectUri":{"$ref":"#/components/schemas/OnboardingV3RedirectUri"}},"required":["code","state","redirectUri"]},"OnboardingV3GoogleCallback":{"type":"object","additionalProperties":false,"properties":{"integrationId":{"type":"string","format":"uuid"},"syncJobId":{"type":["string","null"],"format":"uuid"}},"required":["integrationId","syncJobId"]},"OnboardingV3GoogleCallbackApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3GoogleCallback"}},"required":["success","data"]},"OnboardingV3BooksAuthorizationRequest":{"type":"object","additionalProperties":false,"properties":{"redirectUri":{"$ref":"#/components/schemas/OnboardingV3RedirectUri"}},"required":["redirectUri"]},"OnboardingV3BooksAuthorization":{"type":"object","additionalProperties":false,"properties":{"authorizationUrl":{"type":"string","format":"uri","maxLength":4096}},"required":["authorizationUrl"]},"OnboardingV3BooksAuthorizationApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3BooksAuthorization"}},"required":["success","data"]},"OnboardingV3QuickBooksCallbackRequest":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","minLength":1,"maxLength":4096},"state":{"type":"string","minLength":1,"maxLength":8192},"redirectUri":{"$ref":"#/components/schemas/OnboardingV3RedirectUri"},"realmId":{"type":"string","pattern":"^[0-9]{1,32}$"}},"required":["code","state","redirectUri","realmId"]},"OnboardingV3XeroCallbackRequest":{"type":"object","additionalProperties":false,"properties":{"code":{"type":"string","minLength":1,"maxLength":4096},"state":{"type":"string","minLength":1,"maxLength":8192},"redirectUri":{"$ref":"#/components/schemas/OnboardingV3RedirectUri"}},"required":["code","state","redirectUri"]},"OnboardingV3BooksMigration":{"type":"object","additionalProperties":false,"properties":{"migrationJobId":{"type":"string","format":"uuid"}},"required":["migrationJobId"]},"OnboardingV3BooksMigrationApiResponse":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/OnboardingV3BooksMigration"}},"required":["success","data"]},"AttributionMatchedClient":{"type":"object","description":"A per-customer acquisition row (ad click and analytics visitor joined to booked revenue).","properties":{"client":{"type":"string"},"campaign":{"type":["string","null"]},"gclid":{"type":["string","null"]},"gaClientId":{"type":"string"},"signedOn":{"type":["string","null"]},"firstValueCents":{"type":"integer"},"ltvCents":{"type":"integer"}},"required":["client","gaClientId","firstValueCents","ltvCents"]},"AttributionChannel":{"type":"object","description":"A per-channel attribution row. Organic channels have zero spend and a null roas.","properties":{"id":{"type":"string"},"channel":{"type":"string"},"source":{"type":["string","null"]},"medium":{"type":["string","null"]},"paid":{"type":"boolean"},"spendCents":{"type":"integer"},"leads":{"type":"integer"},"clients":{"type":"integer"},"firstYearValueCents":{"type":"integer"},"cacCents":{"type":["integer","null"]},"roas":{"type":["number","null"]},"matched":{"type":"array","items":{"$ref":"#/components/schemas/AttributionMatchedClient"}}},"required":["id","channel","paid","spendCents","clients","matched"]},"AttributionTotals":{"type":"object","description":"KPI-strip totals. paybackMonths and avgClientLtvCents are estimates (see economicsBasis).","properties":{"spendCents":{"type":"integer"},"clients":{"type":"integer"},"blendedCacCents":{"type":["integer","null"]},"ltvCac":{"type":["number","null"]},"paidRoas":{"type":["number","null"]},"paybackMonths":{"type":["number","null"]},"avgClientLtvCents":{"type":"integer"},"economicsBasis":{"type":"string"}},"required":["spendCents","clients","avgClientLtvCents","economicsBasis"]},"AttributionReallocation":{"type":"object","description":"Budget-reallocation insight; present only when best and worst paid channels differ.","properties":{"fromChannel":{"type":"string"},"toChannel":{"type":"string"},"fromRoas":{"type":"number"},"toRoas":{"type":"number"},"suggestedShiftCents":{"type":"integer"},"projectedBlendedRoasDelta":{"type":"number"}},"required":["fromChannel","toChannel","suggestedShiftCents"]},"AttributionMarketingSource":{"type":"object","properties":{"provider":{"type":"string"},"status":{"type":"string"},"connectedAt":{"type":["string","null"]},"lastSyncedAt":{"type":["string","null"]}},"required":["provider","status"]},"AttributionResult":{"type":"object","properties":{"period":{"type":"string","enum":["mtd","t90"]},"channels":{"type":"array","items":{"$ref":"#/components/schemas/AttributionChannel"}},"totals":{"$ref":"#/components/schemas/AttributionTotals"},"reallocation":{"oneOf":[{"$ref":"#/components/schemas/AttributionReallocation"},{"type":"null"}]},"sources":{"type":"array","items":{"$ref":"#/components/schemas/AttributionMarketingSource"}},"hasConnectedSource":{"type":"boolean"}},"required":["period","channels","totals","sources","hasConnectedSource"]},"CustomPricingOffer":{"type":"object","additionalProperties":false,"description":"A sales-led custom pricing offer keyed by email.","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"monthlyPriceCents":{"type":"integer","minimum":1,"maximum":100000000},"monthlyPriceDollars":{"type":"integer","minimum":1,"maximum":1000000},"trialDays":{"type":"integer","minimum":0,"maximum":365},"billingInterval":{"type":"string","enum":["month","year"]},"allowMonthly":{"type":"boolean"},"chargedAmountCents":{"type":"integer","minimum":1,"description":"Charged per billing interval at the offer's own interval (annual = monthly x 10)."},"termStart":{"type":["string","null"],"format":"date","description":"First day of the customer's paid period once redeemed; null before payment."},"termEnd":{"type":["string","null"],"format":"date","description":"Last day of the customer's paid period once redeemed; null before payment."},"paidBillingInterval":{"type":["string","null"],"enum":["month","year",null],"description":"Interval the customer actually pays once redeemed (may be month on an annual offer)."},"paidAmountCents":{"type":["integer","null"],"description":"Amount the customer is charged per paid interval once redeemed."},"status":{"type":"string","enum":["active","redeemed","void"]},"note":{"type":["string","null"]},"createdByEmail":{"type":["string","null"]},"companyId":{"type":["string","null"],"format":"uuid"},"redeemedAt":{"type":["string","null"],"format":"date-time"},"expiresAt":{"type":["string","null"],"format":"date-time"},"offerUrl":{"type":["string","null"],"format":"uri"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","email","monthlyPriceCents","monthlyPriceDollars","trialDays","billingInterval","allowMonthly","chargedAmountCents","status","note","createdByEmail","companyId","redeemedAt","expiresAt","offerUrl","createdAt","updatedAt"]},"BooksOverviewSegment":{"type":"object","description":"A single line-item segment inside an assets or liabilities breakdown. `amountCents` is always a non-negative integer.\n","required":["label","amountCents"],"properties":{"label":{"type":"string"},"amountCents":{"type":"integer","minimum":0}}},"BooksOverviewSparkPoint":{"type":"object","description":"One month's P&L data for the spark-line chart.","required":["month","revenueCents","expensesCents","netCents"],"properties":{"month":{"type":"string","description":"YYYY-MM-DD (first of month)"},"revenueCents":{"type":"integer"},"expensesCents":{"type":"integer"},"netCents":{"type":"integer"}}},"BooksOverview":{"type":"object","description":"Headline financial overview for the Books hub: balances as of today, revenue and expenses for the last completed calendar month. All monetary amounts are integers in **cents**.\nAsset segments are total assets by class (cash, what clients owe you, prepaid costs, inventory, equipment after depreciation, other), from posted entity-scoped report values; the service never derives an asset from a payable balance.\n","required":["companyId","entityId","asOf","lastFullMonthLabel","netLastMonthCents","assets","liabilities","revenue","expenses"],"properties":{"companyId":{"type":"string","format":"uuid","description":"Authenticated company whose Books data was read."},"entityId":{"type":"string","format":"uuid","description":"Authorized concrete legal entity whose Books data was read."},"asOf":{"type":"string","format":"date","description":"Today (UTC). Balances include every posting through the current month."},"lastFullMonthLabel":{"type":"string","description":"Human-readable label for the last completed calendar month (e.g. \"May 2026\")."},"netLastMonthCents":{"type":"integer","description":"Net income for the last completed month in cents (full P&L revenue − expenses)."},"assets":{"type":"object","required":["netBookValueCents","segments"],"properties":{"totalAssetsCents":{"type":"integer","description":"Total balance-sheet assets as of today, in cents (the hub's Assets value)."},"netBookValueCents":{"type":"integer","description":"Fixed-asset net book value (cost − accumulated depreciation) as of today, in cents. Ties out to the Assets page headline and the balance-sheet fixed-asset section, NOT to total balance-sheet assets.\n"},"segments":{"type":"array","items":{"$ref":"#/components/schemas/BooksOverviewSegment"}}}},"liabilities":{"type":"object","required":["totalCents","segments"],"properties":{"totalCents":{"type":"integer","description":"Total liabilities as of today, in cents."},"equityCents":{"type":"integer","description":"Balance-sheet equity as of today, including earnings not yet closed (#1994). The liabilities segments end with an \"Equity\" segment when it is positive."},"segments":{"type":"array","items":{"$ref":"#/components/schemas/BooksOverviewSegment"}}}},"revenue":{"type":"object","required":["recognizedLastMonthCents","deferredCarryingCents","sparkSeries"],"properties":{"recognizedLastMonthCents":{"type":"integer","description":"Operating revenue recognized in the last completed month, in cents (other income and 4999 Uncategorized Income excluded)."},"deferredCarryingCents":{"type":"integer","description":"Outstanding deferred-revenue liability carrying balance as of today, in cents (unearned revenue still to be recognized).\n"},"sparkSeries":{"type":"array","items":{"$ref":"#/components/schemas/BooksOverviewSparkPoint"}}}},"expenses":{"type":"object","required":["recognizedLastMonthCents","topCategoryCents","sparkSeries"],"properties":{"recognizedLastMonthCents":{"type":"integer","description":"Total expenses in the last closed month, in cents."},"topCategoryCents":{"type":"integer","description":"Largest single expense category recognized in the last completed month, in cents.\n"},"largestAccount":{"type":["object","null"],"description":"The single expense account with the largest amount in the last completed month.","required":["name","amountCents"],"properties":{"name":{"type":"string"},"amountCents":{"type":"integer"}}},"sparkSeries":{"type":"array","items":{"$ref":"#/components/schemas/BooksOverviewSparkPoint"}}}}}},"RecognitionScheduleEntry":{"type":"object","description":"A single period entry in a recognition or amortization schedule.","required":["periodIndex","label","amountCents","cumulativeCents","posted","date"],"properties":{"periodIndex":{"type":"integer","minimum":1,"description":"1-based sequence number."},"label":{"type":"string","description":"Human-readable label for this period (e.g. \"Period 1\")."},"amountCents":{"type":"integer","description":"Amount recognised/amortized in this period, in cents."},"cumulativeCents":{"type":"integer","description":"Running cumulative total through this period, in cents."},"posted":{"type":"boolean","description":"Whether the corresponding journal entry has been posted."},"date":{"type":"string","format":"date","description":"Scheduled date for this period (ISO YYYY-MM-DD)."}}},"RecognitionSchedule":{"description":"Recognition or amortization schedule for a document/contract line.\nWhen `immediate` is `true`, entity-keyed schedule authority proves the document recognises in full in the period it was received. When `scheduleType` and `schedule` are populated, a persisted schedule exists. When `status` is present, nothing proves either, and no recognition timing is claimed.\n","oneOf":[{"type":"object","description":"Immediate full recognition — no schedule.","required":["companyId","entityId","immediate"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"immediate":{"type":"boolean","enum":[true]}}},{"type":"object","description":"Multi-period recognition or amortization schedule.","required":["companyId","entityId","scheduleType","schedule"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"scheduleType":{"type":"string","enum":["prepaid_amortization","deferred_revenue_recognition","depreciation","operating_lease_payment","finance_lease_payment"]},"schedule":{"type":"array","items":{"$ref":"#/components/schemas/RecognitionScheduleEntry"}}}},{"type":"object","description":"No persisted schedule and no authority proving immediate recognition.","required":["companyId","entityId","status","reason"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["not_scheduled","unavailable"]},"reason":{"type":"string","enum":["document_not_found","no_business_event","schedule_authority_not_entity_scoped"]}}}]},"MetricSourceRef":{"type":"object","required":["type","id","label"],"properties":{"type":{"type":"string","enum":["overview","report","aging","marketing","stripe","document","transaction","manual"]},"id":{"type":"string"},"label":{"type":"string"}}},"MetricQualityFlag":{"type":"object","required":["type","severity","message"],"properties":{"type":{"type":"string","enum":["reconciliation_gap","outlier_dampened","marketing_attribution_gap","platform_reporting_only"]},"severity":{"type":"string","enum":["info","warning"]},"message":{"type":"string","example":"Numbers are still settling — your accountant is working on it"},"metadata":{"type":"object","additionalProperties":true}}},"MetricSeriesPoint":{"type":"object","required":["date","value"],"properties":{"date":{"type":"string","format":"date"},"value":{"type":"number"},"originalValue":{"type":"number"},"annotations":{"type":"array","items":{"$ref":"#/components/schemas/MetricQualityFlag"}}}},"InsightMetric":{"type":"object","required":["key","label","value","unit","delta","series","sourceRefs","qualityFlags","computedAt","staleness","unavailableReason"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"value":{"oneOf":[{"type":"number"},{"type":"object","additionalProperties":true},{"type":"null"}]},"unit":{"type":"string","enum":["usd","cents","months","percent","count","days","ratio","object"]},"delta":{"type":["number","null"]},"series":{"type":"array","items":{"$ref":"#/components/schemas/MetricSeriesPoint"}},"sourceRefs":{"type":"array","items":{"$ref":"#/components/schemas/MetricSourceRef"}},"qualityFlags":{"type":"array","items":{"$ref":"#/components/schemas/MetricQualityFlag"}},"computedAt":{"type":"string","format":"date-time"},"staleness":{"type":"string","enum":["fresh","stale","unavailable"]},"unavailableReason":{"type":["string","null"]}}},"InsightsBundle":{"type":"object","required":["companyId","entityId","period","industry","computedAt","metrics"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"period":{"type":"object","required":["startDate","endDate","label"],"properties":{"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"label":{"type":"string"}}},"industry":{"type":["string","null"]},"computedAt":{"type":"string","format":"date-time"},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/InsightMetric"}}}},"InsightsBundleResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/InsightsBundle"}}},"InsightAskInput":{"type":"object","required":["question"],"properties":{"question":{"type":"string","minLength":3,"maxLength":1000},"period":{"type":"string","enum":["last_30_days","last_90_days","month_to_date"]},"industry":{"type":"string","minLength":1,"maxLength":80},"parentAskId":{"type":"string","format":"uuid"}}},"InsightAskAnswer":{"type":"object","required":["companyId","entityId","question","answer","confidence","metricKeys","sourceRefs","computedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"question":{"type":"string"},"answer":{"type":"string"},"confidence":{"type":["number","null"],"minimum":0,"maximum":100},"metricKeys":{"type":"array","items":{"type":"string"}},"sourceRefs":{"type":"array","items":{"$ref":"#/components/schemas/MetricSourceRef"}},"computedAt":{"type":"string","format":"date-time"}}},"InsightAskRecord":{"type":"object","required":["id","companyId","entityId","askedBy","question","answer","status","answeredAt","model","promptTokens","completionTokens","costCents","error","sourceRefs","parentAskId","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"askedBy":{"type":["string","null"],"format":"uuid"},"question":{"type":"string"},"answer":{"type":["string","null"]},"status":{"type":"string","enum":["pending","answered","failed","rate_limited"]},"answeredAt":{"type":["string","null"],"format":"date-time"},"model":{"type":["string","null"]},"promptTokens":{"type":["integer","null"],"minimum":0},"completionTokens":{"type":["integer","null"],"minimum":0},"costCents":{"type":["integer","null"],"minimum":0},"error":{"type":["string","null"]},"sourceRefs":{"type":"array","items":{"$ref":"#/components/schemas/MetricSourceRef"}},"parentAskId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"InsightAskAnswerResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/InsightAskAnswer"}}},"InsightAskRecordResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/InsightAskRecord"}}},"InsightAskListResponse":{"type":"object","required":["success","data","meta"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/InsightAskRecord"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"IntelligenceQualityState":{"type":"string","enum":["ready","stale","low_confidence","blocked"]},"IntelligenceHomeCurationItem":{"type":"object","required":["kind","key","title","rationale","priority","sourceRefs"],"properties":{"kind":{"type":"string","enum":["metric","report"]},"key":{"type":"string"},"title":{"type":"string"},"rationale":{"type":"string"},"priority":{"type":"integer","minimum":1,"maximum":7},"sourceRefs":{"type":"array","items":{"$ref":"#/components/schemas/MetricSourceRef"}}}},"IntelligenceHomeCuration":{"type":"object","required":["companyId","entityId","periodStart","periodEnd","periodLabel","status","selectedItems","rationale","sourceRefs","inputHash","promptVersion","model","validationIssues","validationErrors","validationWarnings","supersedesCurationId","reviewDecision","reviewerType","reviewedAt","reviewModel","reviewReasons","reviewBlockers","generatedAt","promotedAt"],"properties":{"id":{"type":"string"},"companyId":{"type":"string"},"entityId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"periodLabel":{"type":"string"},"status":{"type":"string","enum":["draft","active","archived"]},"selectedItems":{"type":"array","minItems":3,"maxItems":7,"items":{"$ref":"#/components/schemas/IntelligenceHomeCurationItem"}},"rationale":{"type":"string"},"sourceRefs":{"type":"array","items":{"$ref":"#/components/schemas/MetricSourceRef"}},"inputHash":{"type":"string"},"promptVersion":{"type":"string","example":"intelligence-home-v2"},"model":{"type":["string","null"],"example":"deterministic-curator"},"validationIssues":{"type":"array","items":{"type":"object","required":["code","severity","message","owner"],"properties":{"code":{"type":"string"},"severity":{"type":"string","enum":["blocking","warning"]},"message":{"type":"string"},"owner":{"type":"string","enum":["system","integrations","accounting","attribution","ai_review"]},"sourceKey":{"type":["string","null"]}}}},"validationErrors":{"type":"array","items":{"type":"string"}},"validationWarnings":{"type":"array","items":{"type":"string"}},"supersedesCurationId":{"type":["string","null"]},"reviewDecision":{"type":["string","null"],"enum":["approved","needs_review","blocked",null]},"reviewerType":{"type":["string","null"],"enum":["ai_assisted_system",null]},"reviewedAt":{"type":["string","null"],"format":"date-time"},"reviewModel":{"type":["string","null"]},"reviewReasons":{"type":"array","items":{"type":"string"}},"reviewBlockers":{"type":"array","items":{"type":"string"}},"generatedAt":{"type":"string","format":"date-time"},"promotedAt":{"type":["string","null"],"format":"date-time"}}},"IntelligenceHomeSignal":{"type":"object","required":["key","metricKey","label","value","unit","period","comparison","qualityState","sourceRefs","rationale"],"properties":{"key":{"type":"string"},"metricKey":{"type":"string"},"label":{"type":"string"},"value":{"oneOf":[{"type":"number"},{"type":"object","additionalProperties":true},{"type":"null"}]},"unit":{"type":"string"},"period":{"type":"object","additionalProperties":true},"comparison":{"type":"object","properties":{"delta":{"type":["number","null"]},"label":{"type":["string","null"]}}},"qualityState":{"$ref":"#/components/schemas/IntelligenceQualityState"},"sourceRefs":{"type":"array","items":{"$ref":"#/components/schemas/MetricSourceRef"}},"rationale":{"type":"string"},"unavailableReason":{"type":["string","null"]},"qualityMessages":{"type":"array","items":{"type":"string"}}}},"IntelligenceHomeReport":{"type":"object","required":["key","title","description","path","qualityState","rationale","sourceRefs"],"properties":{"key":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"path":{"type":["string","null"]},"qualityState":{"$ref":"#/components/schemas/IntelligenceQualityState"},"rationale":{"type":"string"},"sourceRefs":{"type":"array","items":{"$ref":"#/components/schemas/MetricSourceRef"}}}},"IntelligenceHomeBrief":{"type":"object","required":["title","primaryDecision","whatChanged","whyItMatters","nextAction","confidence","confidenceLabel","sourceRefs","supportingSignals","missingData"],"properties":{"title":{"type":"string","example":"Founder Brief"},"primaryDecision":{"type":"string"},"whatChanged":{"type":"string"},"whyItMatters":{"type":"string"},"nextAction":{"type":"string"},"confidence":{"$ref":"#/components/schemas/IntelligenceQualityState"},"confidenceLabel":{"type":"string"},"sourceRefs":{"type":"array","items":{"$ref":"#/components/schemas/MetricSourceRef"}},"supportingSignals":{"type":"array","items":{"type":"string"}},"missingData":{"type":"array","items":{"type":"string"}},"deeperReport":{"type":["object","null"],"additionalProperties":true}}},"IntelligenceHome":{"type":"object","required":["companyId","entityId","homeState","period","businessContext","brief","curation","signals","reports","metrics","curatedMetrics","evidenceStrip","verificationTimeline","dataReadiness","openNext","dataHealth","topInsights","pendingInsightCount"],"properties":{"companyId":{"type":"string"},"entityId":{"type":"string","format":"uuid"},"homeState":{"type":"string","enum":["active_curated","active_needs_review","fallback_unreviewed","blocked"]},"period":{"type":"object","additionalProperties":true},"businessContext":{"type":"object","additionalProperties":true},"brief":{"$ref":"#/components/schemas/IntelligenceHomeBrief"},"curation":{"$ref":"#/components/schemas/IntelligenceHomeCuration"},"signals":{"type":"array","minItems":0,"maxItems":7,"items":{"$ref":"#/components/schemas/IntelligenceHomeSignal"}},"reports":{"type":"array","items":{"$ref":"#/components/schemas/IntelligenceHomeReport"}},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/InsightMetric"}},"curatedMetrics":{"type":"array","items":{"type":"object","required":["item","metric"],"properties":{"item":{"$ref":"#/components/schemas/IntelligenceHomeCurationItem"},"metric":{"oneOf":[{"$ref":"#/components/schemas/InsightMetric"},{"type":"null"}]}}}},"evidenceStrip":{"type":"array","items":{"type":"object","required":["key","label","value","qualityState","verifiedAsOf","sourceRefs"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"value":{"type":"string"},"qualityState":{"$ref":"#/components/schemas/IntelligenceQualityState"},"verifiedAsOf":{"type":["string","null"],"format":"date-time"},"sourceRefs":{"type":"array","items":{"$ref":"#/components/schemas/MetricSourceRef"}}}}},"verificationTimeline":{"type":"array","items":{"type":"object","required":["key","label","state","detail","updatedAt","sourceRefs"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"state":{"type":"string","enum":["source_synced","ai_reviewed","accounting_reviewed","reviewing","blocked","pending"]},"detail":{"type":"string"},"updatedAt":{"type":["string","null"],"format":"date-time"},"sourceRefs":{"type":"array","items":{"$ref":"#/components/schemas/MetricSourceRef"}}}}},"dataReadiness":{"type":"object","required":["state","summary","verifiedAsOf","blockers","warnings"],"properties":{"state":{"$ref":"#/components/schemas/IntelligenceQualityState"},"summary":{"type":"string"},"verifiedAsOf":{"type":["string","null"],"format":"date-time"},"blockers":{"type":"array","items":{"type":"object","additionalProperties":true}},"warnings":{"type":"array","items":{"type":"object","additionalProperties":true}}}},"openNext":{"oneOf":[{"type":"object","required":["key","title","description","path","qualityState","sourceRefs"],"properties":{"key":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"path":{"type":["string","null"]},"qualityState":{"$ref":"#/components/schemas/IntelligenceQualityState"},"sourceRefs":{"type":"array","items":{"$ref":"#/components/schemas/MetricSourceRef"}}}},{"type":"null"}]},"dataHealth":{"type":"object","additionalProperties":true},"topInsights":{"type":"array","items":{"type":"object","additionalProperties":true}},"pendingInsightCount":{"type":"integer","minimum":0}}},"IntelligenceHomeResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/IntelligenceHome"}}},"ReportComparisonMode":{"type":"string","enum":["none","prior-period","prior-year"]},"LedgerRevision":{"type":["string","null"],"pattern":"^lr1_[0-9a-f]{24}$","description":"Opaque token of the posted ledger state the report was read under (#1166). It changes whenever any journal entry or line of the company (with `entityId`, of that entity and of entries with no entity) is inserted, updated, voided or deleted, backdated or not. Two reads with equal tokens saw the same ledger. Null when the ledger moved on both attempts of the read, so a client combining pages or statements must treat the result as unproven and retry. Not a credential; not ordered.\n"},"LedgerRevisionStamp":{"type":"object","properties":{"ledgerRevision":{"$ref":"#/components/schemas/LedgerRevision"}}},"StatementBasisMetadata":{"type":"object","required":["configuredBasis","configuredBasisSource","reportBasis"],"description":"The configured accounting preference is reported separately from the basis the statement was actually calculated on, and never changes the calculation. `reportBasis` is `accrual` unless the request asked for `basis=cash` and the cash-basis view could be produced (#2911). Only the accountant report routes accept `basis`, so customer report routes always return `accrual` and never carry `cashBasis`. `configuredBasisSource` is `statement_basis` when an accountant has recorded an approved statement basis effective on the report date (J-355); that row is metadata only and never changes figures or `reportBasis`. The row is resolved on the request's `endDate` / `asOfDate` (the month end for a legacy `month`); when the request names no date, it is resolved on today's date (UTC), the current basis, even though the payload then describes the latest posted period.\n","properties":{"configuredBasis":{"type":"string","enum":["cash","accrual","unknown"]},"configuredBasisSource":{"type":"string","enum":["statement_basis","tax_settings","company","missing","unavailable"]},"reportBasis":{"type":"string","enum":["accrual","cash"]},"fiscalYearEnd":{"type":["string","null"],"pattern":"^[0-9]{2}-[0-9]{2}$","description":"companies.fiscal_year_end (MM-DD); null when not confirmed (#2019)."},"fiscalYearReview":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["unknown"]}],"description":"True when companies.fiscal_year_end is set and is not 12-31, or tax_settings.fiscal_year_end (month) is set and is not 12. Non-calendar fiscal years are not supported yet, so the statement is still calendar-year and must be reviewed. It is \"unknown\" when the company or tax-settings fiscal year end could not be read, never a silent false (#2019)."},"fiscalYearReviewReason":{"type":["string","null"],"description":"Why fiscalYearReview is raised, naming the field that raised it; null when not raised (#2019)."},"cashBasis":{"$ref":"#/components/schemas/CashBasisSummary"}}},"ProfitAndLossComparison":{"type":"object","required":["configuredBasis","configuredBasisSource","reportBasis","checks"],"description":"Prior-period / prior-year comparison block attached to the P&L payload when `comparePeriod` is supplied. Mirrors the main-period shape plus a `mode`, range dates, and `hasData` flag. `reportBasis` is that of the statement it is attached to: `cash` only under a statement requested with `basis=cash` on the accountant report routes. `configuredBasis` and `configuredBasisSource` are inherited from the primary period and are not re-resolved on the comparison's own date (#2911).\n","properties":{"configuredBasis":{"type":"string","enum":["cash","accrual","unknown"]},"configuredBasisSource":{"type":"string","enum":["statement_basis","tax_settings","company","missing","unavailable"]},"reportBasis":{"type":"string","enum":["accrual","cash"]},"currency":{"type":["string","null"],"description":"ISO currency of the comparison figures; the same authority as the statement it is attached to (#3434)."},"minorUnitExponent":{"type":["integer","null"],"description":"Minor-unit exponent of the comparison figures (2), null with currency (#3434)."},"fiscalYearEnd":{"type":["string","null"],"pattern":"^[0-9]{2}-[0-9]{2}$","description":"companies.fiscal_year_end (MM-DD); null when not confirmed (#2019)."},"fiscalYearReview":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["unknown"]}],"description":"True when companies.fiscal_year_end is set and not 12-31, or tax_settings.fiscal_year_end is set and not 12; statements are still calendar-year and need review; \"unknown\" when the fiscal year end could not be read (#2019)."},"fiscalYearReviewReason":{"type":["string","null"],"description":"Why fiscalYearReview is raised, naming the field (companies.fiscal_year_end or tax_settings.fiscal_year_end); null when not raised (#2019)."},"mode":{"$ref":"#/components/schemas/ReportComparisonMode"},"period":{"type":"string"},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"hasData":{"type":"boolean"},"revenue":{"type":"array","items":{"type":"object"}},"cogs":{"type":"array","items":{"type":"object"}},"expenses":{"type":"object"},"otherIncome":{"type":"array","items":{"type":"object"}},"totalRevenue":{"type":"number"},"totalCogs":{"type":"number"},"totalOpex":{"type":"number"},"totalExpenses":{"type":"number"},"operatingIncome":{"type":"number"},"totalOtherIncome":{"type":"number"},"netIncome":{"type":"number"},"differenceCents":{"type":"integer"},"isConsistent":{"type":"boolean"},"checks":{"$ref":"#/components/schemas/ReportChecks"}}},"BalanceSheetComparison":{"type":"object","required":["configuredBasis","configuredBasisSource","reportBasis"],"description":"Prior-period / prior-year comparison block attached to the Balance Sheet payload when `comparePeriod` is supplied. Mirrors the main shape plus a `mode`, `asOfDate`, and `hasData` flag. `reportBasis` is that of the statement it is attached to: `cash` only under a statement requested with `basis=cash` on the accountant report routes. `configuredBasis` and `configuredBasisSource` are inherited from the primary period and are not re-resolved on the comparison's own date (#2911).\n","properties":{"configuredBasis":{"type":"string","enum":["cash","accrual","unknown"]},"configuredBasisSource":{"type":"string","enum":["statement_basis","tax_settings","company","missing","unavailable"]},"reportBasis":{"type":"string","enum":["accrual","cash"]},"currency":{"type":["string","null"],"description":"ISO currency of the comparison figures; the same authority as the statement it is attached to (#3434)."},"minorUnitExponent":{"type":["integer","null"],"description":"Minor-unit exponent of the comparison figures (2), null with currency (#3434)."},"fiscalYearEnd":{"type":["string","null"],"pattern":"^[0-9]{2}-[0-9]{2}$","description":"companies.fiscal_year_end (MM-DD); null when not confirmed (#2019)."},"fiscalYearReview":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["unknown"]}],"description":"True when companies.fiscal_year_end is set and not 12-31, or tax_settings.fiscal_year_end is set and not 12; statements are still calendar-year and need review; \"unknown\" when the fiscal year end could not be read (#2019)."},"fiscalYearReviewReason":{"type":["string","null"],"description":"Why fiscalYearReview is raised, naming the field (companies.fiscal_year_end or tax_settings.fiscal_year_end); null when not raised (#2019)."},"mode":{"$ref":"#/components/schemas/ReportComparisonMode"},"asOfDate":{"type":"string","format":"date"},"hasData":{"type":"boolean"},"assets":{"type":"object"},"liabilities":{"type":"object"},"equity":{"type":"array","items":{"type":"object"}},"totalAssets":{"type":"number"},"totalLiabilities":{"type":"number"},"totalEquity":{"type":"number"},"totalLiabilitiesAndEquity":{"type":"number"},"differenceCents":{"type":"integer"},"isBalanced":{"type":"boolean"}}},"CashFlowComparison":{"type":"object","required":["configuredBasis","configuredBasisSource","reportBasis","checks"],"description":"Prior-period / prior-year comparison block attached to the Cash Flow payload when `comparePeriod` is supplied. Mirrors the main shape plus a `mode`, range dates, and `hasData` flag. `reportBasis` is that of the statement it is attached to: `cash` only under a statement requested with `basis=cash` on the accountant report routes. `configuredBasis` and `configuredBasisSource` are inherited from the primary period and are not re-resolved on the comparison's own date (#2911).\n","properties":{"configuredBasis":{"type":"string","enum":["cash","accrual","unknown"]},"configuredBasisSource":{"type":"string","enum":["statement_basis","tax_settings","company","missing","unavailable"]},"reportBasis":{"type":"string","enum":["accrual","cash"]},"fiscalYearEnd":{"type":["string","null"],"pattern":"^[0-9]{2}-[0-9]{2}$","description":"companies.fiscal_year_end (MM-DD); null when not confirmed (#2019)."},"fiscalYearReview":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["unknown"]}],"description":"True when companies.fiscal_year_end is set and not 12-31, or tax_settings.fiscal_year_end is set and not 12; statements are still calendar-year and need review; \"unknown\" when the fiscal year end could not be read (#2019)."},"fiscalYearReviewReason":{"type":["string","null"],"description":"Why fiscalYearReview is raised, naming the field (companies.fiscal_year_end or tax_settings.fiscal_year_end); null when not raised (#2019)."},"mode":{"$ref":"#/components/schemas/ReportComparisonMode"},"period":{"type":"string"},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"hasData":{"type":"boolean"},"operating":{"type":"object","properties":{"netIncome":{"type":"number"},"adjustments":{"type":"array","items":{"type":"object"}}}},"investing":{"type":"array","items":{"type":"object"}},"financing":{"type":"array","items":{"type":"object"}},"beginningCash":{"type":"number"},"endingCash":{"type":"number"},"differenceFromBalanceSheetCents":{"type":"integer"},"isConsistent":{"type":"boolean"},"checks":{"$ref":"#/components/schemas/ReportChecks"}}},"CashBasisScope":{"type":"object","required":["kind","entityId","startDate","endDate"],"description":"What a cash-basis statement or refusal answers for. `range` (P&L, cash flow, income-statement drill-down) is blocked by a refusal dated inside `startDate`..`endDate`; `as_of` (balance sheet, trial balance, balance-sheet drill-down) by any refusal dated on or before `endDate`.\n","properties":{"kind":{"type":"string","enum":["range","as_of"]},"entityId":{"type":["string","null"],"description":"Null when the request named no entity."},"startDate":{"type":["string","null"],"format":"date","description":"Null on `as_of`, and when the request carried no explicit start."},"endDate":{"type":["string","null"],"format":"date","description":"Range end or as-of date. Null only when the request carried no explicit date."}}},"CashBasisSummary":{"type":"object","required":["policyId","policyVersion","reviewedBy","throughDate","scope","droppedEntryCount","retargetedLineCount","retargetedCents","accrualNetIncomeCents","timingMovementCents","evidence","reviewItemCount","reviewItems","basisNotice"],"description":"The `cashBasis` block of a statement whose `reportBasis` is `cash`. Present only then; an accrual statement has no such key. Money is integer ledger cents. Cash net income over the scope equals `accrualNetIncomeCents - timingMovementCents`, so the difference from accrual can be re-derived by hand. The view is not a GAAP statement; `basisNotice` says so and clients print it with the statement.\n","properties":{"policyId":{"type":"string","enum":["cash-basis-v1"]},"policyVersion":{"type":"integer","minimum":1,"description":"Revision of the rules under this policy id."},"reviewedBy":{"type":"string","description":"Reviewer of the policy the statement was calculated under."},"throughDate":{"type":"string","format":"date","description":"The cash view was built from inception through this date."},"scope":{"$ref":"#/components/schemas/CashBasisScope"},"droppedEntryCount":{"type":"integer","minimum":0,"description":"Entries left out of the cash view because they only move amounts between income or expense and a receivable, payable, deferred-revenue or accrued account. Whole view, inception through `throughDate`."},"retargetedLineCount":{"type":"integer","minimum":0,"description":"Receivable or payable settlement lines moved onto the income or expense accounts of the invoice or bill they settle. Whole view, inception through `throughDate`."},"retargetedCents":{"type":"integer","description":"Sum of the retargeted settlement lines. Whole view, inception through `throughDate`."},"accrualNetIncomeCents":{"type":"integer","description":"Accrual net income over the scope (revenue minus expense, closing entries excluded)."},"timingMovementCents":{"type":"integer","description":"Change over the scope in the debit-positive balance of the receivable, payable, deferred-revenue and accrued accounts, on the accrual ledger."},"evidence":{"type":"object","required":["uncategorizedIncomeCents","uncategorizedExpenseCents","suspenseBalanceCents"],"description":"Completeness figures over the scope. They have no basis effect.","properties":{"uncategorizedIncomeCents":{"type":"integer"},"uncategorizedExpenseCents":{"type":"integer"},"suspenseBalanceCents":{"type":"integer","description":"Balance of suspense and ask-my-client accounts at the scope's end, debit positive."}}},"reviewItemCount":{"type":"integer","minimum":0,"description":"Review items dated inside the scope, including those beyond the cap on `reviewItems`."},"reviewItems":{"type":"array","maxItems":50,"description":"Kept income or expense lines with no cash, card or clearing line behind them, earliest first. They are identical on both bases and listed for review. No memo or description text.","items":{"type":"object","required":["kind","entryId","entryDate","accountCode","amountCents"],"properties":{"kind":{"type":"string","enum":["pnl_against_equity_or_suspense"]},"entryId":{"type":"string"},"entryDate":{"type":"string","format":"date"},"accountCode":{"type":"string","description":"Code of the income or expense account."},"amountCents":{"type":"integer","minimum":0,"description":"Ledger cents of that line."}}}},"basisNotice":{"type":"string","description":"Fixed wording that the view is not a GAAP statement. Clients print it with the statement instead of composing their own.","enum":["Cash basis. Not a GAAP statement: revenue is recognized when cash is received, not when performance obligations are satisfied (ASC 606)."]}}},"CashBasisLineProvenance":{"type":"object","required":["originEntryId","originEntryDate","controlAccountId","cumulativeSettledCents","itemTotalCents"],"description":"Present on a drill-down row of a cash-basis read when the row is a receivable or payable settlement moved onto the income or expense accounts of the invoice or bill it settles. The row keeps the settlement's own date and amount; this names where it came from.\n","properties":{"originEntryId":{"type":"string","description":"The invoice or bill entry."},"originEntryDate":{"type":"string","format":"date"},"controlAccountId":{"type":"string","description":"The receivable or payable account the settlement line was posted to."},"cumulativeSettledCents":{"type":"integer","description":"Settled on the item up to and including this settlement, in ledger cents."},"itemTotalCents":{"type":"integer","description":"The invoice's or bill's receivable or payable total, in ledger cents."}}},"CashBasisUnavailableExtensions":{"type":"object","required":["cashBasis"],"description":"Why a cash-basis statement cannot be produced. Carries no memo or description text.","properties":{"cashBasis":{"type":"object","required":["reasons","policyId","scope"],"properties":{"reasons":{"type":"array","items":{"type":"object","required":["code","count","samples"],"properties":{"code":{"type":"string","description":"`policy_unreviewed`, `consolidated_scope_unsupported`, `entity_scope_required` and `explicit_period_required` are decided from the request alone, before the ledger is read. `self_check_failed:*` means an internal consistency check on the cash view failed. Every other code names posted entries the policy cannot place on the cash basis.\n","enum":["policy_unreviewed","consolidated_scope_unsupported","entity_scope_required","explicit_period_required","unknown_account","ambiguous_account_role","policy_unreviewed_account","unlinked_receivable_settlement","unlinked_payable_settlement","unlinked_deferred_revenue","unlinked_accrued_liability","pnl_against_unpaid_liability","pnl_against_noncash_asset","settlement_without_origin","duplicate_origin","overpaid_item","origin_counter_not_pnl","control_side_mismatch","control_account_mismatch","currency_mismatch","cross_entity_link","fx_revaluation_unsupported","self_check_failed:I1","self_check_failed:I2","self_check_failed:I3","self_check_failed:I4","self_check_failed:I5","self_check_failed:I6","self_check_failed:X4","self_check_failed:coverage","self_check_failed:balance_sheet"]},"count":{"type":"integer","minimum":1,"description":"Refusals with this code inside the scope. Request-level and self-check reasons count 1 and carry no samples."},"samples":{"type":"array","maxItems":20,"description":"Example entries behind the reason, earliest first.","items":{"type":"object","additionalProperties":false,"required":["entryId","entryDate","accountCode","documentId","amountCents"],"properties":{"entryId":{"type":"string"},"entryDate":{"type":"string","format":"date"},"accountCode":{"type":["string","null"],"description":"Code of the offending line's account. Null when the account is unknown or the refusal is about the whole entry."},"documentId":{"type":["string","null"],"description":"The invoice or bill document the offending line names, when it names one."},"amountCents":{"type":"integer","minimum":0,"description":"Ledger cents of the offending line, or the entry's total debits when the refusal is about the whole entry."}}}}}}},"policyId":{"type":"string","enum":["cash-basis-v1"]},"scope":{"$ref":"#/components/schemas/CashBasisScope"}}}}},"CashBasisUnavailable":{"type":"object","required":["success","error"],"description":"The 422 answered when a cash-basis read cannot be produced. No figures are returned, on either basis.\n","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","required":["title","status","detail","extensions"],"properties":{"title":{"type":"string","enum":["CASH_BASIS_UNAVAILABLE"]},"status":{"type":"integer","enum":[422]},"detail":{"type":"string"},"traceId":{"type":"string"},"extensions":{"$ref":"#/components/schemas/CashBasisUnavailableExtensions"}}}}},"AccountantReportStatementUnavailable":{"type":"object","required":["unavailable","reason","code","traceId"],"description":"Left in a statement's place in the accountant reports bundle when that statement could not be produced. The other statements of the bundle are unaffected.\n","properties":{"unavailable":{"type":"boolean","enum":[true]},"reason":{"type":"string","description":"Client-facing message. A literal for unexpected failures."},"code":{"type":"string","description":"Error code of the rejection. `CASH_BASIS_UNAVAILABLE` when the statement was asked on the cash basis and cannot be produced; `INTERNAL_ERROR` for an unexpected failure.\n"},"traceId":{"type":["string","integer","null"],"description":"Server log correlation id of the request."},"details":{"$ref":"#/components/schemas/CashBasisUnavailableExtensions","description":"Present only when `code` is `CASH_BASIS_UNAVAILABLE`."}}},"AccountantBundledStatement":{"description":"One statement of the accountant reports bundle: the statement itself, or the marker left in its place when it could not be produced. A rejected statement is never null and is never replaced by figures on another basis.\n","oneOf":[{"allOf":[{"$ref":"#/components/schemas/StatementBasisMetadata"},{"type":"object","additionalProperties":true}]},{"$ref":"#/components/schemas/AccountantReportStatementUnavailable"}]},"AccountantReportsBundle":{"type":"object","additionalProperties":true,"description":"Statements and aging of one customer. With `type`, only the requested section is present beside `type` and `customerId`. Without a customer the payload lists `availableReports` instead. The four statements share the request's `basis`; A/R and A/P aging have no basis.\n","properties":{"profitAndLoss":{"$ref":"#/components/schemas/AccountantBundledStatement"},"balanceSheet":{"$ref":"#/components/schemas/AccountantBundledStatement"},"cashFlow":{"$ref":"#/components/schemas/AccountantBundledStatement"},"trialBalance":{"$ref":"#/components/schemas/AccountantBundledStatement"}}},"ReportClassDescriptor":{"type":"object","required":["classId","className","isUnassigned"],"properties":{"classId":{"type":["string","null"],"description":"Null represents the explicit Unassigned class bucket."},"className":{"type":"string"},"isUnassigned":{"type":"boolean"}}},"ProfitAndLossClassGroup":{"allOf":[{"$ref":"#/components/schemas/ReportClassDescriptor"},{"type":"object","properties":{"period":{"type":"string"},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"revenue":{"type":"array","items":{"type":"object"}},"cogs":{"type":"array","items":{"type":"object"}},"expenses":{"type":"object"},"otherIncome":{"type":"array","items":{"type":"object"}},"totalRevenue":{"type":"number"},"totalCogs":{"type":"number"},"totalOpex":{"type":"number"},"totalExpenses":{"type":"number"},"operatingIncome":{"type":"number"},"totalOtherIncome":{"type":"number"},"netIncome":{"type":"number"},"differenceCents":{"type":"integer"},"isConsistent":{"type":"boolean"},"hasData":{"type":"boolean"}}}]},"ProfitAndLossClassReconciliation":{"type":"object","description":"Reconciles summed class groups to the unfiltered P&L totals for the same company, period, and basis.\n","properties":{"totalRevenueCents":{"type":"object","additionalProperties":true},"totalCogsCents":{"type":"object","additionalProperties":true},"totalOpexCents":{"type":"object","additionalProperties":true},"totalExpensesCents":{"type":"object","additionalProperties":true},"netIncomeCents":{"type":"object","additionalProperties":true},"isConsistent":{"type":"boolean"}}},"ReportSelfCheckBalanced":{"type":"object","description":"Non-failing self-check fields surfaced on reports whose correctness is expressed as a balance identity (trial balance, balance sheet). When the underlying GL reconciles, `isBalanced` is true and `differenceCents` is 0. Tolerance is 1 cent.\n","properties":{"isBalanced":{"type":"boolean"},"differenceCents":{"type":"integer","description":"Signed drift in cents. Positive = debits exceed credits (or assets exceed L+E)."}}},"ReportCheckScope":{"type":"object","required":["companyId","entityId","classId","startDate","endDate","source"],"properties":{"companyId":{"type":"string"},"entityId":{"type":["string","null"]},"classId":{"type":["string","null"],"description":"Null means no class filter; the literal unassigned selector is retained as a string."},"startDate":{"type":["string","null"],"format":"date"},"endDate":{"type":["string","null"],"format":"date"},"source":{"type":"string","enum":["journal_entries","monthly_balances","issued_snapshot"],"description":"Authority evaluated, not the origin of the entire report. Cross-checks name the monthly cache authority being compared to journal-derived amounts. An issued snapshot's arithmetic names issued_snapshot; its unexecuted cache check still names monthly_balances.\n"}}},"ReportCheck":{"type":"object","required":["id","status","reason","differenceCents","toleranceCents","scope"],"properties":{"id":{"type":"string","enum":["pl_arithmetic","pl_cache","cash_flow_identity","cash_flow_balance_sheet"]},"status":{"type":"string","enum":["PASS","FAIL","NOT_CHECKED","UNKNOWN"]},"reason":{"type":["string","null"],"description":"Null for executed checks. Skip reasons are class_filtered, tag_filtered, partial_month_range, closing_entries_in_range, no_monthly_balances, no_data, issued_snapshot, comparison_cache_not_supported, and cash_basis (pl_cache on a cash-basis P&L: the monthly cache holds accrual balances, so it is not compared). UNKNOWN uses unavailable. Future reasons cannot prove PASS.\n"},"differenceCents":{"type":["integer","null"],"description":"Null when not executed. Signed differences: pl_arithmetic = revenue - expenses - netIncome; pl_cache = largest absolute journal-minus-cache discrepancy across revenue/COGS/OPEX/expenses/NI; cash_flow_identity = beginning + netIncome + adjustments + investing + financing - ending; cash_flow_balance_sheet = ending - cumulative monthly cash balances.\n"},"toleranceCents":{"type":"integer","minimum":0,"description":"Zero for exact cash-flow identity; one minor unit for other existing checks."},"scope":{"$ref":"#/components/schemas/ReportCheckScope"}},"oneOf":[{"required":["status","reason","differenceCents"],"properties":{"status":{"enum":["PASS","FAIL"]},"reason":{"type":"null"},"differenceCents":{"type":"integer"}}},{"required":["status","reason","differenceCents"],"properties":{"status":{"enum":["NOT_CHECKED","UNKNOWN"]},"reason":{"type":"string","minLength":1},"differenceCents":{"type":"null"}}}]},"ReportChecks":{"type":"object","required":["version","status","items"],"description":"Additive v1 evidence. Expected IDs are exactly pl_arithmetic/pl_cache for P&L or cash_flow_identity/cash_flow_balance_sheet for cash flow. Any failure wins; all expected checks must pass for PASS; a skipped, missing, malformed or unknown check yields UNKNOWN. Invalid top-level status/version cannot establish success. An explicit legacy false or recognized failure survives invalid/skipped siblings. Each comparison has independent scope and status. P&L nested comparison cache is NOT_CHECKED/comparison_cache_not_supported. No-range responses skip both checks with no_data; explicit zero-activity windows can execute.\n","properties":{"version":{"type":"integer","const":1},"status":{"type":"string","enum":["PASS","FAIL","UNKNOWN"]},"items":{"type":"array","minItems":2,"maxItems":2,"items":{"$ref":"#/components/schemas/ReportCheck"}}}},"ReportSelfCheckConsistent":{"type":"object","required":["checks"],"description":"Compatibility fields plus explicit check evidence for P&L/cash flow. isConsistent remains boolean: false for any executed failure, true otherwise (including skipped checks). It is not proof that all checks ran. Legacy differences remain integers; skipped differences retain zero. Inspect checks for execution, signed differences, applicability and per-check tolerances.\n","properties":{"isConsistent":{"type":"boolean"},"differenceCents":{"type":"integer","description":"P&L only. Revenue minus expenses minus net income."},"cacheDifferenceCents":{"type":"integer","description":"P&L primary only. Largest signed journal-minus-cache discrepancy; zero if skipped."},"differenceFromBalanceSheetCents":{"type":"integer","description":"Cash flow only. Ending cash minus monthly-balance cash; zero if skipped."},"checks":{"$ref":"#/components/schemas/ReportChecks"}}},"ReportCategoryDiagnostics":{"type":"object","required":["startDate","endDate","summary","items"],"properties":{"startDate":{"type":["string","null"],"format":"date"},"endDate":{"type":["string","null"],"format":"date"},"summary":{"type":"object","required":["transactionsScanned","pnlAccountsChecked","categoryJournalMismatchCount","drilldownMismatchCount","classLinesScanned","classAssignedLineCount","classUnassignedLineCount","classUnassignedAmountCents","classCrossCompanyReferenceCount","itemCount","isConsistent"],"properties":{"transactionsScanned":{"type":"integer","minimum":0},"pnlAccountsChecked":{"type":"integer","minimum":0},"categoryJournalMismatchCount":{"type":"integer","minimum":0},"drilldownMismatchCount":{"type":"integer","minimum":0},"classLinesScanned":{"type":"integer","minimum":0},"classAssignedLineCount":{"type":"integer","minimum":0},"classUnassignedLineCount":{"type":"integer","minimum":0},"classUnassignedAmountCents":{"type":"integer","minimum":0},"classCrossCompanyReferenceCount":{"type":"integer","minimum":0},"itemCount":{"type":"integer","minimum":0},"isConsistent":{"type":"boolean"}}},"items":{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/ReportCategoryJournalMismatch"},{"$ref":"#/components/schemas/ReportDrilldownMismatch"},{"$ref":"#/components/schemas/ReportClassUnassignedLines"},{"$ref":"#/components/schemas/ReportClassCrossCompanyReference"}]}}}},"ReportCategoryJournalMismatch":{"type":"object","required":["issue","severity","transactionId","journalEntryId","journalLineId","categoryGlCode","journalGlCode","recommendedAction"],"properties":{"issue":{"type":"string","enum":["transaction_category_journal_line_mismatch"]},"severity":{"type":"string","enum":["error"]},"transactionId":{"type":"string"},"transactionDate":{"type":"string","format":"date"},"transactionDescription":{"type":"string"},"journalEntryId":{"type":"string"},"journalLineId":{"type":"string"},"categoryGlAccountId":{"type":"string"},"categoryGlCode":{"type":"string"},"categoryGlName":{"type":"string"},"journalGlAccountId":{"type":"string"},"journalGlCode":{"type":"string"},"journalGlName":{"type":"string"},"amountCents":{"type":"integer"},"recommendedAction":{"type":"string"}}},"ReportDrilldownMismatch":{"type":"object","required":["issue","severity","accountId","accountCode","reportAmountCents","drilldownAmountCents","differenceCents","recommendedAction"],"properties":{"issue":{"type":"string","enum":["pl_row_drilldown_total_mismatch"]},"severity":{"type":"string","enum":["error"]},"accountId":{"type":"string"},"accountCode":{"type":"string"},"accountName":{"type":"string"},"reportSection":{"type":"string"},"reportSectionLabel":{"type":"string"},"reportAmountCents":{"type":"integer"},"drilldownAmountCents":{"type":"integer"},"differenceCents":{"type":"integer"},"recommendedAction":{"type":"string"}}},"ReportClassUnassignedLines":{"type":"object","required":["issue","severity","accountId","accountCode","lineCount","amountCents","recommendedAction"],"properties":{"issue":{"type":"string","enum":["pl_unassigned_class_lines"]},"severity":{"type":"string","enum":["warning"]},"accountId":{"type":"string"},"accountCode":{"type":"string"},"accountName":{"type":"string"},"lineCount":{"type":"integer","minimum":0},"amountCents":{"type":"integer","minimum":0},"recommendedAction":{"type":"string"}}},"ReportClassCrossCompanyReference":{"type":"object","required":["issue","severity","journalEntryId","journalLineId","classId","accountId","recommendedAction"],"properties":{"issue":{"type":"string","enum":["journal_line_class_cross_company_reference"]},"severity":{"type":"string","enum":["error"]},"journalEntryId":{"type":"string"},"journalLineId":{"type":"string"},"entryDate":{"type":"string","format":"date"},"classId":{"type":"string"},"accountId":{"type":"string"},"accountCode":{"type":"string"},"accountName":{"type":"string"},"recommendedAction":{"type":"string"}}},"OverviewMetrics":{"type":"object","description":"Home page metrics. Legacy fields stay for backward compatibility.","required":["cashBalance","mrr","burnRate","netBurnRate","runway","runwayState","runwayCapped","cashTrend","mrrTrend","burnTrend","runwayTrend","monthlyRevenue","monthlyRevenueTrend","monthlyRevenueTrendState","monthlyRevenueChange","shortTermDebt","operatingCashAvailable"],"properties":{"currency":{"type":["string","null"],"pattern":"^[A-Z]{3}$","description":"Company presentation currency used by every monetary metric in this object."},"cashBalance":{"type":"number","description":"Resolved cash balance (liveCashBalance ?? glCashBalance) in `currency`. Foreign provider balances are translated through an immutable spot FX rate for the provider balance date before aggregation.\n"},"mrr":{"type":["number","null"],"description":"Subscription MRR as of today from the recurring-revenue authority (#2217): the certified current-month snapshot, net of recurring discounts, never posted revenue (one-time invoices never enter it). Scope is the route's legal entity, or the company's sole legal entity for unscoped callers. Null when the authority cannot answer; `mrrAvailability` names why. Posted revenue is `monthlyRevenue`.\n"},"mrrCents":{"type":["integer","null"],"description":"Exact minor units of `mrr` (null exactly when `mrr` is null)."},"mrrAvailability":{"type":"object","required":["available","reason","asOf","basis"],"properties":{"available":{"type":"boolean"},"reason":{"type":["string","null"],"description":"Customer-safe reason when unavailable (e.g. syncing, source_not_authorized, insufficient_history, entity_scope_unavailable, mixed_currency, not_configured, failed); null when available."},"asOf":{"type":["string","null"],"format":"date","description":"The date `mrr` represents (today, from the request clock). It is not the snapshot's computation time and is not evidence of source freshness."},"basis":{"type":"string","enum":["subscription_mrr_as_of_today"]}}},"burnRate":{"type":"number","description":"Gross burn rate per month. Sourced from trailing-90-day Expense-account activity divided by 3, excluding transfers, credit-card payments, and other balance-sheet moves.\n"},"netBurnRate":{"type":"number","description":"Net burn rate per month. Sourced from trailing-90-day Expense-account activity minus Revenue-account activity, divided by 3 and floored at zero. Runway uses this value.\n"},"runway":{"type":["integer","null"],"description":"Debt-adjusted runway months on balance-sheet cash (#1412): operatingCashAvailable divided by netBurnRate. The cash is the posted ledger balance of the cash accounts, not the live-first cashBalance. Null when non-burning or unavailable."},"runwayState":{"type":"string","enum":["finite","depleted","non_burning","unavailable"]},"runwayCapped":{"type":"boolean","description":"True when the displayed runway is capped at 120 months."},"cashTrend":{"type":"number"},"mrrTrend":{"type":["number","null"],"description":"Percent change of `mrr` (as of today) against the last completed month's sealed MRR. Null when either is unavailable or the completed month is zero."},"burnTrend":{"type":"number"},"runwayTrend":{"type":"number"},"monthlyRevenue":{"type":"number","description":"Posted revenue for the headline window (trailing 30 days, or the last closed calendar month on a rangeless call when one has activity). Not MRR; see `mrr`."},"monthlyRevenueTrend":{"type":["number","null"],"description":"Percent change in monthlyRevenue vs. the prior 30-day window."},"monthlyRevenueTrendState":{"type":"string","enum":["available","no_prior_base","unstable_base"],"description":"Explains whether the percentage has a stable prior-period base."},"monthlyRevenueChange":{"type":"number","description":"Absolute change in monthly revenue, retained when the percentage is unavailable."},"shortTermDebt":{"type":"number","description":"Drawn short-term debt included in the runway adjustment."},"shortTermDebtCents":{"type":["integer","null"],"description":"Exact minor-unit twin of shortTermDebt (#1412 J-289 B), so a client can show the runway on postedCashBalanceCents less short-term debt without a rounded major-unit figure. Null only when the overview has no presentation-currency authority and the debt is zero."},"operatingCashAvailable":{"type":"number","description":"Balance-sheet cash (the posted ledger balance of the cash accounts, glCashBalance) less drawn short-term debt (#1412). It is not derived from the live-first cashBalance."},"postedCashBalanceCents":{"type":["integer","null"],"description":"Balance-sheet cash in exact minor units (#1412): the posted ledger balance of the cash accounts, the exact twin of glCashBalance. The Home Runway headline, the accountant Customer View and the weekly email divide this value, not the live-first cash balance the Cash tile shows. Null only when the overview has no presentation-currency authority and the balance is zero."},"liveCashBalance":{"type":["number","null"],"description":"Best-available cash: live checking/savings, plus a Stripe balance only when its GL account is classified as cash, plus a GL fallback for cash accounts that have no live provider balance (e.g. Ramp). Null when no live integration balance exists.\n"},"glCashBalance":{"type":"number","description":"Sum of GL cash-account balances for the latest month."},"liveCashAsOf":{"type":["string","null"],"format":"date-time","description":"Oldest KNOWN sync timestamp among the cash accounts funding liveCashBalance: the total is only as fresh as its stalest component. Read it together with liveCashUndatedAccountCount: when that is non-zero this value is a LOWER BOUND, because some contributing account carries no sync stamp and could be older. Null only when no contributing account has a stamp at all. GL-fallback / Ramp-style accounts do not fund liveCashBalance through this path."},"liveCashUndatedAccountCount":{"type":"integer","description":"How many accounts funding liveCashBalance carry no sync stamp at all. 0 means liveCashAsOf describes every contributing account. Non-zero means liveCashAsOf is a lower bound and the true oldest sync may be older, so a renderer must not present it as exact."},"staleCashCents":{"type":"integer","description":"The portion of the cash headline (`cashBalance`) that comes from cash accounts whose provider feed is disconnected, in integer minor units of `currency`. It is an unverified book balance, not a provider figure, and `liveCashAsOf` does not describe it. Sourced from the same posted-ledger authority as the headline, so it equals the sum of `bookBalanceCents` over the disconnected `perAccountReconciliation` rows exactly. 0 when every cash account is either live or books-only.\n"},"staleCashAsOf":{"type":["string","null"],"format":"date-time","description":"The last time a provider verified the whole stale portion of the cash headline: each disconnected cash account behind `staleCashCents` is taken at its most recent known sync, and the oldest of those is reported. Null when any disconnected cash account has no known last sync, because a date on the total would vouch for money it never covered. The money it dates is the same posted-ledger figure the headline counts; the amount is unaffected by this rule.\n"},"darkCashCents":{"type":"integer","description":"The portion of the cash headline funded by accounts whose provider feed is still ATTACHED but has not synced in over 48 hours, in integer minor units of `currency`. Unlike staleCashCents these are real provider balances that have merely gone stale (a reauth or a wedged scheduler), not frozen book balances, so the figure is the provider amount and never a GL fallback. Disjoint from staleCashCents by construction: this counts only active accounts, that one counts only removed feeds. 0 when every funding account synced within the window."},"darkCashAsOf":{"type":["string","null"],"format":"date-time","description":"Oldest sync timestamp among the dark-but-attached accounts counted in darkCashCents. Null exactly when darkCashAccountCount is 0; every counted account carries a stamp by construction (undated ones are reported by liveCashUndatedAccountCount instead)."},"darkCashAccountCount":{"type":"integer","description":"How many still-attached accounts funding the cash headline have not synced in over 48 hours. 0 when none have."},"staleCashAccountCount":{"type":"integer","description":"Number of cash accounts whose provider feed is disconnected and whose book balance is counted in `staleCashCents`, one per GL cash account however many bank rows map to it. Drawn from the same posted-ledger cash-account set as the headline. 0 when no cash account is disconnected.\n"},"reconciliationDeltaCents":{"type":["integer","null"],"description":"Signed bank-minus-GL delta in cents. Null when no live cash to compare."},"glMonthlyExpenses":{"type":"number","description":"Latest-month GL expense total (display-only)."},"netBurnTrend":{"type":["number","null"],"description":"Percent change of netBurnRate vs the same trailing-90-day average for the prior 90-day window (days 91-180). Null when the prior window has no positive net burn to compare against.\n"},"currentAssets":{"type":["number","null"],"description":"Balance-sheet current assets, surfaced for display/context only. It is not the runway numerator. Runway uses posted cash less drawn short-term debt, divided by net burn. Null when the GL is empty.\n"}}},"ExactMoney":{"type":"object","description":"Exact money value: signed integer minor units as a string (never a float), with explicit currency and minor-unit exponent.\n","required":["amountMinor","currency","minorUnitExponent"],"properties":{"amountMinor":{"type":"string","pattern":"^-?\\d+$","description":"Signed integer minor units, e.g. \"80000\" = $800.00 at exponent 2."},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer"}}},"CacUnavailableReason":{"type":"string","description":"Customer-safe reason for an unavailable CAC. `truncated` (a capped scan) and `failed` (a thrown read, added by the /metrics/saas assembler) are the FAILURE class the UI renders as an explicit unavailable state (master-index pin P4); every other value is honest absence.\n","enum":["insufficient_history","source_not_authorized","mixed_currency","entity_scope_unavailable","insufficient_inputs","truncated","failed"]},"CacAnalysisPeriod":{"type":"object","description":"The resolved analysis window. `period=month` is CLAMPED to today, so a partial month is never keyed (or served) under the complete-month end.\n","required":["start","end","label"],"properties":{"start":{"type":"string","format":"date"},"end":{"type":"string","format":"date"},"label":{"type":"string"}}},"CacBreakdown":{"type":"object","description":"Evidence behind the headline, all in the entity's functional currency. `glSmSpendCents` is the naive GL 64xx bucket — EVIDENCE for reconciling against the explicit tags, never itself a tag — and carries the same currency authority and refund sign convention as `smSpendCents`, so `reconciliationDeltaCents` is a comparable figure.\n","required":["smSpendCents","glSmSpendCents","newCustomers","currency","minorUnitExponent"],"properties":{"smSpendCents":{"type":"integer"},"glSmSpendCents":{"type":"integer"},"reconciliationDeltaCents":{"type":"integer"},"taggedTxnCount":{"type":"integer"},"newCustomers":{"type":"integer"},"cacCents":{"type":["integer","null"]},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer"},"sourceGeneration":{"type":["string","null"]},"evidenceSha256":{"type":["string","null"]},"source":{"type":"string"},"computedAt":{"type":"string","format":"date-time"}}},"CacTrendRow":{"type":"object","required":["period","cacCents","smSpendCents","newCustomers"],"properties":{"period":{"type":"string"},"cacCents":{"type":["integer","null"]},"smSpendCents":{"type":"integer"},"newCustomers":{"type":"integer"}}},"MetricCompleteness":{"type":"object","description":"Coverage assertion for a per-metric value/authority contract. An available metric carries all three booleans as true.\n","required":["windowComplete","sourceComplete","provenanceComplete"],"properties":{"windowComplete":{"type":"boolean"},"sourceComplete":{"type":"boolean"},"provenanceComplete":{"type":"boolean"},"historyCompleteFrom":{"type":"string"},"booksAsOf":{"type":"string"},"sourceGeneration":{"type":"string"}}},"UncategorizedIncomeBesideRevenue":{"description":"#2243: signed posted net on 4999 Uncategorized Income inside the same window and currency scope as the revenue figure it sits beside. Never included in that figure's `value` (Home revenue excludes 4999), never called revenue (parked inflows can be transfers or investment wires awaiting categorization). Present only when non-zero.\n","allOf":[{"$ref":"#/components/schemas/ExactMoney"}]},"RevenueMonthToDateMetric":{"description":"Live Home (founder sync 2026-09-21), basis month_to_date_posted_revenue: exact signed posted operating revenue from the 1st of the current UTC month through today (`authority.asOf` is the posted-through day; startDate/endDate bound the window). Available whenever the trailing 90 days hold posted P&L evidence, so a month with nothing posted yet is an authoritative 0. Fails closed exactly like RevenueCompletedMonthMetric.\n","oneOf":[{"type":"object","required":["available","value","authority","completeness"],"properties":{"available":{"type":"boolean","enum":[true]},"value":{"$ref":"#/components/schemas/ExactMoney"},"uncategorizedIncome":{"$ref":"#/components/schemas/UncategorizedIncomeBesideRevenue"},"priorPeriod":{"description":"#2653: the like-for-like comparison, the same days of the previous calendar month (startDate = its 1st; endDate = the same day-of-month, clamped to that month's last day). `percent` is null with state `no_prior_base` when the prior base is <= 0 and `unstable_base` beyond the 1000% cap (#2016: undefined, not 0%).\n","type":"object","required":["startDate","endDate","value","percent","state"],"properties":{"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"value":{"$ref":"#/components/schemas/ExactMoney"},"percent":{"type":["number","null"]},"state":{"type":"string","enum":["available","no_prior_base","unstable_base"]}}},"authority":{"type":"object","required":["companyId","entityId","basis","asOf","month","startDate","endDate"],"properties":{"companyId":{"type":"string"},"entityId":{"type":"string"},"basis":{"type":"string","enum":["month_to_date_posted_revenue"]},"asOf":{"type":"string","format":"date"},"month":{"type":"string","pattern":"^\\\\d{4}-\\\\d{2}$"},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"}}},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}},{"type":"object","required":["available","reason","completeness"],"properties":{"available":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["insufficient_history","source_not_authorized","syncing","stale","failed","mixed_currency","entity_scope_unavailable","incomplete_provenance","truncated"]},"authority":{"type":"object","additionalProperties":true},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}}]},"NetBurnTrailing90dMetric":{"description":"Live Home (founder sync 2026-09-21), basis trailing_90d_posted_operating_net_burn: posted operating costs less posted operating revenue and posted uncategorized income (4999) over the last 90 UTC days (startDate..endDate, endDate = today), divided by 3 half away from zero — the \"last 90 days average\" Monthly burn. Signed: negative is an operating net inflow (not net income). Shares one journal read and one currency scope with revenueMonthToDate.\n","oneOf":[{"type":"object","required":["available","value","authority","completeness"],"properties":{"available":{"type":"boolean","enum":[true]},"value":{"$ref":"#/components/schemas/ExactMoney"},"authority":{"type":"object","required":["companyId","entityId","basis","asOf","startDate","endDate"],"properties":{"companyId":{"type":"string"},"entityId":{"type":"string"},"basis":{"type":"string","enum":["trailing_90d_posted_operating_net_burn"]},"asOf":{"type":"string","format":"date"},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"}}},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}},{"type":"object","required":["available","reason","completeness"],"properties":{"available":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["insufficient_history","source_not_authorized","syncing","stale","failed","mixed_currency","entity_scope_unavailable","incomplete_provenance","truncated"]},"authority":{"type":"object","additionalProperties":true},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}}]},"GrossBurnTrailing90dMetric":{"description":"#1412 J-289 (B), a secondary line under Net burn, basis trailing_90d_posted_operating_gross_burn: posted operating costs (the same inclusion set as netBurnTrailing90d) over the same last 90 UTC days, divided by 3 half away from zero, with no revenue netted. Shares the netBurnTrailing90d journal read, window and currency scope, and is unavailable whenever that read is. Unavailable never carries a value.\n","oneOf":[{"type":"object","required":["available","value","authority","completeness"],"properties":{"available":{"type":"boolean","enum":[true]},"value":{"$ref":"#/components/schemas/ExactMoney"},"authority":{"type":"object","required":["companyId","entityId","basis","asOf","startDate","endDate"],"properties":{"companyId":{"type":"string"},"entityId":{"type":"string"},"basis":{"type":"string","enum":["trailing_90d_posted_operating_gross_burn"]},"asOf":{"type":"string","format":"date"},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"}}},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}},{"type":"object","required":["available","reason","completeness"],"properties":{"available":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["insufficient_history","source_not_authorized","syncing","stale","failed","mixed_currency","entity_scope_unavailable","incomplete_provenance","truncated"]},"authority":{"type":"object","additionalProperties":true},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}}]},"OwnerFinancingTrailing90dMetric":{"description":"#1412 J-289 (B), a secondary line under Net burn, basis trailing_90d_posted_owner_financing_cash_flow: owner distributions, owner contributions, debt proceeds and debt principal repayments as the Cash Flow statement classifies them (cash accounts per the statement, so clearing is never cash; closing entries skipped; opening balance equity left out), over the same last 90 UTC days and journal read as netBurnTrailing90d. `value` is the window total divided by 3 half away from zero. Signed cash-flow convention: positive is cash in (borrowing, owner money in), negative is cash out (draws, principal). `components` and `authority.windowTotalMinor` are exact, un-averaged window totals that reconcile to the Cash Flow statement for the same dates. Fails closed on its own (incomplete_provenance when a compound debt journal cannot be attributed, mixed_currency, not_configured, failed) without affecting Net or Gross burn. Unavailable never carries a value.\n","oneOf":[{"type":"object","required":["available","value","components","authority","completeness"],"properties":{"available":{"type":"boolean","enum":[true]},"value":{"$ref":"#/components/schemas/ExactMoney"},"components":{"type":"object","required":["ownerDistributionsMinor","ownerContributionsMinor","debtProceedsMinor","debtRepaymentsMinor"],"properties":{"ownerDistributionsMinor":{"type":"string","pattern":"^-?\\d+$"},"ownerContributionsMinor":{"type":"string","pattern":"^-?\\d+$"},"debtProceedsMinor":{"type":"string","pattern":"^-?\\d+$"},"debtRepaymentsMinor":{"type":"string","pattern":"^-?\\d+$"}}},"authority":{"type":"object","required":["companyId","entityId","basis","asOf","startDate","endDate","windowTotalMinor"],"properties":{"companyId":{"type":"string"},"entityId":{"type":"string"},"basis":{"type":"string","enum":["trailing_90d_posted_owner_financing_cash_flow"]},"asOf":{"type":"string","format":"date"},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"windowTotalMinor":{"type":"string","pattern":"^-?\\d+$"}}},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}},{"type":"object","required":["available","reason","completeness"],"properties":{"available":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["insufficient_history","source_not_authorized","not_configured","syncing","stale","failed","mixed_currency","entity_scope_unavailable","incomplete_provenance","truncated"]},"authority":{"type":"object","additionalProperties":true},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}}]},"RevenueCompletedMonthMetric":{"description":"Additive Home Revenue headline metric (basis completed_month_posted_revenue): exact signed posted operating revenue over the last completed calendar month (UTC), never the current partial month and never a rolling window, so month-end adjusting entries stay inside the month they correct. `authority.month` names the month (YYYY-MM); startDate/endDate are its first and last day. Never re-scoped by report ranges or the closed-month headline rewrite. The legacy metrics.monthlyRevenue*/metrics.mrr* fields keep their existing behavior for old clients.\n","oneOf":[{"type":"object","required":["available","value","authority","completeness"],"properties":{"available":{"type":"boolean","enum":[true]},"value":{"$ref":"#/components/schemas/ExactMoney"},"uncategorizedIncome":{"$ref":"#/components/schemas/UncategorizedIncomeBesideRevenue"},"authority":{"type":"object","required":["companyId","entityId","basis","asOf","month","startDate","endDate"],"properties":{"companyId":{"type":"string"},"entityId":{"type":"string"},"basis":{"type":"string","enum":["completed_month_posted_revenue"]},"asOf":{"type":"string","format":"date"},"month":{"type":"string","pattern":"^\\\\d{4}-\\\\d{2}$"},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"}}},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}},{"type":"object","required":["available","reason","completeness"],"properties":{"available":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["insufficient_history","source_not_authorized","syncing","stale","failed","mixed_currency","entity_scope_unavailable","incomplete_provenance","truncated"]},"authority":{"type":"object","description":"Partial authority — whatever scope was proven before the failure.","additionalProperties":true},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}}]},"OverviewFxRateAudit":{"type":"object","required":["id","rate","rateType","requestedDate","effectiveAt","source","sourceKind","providerReference"],"properties":{"id":{"type":["string","null"],"format":"uuid","description":"Immutable FX-rate revision id. Null only for an identity conversion."},"rate":{"type":"string","pattern":"^\\d+\\.\\d{15}$"},"rateType":{"type":"string","enum":["spot"]},"requestedDate":{"type":["string","null"],"format":"date"},"effectiveAt":{"type":["string","null"],"format":"date-time"},"source":{"type":"string"},"sourceKind":{"type":"string","enum":["identity","provider","manual"]},"providerReference":{"type":["string","null"]}}},"OverviewPerAccountReconciliation":{"type":"object","required":["accountId","bankAccountId","name","reconciledBalanceCents","bookBalanceCents","differenceCents","lastReconciled","liveCents"],"properties":{"accountId":{"type":["string","null"],"description":"Linked GL (book) cash account id (bank_accounts.gl_account_id). Null when the provider account is not mapped to the GL.\n"},"bankAccountId":{"type":"string","description":"Provider account identifier. Usually a bank_accounts UUID; Stripe cache rows use the Stripe connection identifier. When several live bank accounts map to one GL cash account they are grouped into a single row and this is the first member's id.\n"},"name":{"type":"string","description":"Display name. A live bank account's own name, or the GL cash account's name when several live bank accounts map to that GL (grouped row).\n"},"integrationKind":{"type":"string","enum":["plaid","mercury","brex","ramp","stripe","other"]},"sourceCurrency":{"type":"string","pattern":"^[A-Z]{3}$","description":"Provider-reported currency before presentation conversion. On a grouped row, present only when every member shares one source currency and one rate record; a mixed group omits it and carries sourceBalances instead.\n"},"sourceLiveCents":{"type":"integer","description":"Provider-reported minor units before presentation conversion. On a grouped row this is the sum of the members' source amounts and is present only when every member shares one source currency and one rate record (so sourceLiveCents at fxRate reproduces reconciledBalanceCents); a mixed group omits it and carries sourceBalances instead.\n"},"presentationCurrency":{"type":["string","null"],"pattern":"^[A-Z]{3}$"},"fxRate":{"$ref":"#/components/schemas/OverviewFxRateAudit","description":"Rate record behind sourceLiveCents. On a grouped row, present only when every member shares one source currency and one rate record; a mixed group omits it and carries sourceBalances instead.\n"},"sourceBalances":{"type":"array","description":"Per-connection source amounts and immutable FX provenance when multiple Stripe connections map to one GL cash account, or per-member provenance for a grouped live-bank row whose members do not share one source currency and rate record (connectionId is then the member's bank_accounts id and integrationAccountCurrency is null). Such a row omits sourceCurrency, sourceLiveCents and fxRate.\n","items":{"type":"object","required":["connectionId","sourceLiveCents","sourceCurrency","integrationAccountCurrency","presentationCurrency","presentationLiveCents","fxRate"],"properties":{"connectionId":{"type":"string"},"sourceLiveCents":{"type":"integer"},"sourceCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"integrationAccountCurrency":{"type":["string","null"],"pattern":"^[A-Z]{3}$","description":"Stripe account default currency. It may legitimately differ from the provider balance settlement currency in `sourceCurrency`.\n"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"presentationLiveCents":{"type":"integer"},"fxRate":{"$ref":"#/components/schemas/OverviewFxRateAudit"}}}},"reconciledBalanceCents":{"type":"integer","description":"Live provider (reconciled-side) balance in cents. For a row grouping several live bank accounts on one GL cash account this is the sum of the members' live balances. Alias of liveCents.\n"},"bookBalanceCents":{"type":["integer","null"],"description":"GL book balance in cents for the linked account, computed from POSTED journal lines only (void and soft-deleted entries excluded). Counted once per GL cash account, however many bank accounts map to it. Alias of glCents. Null when unmapped.\n"},"differenceCents":{"type":["integer","null"],"description":"reconciledBalanceCents minus bookBalanceCents. Alias of deltaCents."},"lastReconciled":{"type":["string","null"],"format":"date-time","description":"Completion time of the latest COMPLETED reconciliations row for the bank account (across every member bank account of a grouped row). Null when the account has never been reconciled — never the provider sync time, which is surfaced separately as lastSyncedAt.\n"},"liveCents":{"type":"integer","description":"Legacy alias of reconciledBalanceCents."},"glCents":{"type":["integer","null"],"description":"Legacy alias of bookBalanceCents."},"deltaCents":{"type":["integer","null"],"description":"Legacy alias of differenceCents."},"lastSyncedAt":{"type":["string","null"],"format":"date-time","description":"Latest provider sync time across the row's bank accounts (a grouped row takes the max over its members). Null for GL-fallback rows.\n"},"latestGlEntryAt":{"type":["string","null"],"format":"date"},"discrepancyExplanation":{"type":"string"}}},"OverviewData":{"type":"object","required":["metrics","booksStatus","booksStatusAvailability","financialSnapshot","monthlyRevenue","expenseBreakdown","revenueByProduct"],"properties":{"presentationCurrency":{"type":["string","null"],"pattern":"^[A-Z]{3}$","description":"Currency used for every aggregate monetary amount in this response."},"metrics":{"$ref":"#/components/schemas/OverviewMetrics"},"booksStatus":{"type":["object","null"],"additionalProperties":true,"description":"Books status is company-wide, not legal-entity-dimensional. Served for an unscoped Home request and for the company's sole non-group legal entity (it owns every company activity); null for one legal entity of a real multi-entity company, or when the entity roster cannot be verified (see booksStatusAvailability). Never fabricated.\n"},"booksStatusAvailability":{"$ref":"#/components/schemas/HomeBooksStatusAvailability"},"financialSnapshot":{"type":"object","additionalProperties":true},"perAccountReconciliation":{"type":"array","items":{"$ref":"#/components/schemas/OverviewPerAccountReconciliation"}},"monthlyRevenue":{"type":"array","description":"Monthly chart series. Length is governed by the optional `?months=` query param (clamped 1-12, default 6).\n","items":{"type":"object","additionalProperties":true}},"expenseBreakdown":{"type":"array","items":{"type":"object","additionalProperties":true}},"revenueByProduct":{"type":"array","items":{"type":"object","additionalProperties":true}},"businessModel":{"description":"The company's stored business model (#1967), which decides the Home board. Never re-derived on read. Null only when the stored value is unset or unregistered (including the retired `general`); the API reports that to Sentry and Home renders an error card.\n","oneOf":[{"type":"null"},{"type":"string","enum":["software","services","digital","ecommerce","manufacturing"]}]},"businessModelSource":{"description":"Provenance of the stored business model (display only; never drives rendering). Null when businessModel is null.","oneOf":[{"type":"null"},{"type":"string","enum":["override","industry","revenue_streams","default"]}]},"additionalMetrics":{"type":"array","description":"Per-company additional Home metric packs enabled by an accountant (#1967); empty when none. Each listed pack renders at the bottom of the Home board.","items":{"type":"string","enum":["practice_metrics"]}},"reconciliation":{"type":"object","description":"Reconciliation chip state for the home dashboard.","properties":{"status":{"type":"string","enum":["reconciled","pending","attention"],"description":"reconciled: abs(delta) < $100 and no stale accounts; attention: abs(delta) >= $1000 or a stale/disconnected account; pending: everything else.\n"}},"required":["status"]},"revenueMix":{"description":"Revenue-mix breakdown (deferred — null until finance spec finalized).\n","oneOf":[{"type":"null"},{"type":"object","additionalProperties":true}]},"revenueCompletedMonth":{"$ref":"#/components/schemas/RevenueCompletedMonthMetric"},"revenueMonthToDate":{"$ref":"#/components/schemas/RevenueMonthToDateMetric"},"netBurnTrailing90d":{"$ref":"#/components/schemas/NetBurnTrailing90dMetric"},"grossBurnTrailing90d":{"$ref":"#/components/schemas/GrossBurnTrailing90dMetric"},"ownerFinancingTrailing90d":{"$ref":"#/components/schemas/OwnerFinancingTrailing90dMetric"},"monthlyRevenueInProgress":{"description":"Live Home (founder sync 2026-09-21): the in-progress calendar month's exact series point, in the same shape as a monthlyRevenueMoney row plus `postedThrough` (YYYY-MM-DD, the day the figures run to). Kept OUT of monthlyRevenue/monthlyRevenueMoney so old clients and Closed-only mode keep comparing full months. Null when the series has no current-month point.\n","oneOf":[{"type":"null"},{"type":"object","additionalProperties":true,"required":["month","revenueCents","expensesCents","netCents","postedThrough"],"properties":{"month":{"type":"string","example":"Sep 2026"},"revenueCents":{"type":["integer","null"]},"expensesCents":{"type":["integer","null"]},"netCents":{"type":["integer","null"]},"currency":{"type":["string","null"]},"minorUnitExponent":{"type":["integer","null"]},"postedThrough":{"type":"string","format":"date"}}}]},"totalCustomers":{"$ref":"#/components/schemas/TotalCustomersMetric"},"knownCustomerRecords":{"$ref":"#/components/schemas/KnownCustomerRecordsMetric"}}},"TotalCustomersMetric":{"description":"Full-census external-customer claim (F09, additive), basis `entity_customer_census`. Available only when the entity's customer sources have been enumerated, every active one holds a committed census watermark that is still within the freshness bound, every counted master record carries a durable classification, and no invoice-linked payer identity is still outside the master enumeration. Its `completeness` flags answer \"is the CENSUS complete\". An unavailable claim never carries a count; an authoritative zero is `available: true` with `count: 0`. When this claim is unavailable the UI falls back to `knownCustomerRecords`, which answers a different question under its own basis — compare `authority.basis` before treating the two as interchangeable.\n","oneOf":[{"type":"object","required":["available","value","authority","completeness"],"properties":{"available":{"type":"boolean","enum":[true]},"value":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","minimum":0}}},"authority":{"type":"object","required":["companyId","entityId","basis","asOf"],"properties":{"companyId":{"type":"string"},"entityId":{"type":"string"},"basis":{"type":"string","enum":["entity_customer_census"]},"asOf":{"type":"string","format":"date-time"}}},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}},{"type":"object","required":["available","reason","completeness"],"properties":{"available":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["insufficient_history","source_not_authorized","not_configured","syncing","stale","failed","mixed_currency","entity_scope_unavailable","incomplete_provenance","truncated"]},"authority":{"type":"object","description":"Partial authority — never carries asOf-backed value claims.","additionalProperties":true},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}}]},"KnownCustomerRecordsMetric":{"description":"Canonical known-record fallback claim (F09, additive), basis `entity_customer_master` — deliberately NOT `entity_customer_census`. It counts every non-merged customer master record for the entity minus rows durably classified internal/test, and its `completeness` flags answer \"is the LOCAL MASTER ENUMERATION complete\", not \"is the census complete\". The same response may therefore report `sourceComplete: false` on `totalCustomers` and `true` here for one scope: the two claims answer different questions, which the distinct basis is what makes machine-readable. The UI renders it as \"Known customer records\". An unavailable claim never carries a count; an authoritative zero is `available: true` with `count: 0`.\n","oneOf":[{"type":"object","required":["available","value","authority","completeness"],"properties":{"available":{"type":"boolean","enum":[true]},"value":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","minimum":0}}},"authority":{"type":"object","required":["companyId","entityId","basis","asOf"],"properties":{"companyId":{"type":"string"},"entityId":{"type":"string"},"basis":{"type":"string","enum":["entity_customer_master"]},"asOf":{"type":"string","format":"date-time"}}},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}},{"type":"object","required":["available","reason","completeness"],"properties":{"available":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["insufficient_history","source_not_authorized","syncing","stale","failed","mixed_currency","entity_scope_unavailable","incomplete_provenance","truncated"]},"authority":{"type":"object","description":"Partial authority — never carries asOf-backed value claims.","additionalProperties":true},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}}]},"OverviewResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/OverviewData"}}},"OverviewActivitySummaryData":{"type":"object","required":["windowDays","startDate","endDate","transactionsCategorized","documentsMatched","businessEventsRecorded","reconciliationsCompleted","booksStatus","booksStatusAvailability"],"properties":{"windowDays":{"type":"integer","minimum":1,"maximum":90},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"transactionsCategorized":{"type":"integer","minimum":0},"documentsMatched":{"type":"integer","minimum":0},"businessEventsRecorded":{"type":"integer","minimum":0},"reconciliationsCompleted":{"type":"integer","minimum":0},"booksStatus":{"type":["object","null"],"additionalProperties":true,"description":"Books status is company-wide, not legal-entity-dimensional. Served for an unscoped activity request and for the company's sole non-group legal entity (it owns every company activity); null for one legal entity of a real multi-entity company, or when the entity roster cannot be verified (see booksStatusAvailability). Never fabricated.\n"},"booksStatusAvailability":{"$ref":"#/components/schemas/HomeBooksStatusAvailability"}}},"HomeBooksStatusAvailability":{"type":"object","required":["available","reason"],"properties":{"available":{"type":"boolean","description":"True for an unscoped request or the company's sole non-group legal entity, to which the company-wide books status is honestly attributable. False for one legal entity of a real multi-entity company, or when the entity roster cannot be verified (no roster, read failure, or an entity not on it): fail closed, never widened.\n"},"reason":{"type":["string","null"],"enum":["entity_scope_unavailable",null],"description":"entity_scope_unavailable whenever available is false; null when available is true."}}},"OverviewActivitySummaryResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/OverviewActivitySummaryData"}}},"AutonomousImpactTotals":{"type":"object","required":["glLineItemsPosted","documentsMatched","transfersApplied","rulesLearned","anomaliesDetected"],"properties":{"glLineItemsPosted":{"type":["integer","null"],"description":"Journal lines Median posted (engine or accountant), including transactions, accruals, deferrals, and depreciation. Excludes entries a company member posted themselves."},"documentsMatched":{"type":["integer","null"],"description":"Distinct documents (receipts, bills, contracts, invoices) Median matched to transactions."},"transfersApplied":{"type":["integer","null"],"description":"Internal transfers + credit-card payments Median applied (engine or accountant)."},"rulesLearned":{"type":["integer","null"],"description":"Categorization rules Median learned for the company (merchant rules)."},"anomaliesDetected":{"type":["integer","null"],"description":"True anomalies caught (duplicates today; widens to fraud + other anomalies). Excludes low-confidence review flags."}}},"AutonomousImpactMetricAvailability":{"oneOf":[{"type":"object","required":["available","reason"],"properties":{"available":{"type":"boolean","const":true},"reason":{"type":"null"}}},{"type":"object","required":["available","reason"],"properties":{"available":{"type":"boolean","const":false},"reason":{"type":"string","enum":["not_wired","entity_scope_unavailable","read_failed"]}}}]},"AutonomousImpactAvailability":{"type":"object","required":["glLineItemsPosted","documentsMatched","transfersApplied","rulesLearned","anomaliesDetected"],"properties":{"glLineItemsPosted":{"$ref":"#/components/schemas/AutonomousImpactMetricAvailability"},"documentsMatched":{"$ref":"#/components/schemas/AutonomousImpactMetricAvailability"},"transfersApplied":{"$ref":"#/components/schemas/AutonomousImpactMetricAvailability"},"rulesLearned":{"$ref":"#/components/schemas/AutonomousImpactMetricAvailability"},"anomaliesDetected":{"$ref":"#/components/schemas/AutonomousImpactMetricAvailability"}}},"AutonomousImpactData":{"type":"object","required":["enabled","period","startDate","endDate","totals","availability"],"properties":{"enabled":{"type":"boolean"},"period":{"type":"string","enum":["this_month","last_month"]},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"totals":{"$ref":"#/components/schemas/AutonomousImpactTotals"},"availability":{"$ref":"#/components/schemas/AutonomousImpactAvailability"}}},"AutonomousImpactResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AutonomousImpactData"}}},"ArTurnoverMetric":{"type":"object","required":["available","value","asOf"],"properties":{"available":{"type":"boolean"},"value":{"type":["number","null"]},"asOf":{"type":["string","null"],"format":"date"}}},"MrrMetric":{"type":"object","required":["available","currentMinorUnits","newMinorUnits","expansionMinorUnits","reactivationMinorUnits","contractionMinorUnits","churnedMinorUnits","projectedMinorUnits","contractedMinorUnits","currency","minorUnitExponent","asOf"],"properties":{"available":{"type":"boolean","description":"True when the completed-month waterfall (asOf names its month) and/or the live current-month block is complete."},"live":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MrrLiveFields"}]},"currentMinorUnits":{"type":["string","null"],"pattern":"^(0|[1-9][0-9]*)$"},"newMinorUnits":{"type":["string","null"],"pattern":"^(0|[1-9][0-9]*)$"},"expansionMinorUnits":{"type":["string","null"],"pattern":"^(0|[1-9][0-9]*)$"},"reactivationMinorUnits":{"type":["string","null"],"pattern":"^(0|[1-9][0-9]*)$"},"contractionMinorUnits":{"type":["string","null"],"pattern":"^(0|[1-9][0-9]*)$"},"churnedMinorUnits":{"type":["string","null"],"pattern":"^(0|[1-9][0-9]*)$"},"projectedMinorUnits":{"type":["string","null"],"pattern":"^(0|[1-9][0-9]*)$","description":"FORWARD-LOOKING, not part of the completed-month snapshot: the current month's projected MRR from live subscription state. Do not present it under the same period label as the waterfall components.\n"},"contractedMinorUnits":{"type":["string","null"],"pattern":"^(0|[1-9][0-9]*)$","description":"FORWARD-LOOKING: contracted MRR computed from LIVE subscriptions at request time, not from the completed-month snapshot.\n"},"currency":{"type":["string","null"],"pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":["integer","null"],"minimum":0,"maximum":9},"asOf":{"type":["string","null"],"format":"date","description":"Completed calendar month the waterfall fields describe (YYYY-MM-01) — never the current partial month. Null when unavailable.\n"},"reason":{"type":["string","null"],"enum":["source_not_authorized","entity_access_required","syncing","stale","failed","mixed_currency","insufficient_history","incomplete_provenance",null],"description":"Customer-safe availability reason; present only when available:false. Distinguishes an unwired billing source from syncing, stale, failed, mixed-currency, and insufficient-history states (never internal identifiers).\n"},"excludedSubscriptionCount":{"type":"integer","minimum":0,"description":"Subscriptions in a status current MRR counts (active or past_due) left out of these figures because their recurring price cannot be confirmed from Stripe (for example a discount whose terms Stripe no longer returns and whose billed effect is ambiguous, stacked discounts, or a tiered price). Cancelled or trialing subscriptions are not counted. For a sync sealed before this count existed, every left-out subscription is counted. They are never counted or estimated; one such subscription no longer freezes the whole company's MRR. Present when available; 0 when nothing was left out.\n"},"excludedSubscriptionReasons":{"type":"array","description":"Why the subscriptions in excludedSubscriptionCount were left out, one entry per reason with its count, largest first. Empty when nothing was left out or the reasons were not recorded.\n","items":{"type":"object","required":["reason","count"],"properties":{"reason":{"type":"string","enum":["tiered_or_metered_price","discount_terms_unavailable","stacked_discounts","amount_unavailable"]},"count":{"type":"integer","minimum":1}}}}}},"LtvMetric":{"type":"object","description":"Entity LTV (#1944) = ARPA x gross margin x min(1 / monthly churn, 200 months), in integer minor units. Window W = the trailing 12 completed months ending at the last completed month (all completed months when fewer than 12 exist). ARPA = the last completed month's MRR / active customers; monthly churn = sum of churned MRR over W / sum of opening MRR over W (opening = the prior month's close), from the legal entity's authoritative MRR snapshots (the Home MRR substrate, so one-off charges, fees and refunds never move it). Gross margin = (operating revenue - COGS) / operating revenue from the same entity's posted P&L over W; operating revenue excludes other income (e.g. interest) and 4999 Uncategorized Income. `value` is major units of LTV's own `currency`. An unavailable metric carries `reason` and never a numeric zero; `no_observed_churn` means churn was zero across the whole window, so no finite lifetime is reported.\n","required":["available","value"],"properties":{"available":{"type":"boolean"},"value":{"type":["number","null"],"description":"Legacy major units (ltvMoney.amountMinor / 10^minorUnitExponent). Prefer `ltvMoney`."},"reason":{"type":["string","null"],"enum":["source_not_authorized","entity_access_required","syncing","stale","failed","mixed_currency","insufficient_history","incomplete_provenance","not_configured","insufficient_inputs","no_observed_churn",null]},"currency":{"type":["string","null"],"pattern":"^[A-Z]{3}$","description":"LTV's own money authority (the entity's MRR billing currency). Present when available; render in this currency, never the envelope's."},"minorUnitExponent":{"type":["integer","null"]},"ltvMoney":{"description":"Exact LTV in integer minor units (the shared ExactMoney shape, as CAC's `cacMoney`). Prefer this over the legacy major-unit float `value`; clients fail closed without it.","oneOf":[{"$ref":"#/components/schemas/ExactMoney"},{"type":"null"}]}}},"CacMetric":{"type":"object","description":"The CAC headline. Served under the `cac` key of GET /metrics/saas and as `metric` on GET /metrics/cac. `value` is the LEGACY major-unit float kept for old clients; new consumers read `cacMoney`, the shared ExactMoney shape (master-index pin P2). The money authority is the ENTITY's functional currency, which can differ from the envelope's subscription billing currency — render from `currency`/`minorUnitExponent` here, never from the envelope's. An unavailable metric carries `reason` and never a numeric zero.\n","required":["available","value","smSpendCents","newCustomers"],"properties":{"available":{"type":"boolean"},"value":{"type":["number","null"],"description":"Legacy major units (cacCents / 100). Prefer `cacMoney`."},"smSpendCents":{"type":["integer","null"]},"newCustomers":{"type":["integer","null"]},"currency":{"type":["string","null"],"pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":["integer","null"]},"cacMoney":{"oneOf":[{"$ref":"#/components/schemas/ExactMoney"},{"type":"null"}]},"smSpendMoney":{"oneOf":[{"$ref":"#/components/schemas/ExactMoney"},{"type":"null"}]},"reason":{"oneOf":[{"$ref":"#/components/schemas/CacUnavailableReason"},{"type":"null"}]}}},"SaasMetricsData":{"type":"object","required":["companyId","entityId","currency","minorUnitExponent","enabled","mixedCurrencies","arTurnover","mrr","ltv","cac"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"currency":{"type":["string","null"],"pattern":"^[A-Z]{3}$","description":"Authoritative uppercase ISO 4217 currency for this entity's metrics. Null — never an assumed USD — when there are no subscriptions, the source is unwired, or currencies are mixed.\n"},"minorUnitExponent":{"type":["integer","null"],"minimum":0,"maximum":9},"enabled":{"type":"boolean"},"mixedCurrencies":{"type":"boolean","description":"True when subscriptions carry more than one currency (currency is null); false when there is one currency or simply no data.\n"},"arTurnover":{"$ref":"#/components/schemas/ArTurnoverMetric"},"mrr":{"$ref":"#/components/schemas/MrrMetric"},"ltv":{"$ref":"#/components/schemas/LtvMetric"},"cac":{"$ref":"#/components/schemas/CacMetric"}}},"PracticeMetricKey":{"type":"string","description":"Metric vocabulary of the practice-metrics feed. `*_by_member` and `*_by_channel` series are dimensioned by `dimensionKey`; the rest are per-period scalars (dimensionKey '').\n","enum":["revenue_by_member","direct_cost_by_member","hours_booked_by_member","hours_delivered_by_member","spend_by_channel","customers_by_channel","overhead_pool","owner_pay","owner_draws","owner_billings","net_income_before_owner_pay"]},"PracticeMetricUnit":{"type":"string","enum":["cents","percent","hours","count"]},"PracticeMetricPoint":{"type":"object","required":["metricKey","period","dimensionKey","value","unit","computedAt","source","importedAt"],"properties":{"metricKey":{"$ref":"#/components/schemas/PracticeMetricKey"},"period":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$","description":"Calendar month, YYYY-MM."},"dimensionKey":{"type":"string","description":"Patient-free label (staff display name/stable label or channel name); empty string for scalar metrics.\n"},"value":{"type":"number","description":"Integer cents when unit is `cents`."},"unit":{"$ref":"#/components/schemas/PracticeMetricUnit"},"currency":{"type":["string","null"],"pattern":"^[A-Z]{3}$","description":"ISO 4217 code the feed declared for a `cents` series; null when undeclared (never inferred)."},"computedAt":{"type":["string","null"],"format":"date-time"},"source":{"type":["string","null"],"description":"Feed-source label recorded for this row."},"importedAt":{"type":["string","null"],"format":"date-time","description":"Latest import timestamp for this row."}}},"PracticeConfig":{"type":"object","required":["overheadAllocationBasis","ownerCompensationCents","ownerDrawSplitPct"],"properties":{"overheadAllocationBasis":{"type":"string","enum":["revenue","hours","headcount"],"description":"How the overhead pool is allocated across members."},"ownerCompensationCents":{"type":["integer","null"],"description":"S-corp reasonable-comp reference, integer cents; null until set."},"ownerDrawSplitPct":{"type":["number","null"],"minimum":0,"maximum":100}}},"PracticeConfigInput":{"type":"object","description":"Partial practice config — omitted fields keep their stored values.","properties":{"overheadAllocationBasis":{"type":"string","enum":["revenue","hours","headcount"]},"ownerCompensationCents":{"type":["integer","null"]},"ownerDrawSplitPct":{"type":["number","null"],"minimum":0,"maximum":100}}},"UploadPracticeMetricsRequest":{"type":"object","required":["series"],"description":"Capped at 2000 points per request. `cents` series values must be integers; duplicate (period, dimensionKey) points within a series are rejected. Dimension keys may be staff display names or channel names but must not contain patient identifiers; email-shaped and phone-number-shaped values are rejected. `retireDimensionKeys` deletes only those listed labels for the customer before the upsert; a key listed there and also present in `series` is rejected (422).\n","properties":{"series":{"type":"array","minItems":1,"items":{"type":"object","required":["metricKey","unit","points"],"properties":{"metricKey":{"$ref":"#/components/schemas/PracticeMetricKey"},"unit":{"$ref":"#/components/schemas/PracticeMetricUnit"},"currency":{"type":"string","pattern":"^[A-Z]{3}$","description":"ISO 4217 code of a `cents` series' values; must be a supported two-decimal currency (422 otherwise, or on a non-`cents` series). Optional; Home holds profit by team member until member revenue, direct cost and overhead pool all declare the books' currency. Re-uploading a series without it clears the stored declaration."},"points":{"type":"array","minItems":1,"items":{"type":"object","required":["period","value"],"properties":{"period":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"},"dimensionKey":{"type":"string","maxLength":60,"description":"De-identified token; omit for scalar metrics."},"value":{"type":"number"},"computedAt":{"type":"string","format":"date-time"}}}}}}},"practiceConfig":{"$ref":"#/components/schemas/PracticeConfigInput"},"retireDimensionKeys":{"type":"array","maxItems":200,"description":"Explicit superseded dimension labels to delete before this upsert (for example `member_a` after a clinician-name re-upload). Empty string (scalar) keys are rejected.\n","items":{"type":"string"}}}},"UploadPracticeMetricsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["upsertedPoints","retiredPoints","config"],"properties":{"upsertedPoints":{"type":"integer","description":"Rows written by this upload (inserts + updates)."},"retiredPoints":{"type":"integer","description":"Rows deleted because their dimension key was listed in retireDimensionKeys."},"config":{"$ref":"#/components/schemas/PracticeConfig"}}}}},"PracticeMetricPointsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["points"],"properties":{"points":{"type":"array","items":{"$ref":"#/components/schemas/PracticeMetricPoint"}}}}}},"PinnedMetric":{"type":"object","required":["widgetKey","position"],"properties":{"widgetKey":{"type":"string","maxLength":100},"position":{"type":"integer","minimum":0,"maximum":999}}},"UpdatePinnedMetricsRequest":{"type":"object","required":["pins"],"properties":{"pins":{"type":"array","maxItems":50,"items":{"$ref":"#/components/schemas/PinnedMetric"}}}},"PinnedMetricsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["pins"],"properties":{"pins":{"type":"array","items":{"$ref":"#/components/schemas/PinnedMetric"}}}}}},"PracticeWidgetUnavailable":{"type":"object","required":["available","reason"],"properties":{"available":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["not_in_catalog","missing_data"]},"missing":{"type":"array","description":"Metric keys whose absence keeps the widget unavailable.","items":{"$ref":"#/components/schemas/PracticeMetricKey"}}}},"PracticeProfitByTeamMemberWidget":{"oneOf":[{"$ref":"#/components/schemas/PracticeWidgetUnavailable"},{"type":"object","required":["available","period","members","overheadPoolCents","allocationBasis","ledgerRevenueCents","currency","ledgerRevenueCurrency"],"properties":{"available":{"type":"boolean","enum":[true]},"period":{"type":"string"},"currency":{"type":["string","null"],"description":"ISO 4217 code that every profit input for the month (member revenue, direct cost, overhead pool) declares. Null when any input is undeclared or they disagree: the member figures are then bare cents of unconfirmed currency."},"ledgerRevenueCurrency":{"type":["string","null"],"description":"The books' functional currency for `ledgerRevenueCents`; null exactly when that is. Compare the two figures only when this equals `currency`."},"ledgerRevenueCents":{"type":["integer","null"],"description":"Revenue in the company's books for the same month (operating revenue as on Home: other income and Uncategorized Income excluded), for comparison with the practice feed's member revenue. Null — unknown, not zero — when the month is still in progress, has no posted journal entries yet, or the ledger figure could not be read."},"overheadPoolCents":{"type":["integer","null"],"description":"Null when no overhead pool was uploaded — overhead allocation is then unknown, not zero."},"allocationBasis":{"type":"string","enum":["revenue","hours","headcount"]},"members":{"type":"array","items":{"type":"object","required":["member","revenueCents","directCostCents","allocatedOverheadCents","contributionCents"],"properties":{"member":{"type":"string"},"revenueCents":{"type":"integer"},"directCostCents":{"type":["integer","null"]},"allocatedOverheadCents":{"type":["integer","null"]},"contributionCents":{"type":["integer","null"],"description":"Null whenever any input is unknown — never guessed."}}}}}}]},"PracticeRealizationRateWidget":{"oneOf":[{"$ref":"#/components/schemas/PracticeWidgetUnavailable"},{"type":"object","required":["available","period","members","totalHoursBooked","totalHoursDelivered","totalRealizationPct"],"properties":{"available":{"type":"boolean","enum":[true]},"period":{"type":"string"},"totalHoursBooked":{"type":"number"},"totalHoursDelivered":{"type":"number"},"totalRealizationPct":{"type":["number","null"]},"members":{"type":"array","items":{"type":"object","required":["member","hoursBooked","hoursDelivered","realizationPct","unrealizedValueCents"],"properties":{"member":{"type":"string"},"hoursBooked":{"type":"number"},"hoursDelivered":{"type":"number"},"realizationPct":{"type":["number","null"]},"unrealizedValueCents":{"type":["integer","null"],"description":"Booked-but-undelivered value at the member's effective rate; null without revenue."}}}}}}]},"PracticeSpendByChannelWidget":{"oneOf":[{"$ref":"#/components/schemas/PracticeWidgetUnavailable"},{"type":"object","required":["available","period","spendSource","channels","totalSpendCents","unattributedSpendPct"],"properties":{"available":{"type":"boolean","enum":[true]},"period":{"type":"string"},"spendSource":{"type":"string","enum":["ledger","upload"],"description":"ledger = posted GL expense on marketing accounts, one channel per account (tier 1), used when two or more marketing accounts carry spend in the month or nothing was uploaded; upload = the accountant feed otherwise."},"totalSpendCents":{"type":"integer"},"unattributedSpendPct":{"type":["number","null"],"description":"Share of spend whose channel has no customer denominator."},"channels":{"type":"array","items":{"type":"object","required":["channel","spendCents","customers","costPerCustomerCents"],"properties":{"channel":{"type":"string"},"spendCents":{"type":"integer"},"customers":{"type":["integer","null"]},"costPerCustomerCents":{"type":["integer","null"],"description":"Null = cost per customer unknown (no denominator) — never fabricated."}}}}}}]},"PracticeOwnerPayVsProfitWidget":{"oneOf":[{"$ref":"#/components/schemas/PracticeWidgetUnavailable"},{"type":"object","required":["available","period","ownerPayCents","ownerDrawsCents","ownerBillingsCents","netIncomeBeforeOwnerPayCents","profitAfterOwnerPayCents","reasonableCompCents"],"properties":{"available":{"type":"boolean","enum":[true]},"period":{"type":"string"},"ownerPayCents":{"type":["integer","null"]},"ownerDrawsCents":{"type":["integer","null"]},"ownerBillingsCents":{"type":["integer","null"]},"netIncomeBeforeOwnerPayCents":{"type":["integer","null"]},"profitAfterOwnerPayCents":{"type":["integer","null"]},"reasonableCompCents":{"type":["integer","null"],"description":"The configured S-corp reasonable-comp reference; null until set."}}}]},"PracticeMetricsEnvelopeResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["businessModel","catalog","config","pins","latestPeriod","computedAt","importedAt","sources","widgetPeriods","widgets"],"properties":{"businessModel":{"type":["string","null"],"description":"The company's stored business model (#1967), the catalog's services axis."},"catalog":{"type":"object","description":"Two-axis widget catalog: `services` gates the per-person widgets, `owner` keys on the ownership axis (entity type), and spend-by-channel is shared — never gated.\n","required":["services","owner","shared"],"properties":{"services":{"type":"boolean"},"owner":{"type":"boolean"},"shared":{"type":"boolean","enum":[true]}}},"config":{"$ref":"#/components/schemas/PracticeConfig"},"pins":{"type":"array","items":{"$ref":"#/components/schemas/PinnedMetric"}},"latestPeriod":{"type":["string","null"],"description":"Newest YYYY-MM on any stored point. Not proof every widget is complete through that month."},"computedAt":{"type":["string","null"],"format":"date-time","description":"Newest source-computation timestamp across stored points; independent of import time."},"importedAt":{"type":["string","null"],"format":"date-time","description":"Latest database import timestamp across the feed rows."},"sources":{"type":"array","description":"Distinct feed-source labels represented in the returned rows.","items":{"type":"string"}},"widgetPeriods":{"type":"array","description":"Distinct YYYY-MM values the available widgets actually assembled.","items":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"}},"widgets":{"type":"object","required":["profitByTeamMember","realizationRate","spendByChannel","ownerPayVsProfit"],"properties":{"profitByTeamMember":{"$ref":"#/components/schemas/PracticeProfitByTeamMemberWidget"},"realizationRate":{"$ref":"#/components/schemas/PracticeRealizationRateWidget"},"spendByChannel":{"$ref":"#/components/schemas/PracticeSpendByChannelWidget"},"ownerPayVsProfit":{"$ref":"#/components/schemas/PracticeOwnerPayVsProfitWidget"}}}}}}},"MrrCurrentStateResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/MrrCurrentStateData"}}},"MrrCurrentStateData":{"type":"object","additionalProperties":false,"required":["contract","contractVersion","companyId","entityId","enabled","enrolled","mode","state","reason","revision","readAt","current","freshness","history"],"properties":{"contract":{"type":"string","const":"median.mrr_current_state"},"contractVersion":{"type":"integer","const":1},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"enabled":{"type":"boolean","description":"home_saas_metrics presentation permission; does not establish current-data readiness."},"enrolled":{"type":"boolean","description":"An incremental enrollment exists. Suspended enrollment does not authorize a classic-current fallback."},"mode":{"type":["string","null"],"enum":["incremental",null]},"state":{"type":"string","enum":["initializing","live","catching_up","stale","unavailable"]},"reason":{"type":["string","null"],"description":"Customer-safe readiness reason, or null when no reason is needed. Internal provider identities and payloads are never included."},"revision":{"type":["string","null"],"pattern":"^(0|[1-9][0-9]*)$","description":"Exact entity publication revision, without floating-point conversion."},"readAt":{"type":"string","format":"date-time"},"current":{"description":"Atomically published current recurring figures, or null when unavailable or withheld by stale-value policy.","anyOf":[{"$ref":"#/components/schemas/MrrCurrentBlock"},{"type":"null"}]},"freshness":{"$ref":"#/components/schemas/MrrCurrentFreshness"},"history":{"type":"object","additionalProperties":false,"required":["status","reason","completeFrom"],"properties":{"status":{"type":"string","const":"unavailable"},"reason":{"type":"string","const":"not_proven"},"completeFrom":{"type":"null"}}}}},"MrrCurrentBlock":{"type":"object","additionalProperties":false,"required":["asOf","currency","minorUnitExponent","currentMinorUnits","projectedMinorUnits","contractedMinorUnits","payingSubscriptionCount","activeSubscriptionCount","activeCustomerCount","intervalSplit"],"properties":{"asOf":{"type":"string","format":"date-time","description":"UTC publication time of this revision, not a completed-month accounting as-of."},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer","minimum":0},"currentMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$","description":"Exact normalized current recurring run-rate in currency minor units."},"projectedMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"},"contractedMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"},"payingSubscriptionCount":{"type":"integer","minimum":0},"activeSubscriptionCount":{"type":"integer","minimum":0},"activeCustomerCount":{"type":"integer","minimum":0},"intervalSplit":{"type":"array","minItems":3,"maxItems":3,"items":{"$ref":"#/components/schemas/MrrCurrentIntervalRow"}}}},"MrrCurrentIntervalRow":{"type":"object","additionalProperties":false,"required":["key","mrrMinorUnits","subscriptionCount"],"properties":{"key":{"type":"string","enum":["monthly","annual","other"]},"mrrMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"},"subscriptionCount":{"type":"integer","minimum":0}}},"MrrCurrentFreshness":{"type":"object","additionalProperties":false,"required":["publishedAt","recoveryCompletedThrough","oldestPendingReceivedAt","pendingWorkCount","pendingWorkCountIsLowerBound","heldWorkCount","baselineCompletedAt","lastReconciledAt"],"properties":{"publishedAt":{"type":["string","null"],"format":"date-time"},"recoveryCompletedThrough":{"type":["string","null"],"format":"date-time","description":"Oldest completed recovery frontier; null if any source frontier is unknown."},"oldestPendingReceivedAt":{"type":["string","null"],"format":"date-time"},"pendingWorkCount":{"type":"integer","minimum":0},"pendingWorkCountIsLowerBound":{"type":"boolean","description":"True when the reader capped the count; the actual backlog is at least this value."},"heldWorkCount":{"type":"integer","minimum":0},"baselineCompletedAt":{"type":["string","null"],"format":"date-time","description":"Completion time of the baseline provider walk; null when no completed walk is recorded."},"lastReconciledAt":{"type":["string","null"],"format":"date-time","description":"Null when no independently recorded reconciliation time is available."}}},"SaasMetricsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SaasMetricsData"}}},"MrrByIntervalResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["available","reason","asOf","currency","minorUnitExponent","totalMinorUnits","subscriptionCount","rows"],"properties":{"available":{"type":"boolean"},"reason":{"type":["string","null"],"description":"Null when available; otherwise an MRR readiness reason, `no_subscriptions`, or `unreconciled`."},"asOf":{"type":["string","null"],"format":"date","description":"Month start of the current-month MRR snapshot the split reconciles to."},"currency":{"type":["string","null"]},"minorUnitExponent":{"type":["integer","null"]},"totalMinorUnits":{"type":["string","null"],"pattern":"^(0|[1-9][0-9]*)$","description":"Equals the Home MRR tile's live current MRR."},"subscriptionCount":{"type":"integer","minimum":0},"rows":{"type":"array","items":{"type":"object","required":["key","mrrMinorUnits","subscriptionCount"],"properties":{"key":{"type":"string","enum":["monthly","annual","other"]},"mrrMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"},"subscriptionCount":{"type":"integer","minimum":0}}}}}}}},"MrrMovementsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/MrrMovementsData"}}},"MrrMovementsData":{"type":"object","required":["companyId","entityId","enabled","available","currency","minorUnitExponent","asOf","period","historyCompleteFrom","months"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"enabled":{"type":"boolean","description":"home_saas_metrics rollout flag for this company."},"available":{"type":"boolean","description":"True when snapshots exist and have one authoritative billing currency."},"unavailableReason":{"type":"string","enum":["mixed_currency","currency_unavailable"],"description":"Why persisted history cannot be presented without misstating currency."},"currency":{"type":["string","null"],"pattern":"^[A-Z]{3}$","description":"Authoritative ISO billing currency, or null when unavailable."},"minorUnitExponent":{"type":["integer","null"],"minimum":0,"maximum":9,"description":"Exact minor-unit scale for every amount in the response."},"asOf":{"type":["string","null"],"description":"Last completed calendar month included (YYYY-MM) — the current partial month is excluded from every window before slicing. Null when unavailable.\n"},"period":{"type":"object","required":["requestedMonths","startMonth","endMonth","monthKeys"],"description":"Resolved completed-month window actually returned.","properties":{"requestedMonths":{"type":"integer","minimum":1,"maximum":24},"startMonth":{"type":["string","null"],"example":"2025-08"},"endMonth":{"type":["string","null"],"example":"2026-07"},"monthKeys":{"type":"array","items":{"type":"string","example":"2026-07"}}}},"historyCompleteFrom":{"type":["string","null"],"example":"2025-11","description":"Persisted full-census coverage start (YYYY-MM) — stored authority, never inferred from observed events. Null when any expected source lacks full-census coverage.\n"},"reason":{"type":"string","enum":["source_not_authorized","entity_access_required","syncing","stale","failed","mixed_currency","insufficient_history","incomplete_provenance"],"description":"Customer-safe availability reason; present only when available:false."},"months":{"type":"array","description":"Ascending by month; at most the requested window.","items":{"$ref":"#/components/schemas/MrrMovementMonth"}},"coverageGaps":{"type":"array","description":"Present only when reconstructed invoice history is activated for the entity: completed months (YYYY-MM) inside the window that no source covers. They are absent from months, never shown as zero.\n","items":{"type":"string","example":"2026-09"}},"historyRefusal":{"type":"string","enum":["seam_unverified","seam_discontinuity"],"description":"Present only when an activated reconstruction was refused; the answer is then unavailable."},"labelledGaps":{"type":"array","description":"Present only when reconstructed history is activated: months between the last rebuilt month and the first live month, shown as labelled gaps. They are absent from months, never shown as zero.\n","items":{"type":"object","required":["month","label"],"properties":{"month":{"type":"string","example":"2026-09"},"label":{"type":"string","enum":["between_history_and_live"]}}}},"seam":{"type":"object","description":"Present only when reconstructed history is activated: the seam between rebuilt and live months. A difference within 1% of the last rebuilt close is served as a labelled method-change adjustment (live opening minus rebuilt close, signed minor units); gap means labelled gaps separate the rebuilt and live months, so there is no continuity to check.\n","required":["month","status"],"properties":{"month":{"type":"string","example":"2026-10"},"status":{"type":"string","enum":["continuous","method_change","gap"]},"label":{"type":"string","enum":["method_change"]},"adjustmentMinorUnits":{"type":"string","pattern":"^-?(0|[1-9][0-9]*)$"}}}}},"MrrMovementMonth":{"type":"object","required":["month","currentMrrMinorUnits","newMrrMinorUnits","expansionMrrMinorUnits","reactivationMrrMinorUnits","contractionMrrMinorUnits","churnedMrrMinorUnits","netNewMrrMinorUnits"],"properties":{"month":{"type":"string","example":"2026-06"},"currentMrrMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$","description":"Exact ending MRR in authoritative minor units."},"newMrrMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"},"expansionMrrMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"},"reactivationMrrMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"},"contractionMrrMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$","description":"Non-negative contraction magnitude."},"churnedMrrMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$","description":"Non-negative churn magnitude."},"netNewMrrMinorUnits":{"type":"string","pattern":"^-?(0|[1-9][0-9]*)$","description":"new + expansion + reactivation - contraction - churned."},"activeCustomerCount":{"type":"integer","minimum":0,"description":"Paying customers at the end of the month (as of today on the in-progress row)."},"excludedNonUsd":{"type":"array","description":"Reconstructed months only: non-USD lines excluded from this month's MRR, per currency, with their monthly amount in that currency's minor units.\n","items":{"type":"object","required":["currency","lineCount","monthlyMinorUnits"],"properties":{"currency":{"type":"string","pattern":"^[a-z]{3}$"},"lineCount":{"type":"integer","minimum":0},"monthlyMinorUnits":{"type":"integer","minimum":0}}}},"uncollectibleRenewalMrr":{"type":"object","description":"Reconstructed months only: the MRR, and how many subscriptions carry it, from renewal invoices marked uncollectible. They still count as MRR (past-due renewals keep MRR until the subscription ends); paused collection can hide behind them.\n","required":["subscriptionCount","mrrMinorUnits"],"properties":{"subscriptionCount":{"type":"integer","minimum":0},"mrrMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"}}}}},"MrrMovementCurrentMonth":{"description":"Live Home (founder sync 2026-09-21): the in-progress calendar month's movements so far, published beside `months` (never inside it), headed by the day the figures run to.\n","allOf":[{"$ref":"#/components/schemas/MrrMovementMonth"},{"type":"object","required":["postedThrough","daysInMonth"],"properties":{"postedThrough":{"type":"string","format":"date"},"daysInMonth":{"type":"integer","minimum":28,"maximum":31}}}]},"MrrLiveFields":{"description":"Live Home (founder sync 2026-09-21): the current calendar month's sealed snapshot — MRR as of today, this month's movements so far, and paying customers as of today. Present on MrrMetric.live only when the current-month snapshot is published in the current generation; independent of the completed-month fields, so a tenant certified this month has `live` and no completed month.\n","type":"object","required":["currentMinorUnits","month","postedThrough","daysInMonth","newMinorUnits","expansionMinorUnits","reactivationMinorUnits","contractionMinorUnits","churnedMinorUnits","netNewMinorUnits","activeCustomerCount","activeSubscriptionCount","currency","minorUnitExponent"],"properties":{"currentMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"},"month":{"type":"string","example":"2026-09"},"postedThrough":{"type":"string","format":"date"},"daysInMonth":{"type":"integer","minimum":28,"maximum":31},"newMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"},"expansionMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"},"reactivationMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"},"contractionMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"},"churnedMinorUnits":{"type":"string","pattern":"^(0|[1-9][0-9]*)$"},"netNewMinorUnits":{"type":"string","pattern":"^-?(0|[1-9][0-9]*)$"},"activeCustomerCount":{"type":"integer","minimum":0},"activeSubscriptionCount":{"type":"integer","minimum":0},"currency":{"type":"string"},"minorUnitExponent":{"type":"integer"}}},"RevenueMixMonth":{"type":"object","required":["month","recurringCents","servicesCents","otherCents"],"properties":{"month":{"type":"string","example":"2026-06"},"recurringCents":{"type":"integer","description":"Posted revenue with recurring billing provenance, in cents."},"servicesCents":{"type":"integer","description":"Posted revenue with services billing provenance, in cents."},"otherCents":{"type":"integer","description":"Posted revenue with no recognizable billing provenance, in cents."}}},"RevenueMixData":{"type":"object","required":["available","basis","months"],"properties":{"available":{"type":"boolean","description":"False when the window holds no posted revenue lines (months empty)."},"reason":{"type":"string","enum":["mixed_currencies"],"description":"Present only when available is false because the company-wide read spans entities in different functional currencies (banned before consolidation). Entity-scoped reads are single-currency and never carry this.\n"},"basis":{"type":"string","enum":["billing-source"]},"months":{"type":"array","maxItems":7,"description":"Ascending; the 6 complete months plus the current month-to-date, every month present (zero-filled) when available.\n","items":{"$ref":"#/components/schemas/RevenueMixMonth"}}}},"RevenueMixResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevenueMixData"}}},"BillingTypeRevenueAuthority":{"type":"object","required":["companyId","entityId","basis","asOf","startMonth","endMonth","monthKeys"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"basis":{"type":"string","enum":["recognized_revenue_billing_provenance"]},"asOf":{"type":"string","format":"date-time"},"startMonth":{"type":"string","pattern":"^\\d{4}-\\d{2}$"},"endMonth":{"type":"string","pattern":"^\\d{4}-\\d{2}$"},"monthKeys":{"type":"array","items":{"type":"string","pattern":"^\\d{4}-\\d{2}$"}}}},"BillingTypeRevenueRow":{"type":"object","required":["key","label","money"],"properties":{"key":{"type":"string","description":"recurring | one_time | usage (always all three, in that order, zeros included).\n"},"label":{"type":"string","description":"Exactly Recurring / One-time / Usage.\n"},"money":{"$ref":"#/components/schemas/ExactMoney"}}},"BillingTypeRevenueValue":{"type":"object","required":["percentageStatus","total","denominator","rows"],"properties":{"percentageStatus":{"type":"string","enum":["available"]},"total":{"$ref":"#/components/schemas/ExactMoney"},"denominator":{"$ref":"#/components/schemas/ExactMoney","description":"Recognized posted operating revenue for the window (equals total by construction)."},"rows":{"type":"array","items":{"$ref":"#/components/schemas/BillingTypeRevenueRow"}}}},"BillingTypeRevenueDiagnostic":{"type":"object","required":["percentageStatus"],"properties":{"percentageStatus":{"type":"string","enum":["unavailable_incomplete","unavailable_non_positive"]},"recognizedTotal":{"$ref":"#/components/schemas/ExactMoney"},"classifiedTotal":{"$ref":"#/components/schemas/ExactMoney"},"unclassified":{"$ref":"#/components/schemas/ExactMoney"},"missingMonths":{"type":"array","description":"Window months with no posted-books evidence. A month the books never covered is not an authoritative zero, so the whole window fails closed and names them.\n","items":{"type":"string","pattern":"^\\d{4}-\\d{2}$"}},"outOfRangeRows":{"type":"array","description":"Rows whose recognized minor units fall outside [0, denominator] — a share outside 0-100%. Recognition allocations are SIGNED (a refund reverses a prior-month charge), so a single category can net negative, or another exceed the denominator, while the window aggregate stays positive and fully reconciled. That is not a mix, so the metric fails closed and names the offending rows.\n","items":{"type":"object","required":["key","money"],"properties":{"key":{"type":"string"},"money":{"$ref":"#/components/schemas/ExactMoney"}}}}}},"BillingTypeRevenueMetric":{"type":"object","required":["available","completeness"],"properties":{"available":{"type":"boolean"},"value":{"$ref":"#/components/schemas/BillingTypeRevenueValue","description":"Present only when available is true."},"reason":{"type":"string","enum":["insufficient_history","source_not_authorized","syncing","stale","failed","mixed_currency","entity_scope_unavailable","incomplete_provenance","truncated"],"description":"Present only when available is false; public-safe."},"diagnostic":{"$ref":"#/components/schemas/BillingTypeRevenueDiagnostic"},"authority":{"$ref":"#/components/schemas/BillingTypeRevenueAuthority"},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}},"BillingTypeRevenueMixResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/BillingTypeRevenueMetric"}}},"RevenueProducts":{"type":"object","required":["accounts","stripeMappings","history"],"properties":{"accounts":{"type":"array","items":{"type":"object","required":["glAccountId","code","name","productKey","isActive"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"code":{"type":"string"},"name":{"type":"string"},"productKey":{"type":["string","null"]},"isActive":{"type":"boolean"}}}},"stripeMappings":{"type":"array","items":{"type":"object","required":["companyId","stripeProductId","glAccountId","updatedByUserId","updatedAt"],"properties":{"companyId":{"type":"string","format":"uuid"},"stripeProductId":{"type":"string"},"glAccountId":{"type":"string","format":"uuid"},"updatedByUserId":{"type":["string","null"],"format":"uuid"},"updatedAt":{"type":"string","format":"date-time"}}}},"history":{"type":"array","description":"Newest first, at most 100.","items":{"$ref":"#/components/schemas/RevenueProductMappingEvent"}}}},"RevenueProductMappingEvent":{"type":"object","required":["id","companyId","subject","glAccountId","stripeProductId","oldValue","newValue","reason","actorUserId","actorEmail","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"subject":{"type":"string","enum":["account_product_key","stripe_product"]},"glAccountId":{"type":["string","null"],"format":"uuid","description":"The tagged account (account_product_key)."},"stripeProductId":{"type":["string","null"],"description":"The mapped Stripe product (stripe_product)."},"oldValue":{"type":["string","null"],"description":"account_product_key — the product key; stripe_product — the GL account id."},"newValue":{"type":["string","null"]},"reason":{"type":"string"},"actorUserId":{"type":["string","null"],"format":"uuid"},"actorEmail":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}}},"RevenueProductKeyInput":{"type":"object","additionalProperties":false,"required":["productKey","expected","reason"],"properties":{"productKey":{"type":["string","null"],"pattern":"^[a-z0-9][a-z0-9_-]{0,62}$","description":"null removes the tag."},"expected":{"type":["string","null"],"maxLength":63,"description":"The key the caller last saw (null when untagged)."},"reason":{"type":"string","minLength":3,"maxLength":500}}},"StripeRevenueProductMappingInput":{"type":"object","additionalProperties":false,"required":["glAccountId","expectedGlAccountId","reason"],"properties":{"glAccountId":{"type":["string","null"],"format":"uuid","description":"null removes the mapping."},"expectedGlAccountId":{"type":["string","null"],"format":"uuid","description":"The account the caller last saw (null when unmapped)."},"reason":{"type":"string","minLength":3,"maxLength":500}}},"RevenueByProductRow":{"type":"object","required":["key","label","glAccountId","money"],"properties":{"key":{"type":"string","description":"\"gl:<glAccountId>\". Rows are sorted by minor units descending, then label."},"label":{"type":"string","description":"The product account's name."},"glAccountId":{"type":"string"},"money":{"$ref":"#/components/schemas/ExactMoney"}}},"RevenueByProductValue":{"type":"object","required":["total","rows","unattributedRevenue","refundsAndDiscounts","operatingRevenue","mappingComplete"],"properties":{"total":{"$ref":"#/components/schemas/ExactMoney","description":"Product revenue — the sum of the rows."},"rows":{"type":"array","description":"Product accounts (operating, non-contra revenue accounts, tagged or not) with non-zero posted revenue in the window. A product account's net can be negative.","items":{"$ref":"#/components/schemas/RevenueByProductRow"}},"unattributedRevenue":{"$ref":"#/components/schemas/ExactMoney","description":"Signed revenue on 4999 Uncategorized Income, which the P&L shows in Revenue and which is never a product."},"refundsAndDiscounts":{"$ref":"#/components/schemas/ExactMoney","description":"Signed refunds and discounts (contra revenue); negative when they reduce revenue."},"operatingRevenue":{"$ref":"#/components/schemas/ExactMoney","description":"P&L operating revenue for the same entity and window; equals total + unattributedRevenue + refundsAndDiscounts."},"mappingComplete":{"type":"boolean","description":"Always true since"}}},"RevenueByProductAuthority":{"type":"object","required":["companyId","entityId","basis","asOf","startMonth","endMonth","monthKeys"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"basis":{"type":"string","enum":["posted_revenue_by_gl_account"]},"asOf":{"type":"string","format":"date-time"},"startMonth":{"type":"string","pattern":"^\\d{4}-\\d{2}$"},"endMonth":{"type":"string","pattern":"^\\d{4}-\\d{2}$"},"monthKeys":{"type":"array","items":{"type":"string","pattern":"^\\d{4}-\\d{2}$"}}}},"RevenueByProductMetric":{"type":"object","required":["available","completeness"],"properties":{"available":{"type":"boolean"},"value":{"$ref":"#/components/schemas/RevenueByProductValue","description":"Present only when available is true."},"reason":{"type":"string","enum":["insufficient_history","failed","mixed_currency","entity_scope_unavailable","incomplete_provenance","truncated"],"description":"Present only when available is false; public-safe."},"diagnostic":{"type":"object","required":["missingMonths"],"properties":{"missingMonths":{"type":"array","description":"Window months with no posted-books evidence.","items":{"type":"string","pattern":"^\\d{4}-\\d{2}$"}}}},"authority":{"$ref":"#/components/schemas/RevenueByProductAuthority"},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"},"eligibility":{"$ref":"#/components/schemas/RevenueByProductEligibility"}}},"RevenueByProductEligibility":{"type":"object","description":"Home card visibility (#2414) is decided at company level rather than per selected window (read per entity, like the rows). It stays visible when at least two non-contra operating revenue accounts have posted activity over the last 12 completed months, including generic accounts that still need attribution. revenueAccountCount separately reports how many of those accounts are explicitly tagged as products. Refunds and non-operating income do not count. Lookback months the posted books do not cover carry no lines and are simply not counted; they never make eligibility unavailable. Present on both available and unavailable branches; absent only when the eligibility read itself could not be made.\n","required":["eligible","revenueAccountCount","minimumRevenueAccounts","authority"],"properties":{"eligible":{"type":"boolean","description":"True when at least two non-contra operating revenue accounts have posted activity, so incomplete mapping remains visible."},"revenueAccountCount":{"type":"integer","minimum":0,"description":"Distinct explicitly tagged product accounts with nonzero posted activity in the lookback."},"minimumRevenueAccounts":{"type":"integer","enum":[2]},"authority":{"type":"object","required":["startMonth","endMonth","monthKeys","coveredMonthKeys"],"properties":{"startMonth":{"type":"string","pattern":"^\\d{4}-\\d{2}$"},"endMonth":{"type":"string","pattern":"^\\d{4}-\\d{2}$","description":"The last completed month; the current partial month is never counted."},"monthKeys":{"type":"array","minItems":12,"maxItems":12,"description":"The 12 lookback months, ascending.","items":{"type":"string","pattern":"^\\d{4}-\\d{2}$"}},"coveredMonthKeys":{"type":"array","description":"Lookback months the posted books cover (the months actually counted), ascending.","items":{"type":"string","pattern":"^\\d{4}-\\d{2}$"}}}}}},"RevenueByProductMetricResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevenueByProductMetric"}}},"RevenueByClientRow":{"type":"object","required":["customerId","name","revenueCents"],"properties":{"customerId":{"type":"string","format":"uuid"},"name":{"type":"string"},"revenueCents":{"type":"integer","description":"Posted revenue attributed to this customer over the window, in cents."}}},"RevenueByClientData":{"type":"object","required":["available","basis","clients","otherCents"],"properties":{"available":{"type":"boolean","description":"False when the window holds no posted revenue lines (clients empty, otherCents 0).\n"},"reason":{"type":"string","enum":["mixed_currencies"],"description":"Present only when available is false because the company-wide read spans entities in different functional currencies (banned before consolidation). Entity-scoped reads are single-currency and never carry this.\n"},"basis":{"type":"string","enum":["posted-invoices"]},"clients":{"type":"array","description":"Descending by revenue, then name.","items":{"$ref":"#/components/schemas/RevenueByClientRow"}},"otherCents":{"type":"integer","description":"Posted revenue with no invoice-to-customer provenance, in cents. Never guessed per client.\n"}}},"RevenueByClientResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevenueByClientData"}}},"ActiveClientsMonth":{"type":"object","required":["month","status","activeClients","revenueCents","unattributedRevenueCents"],"properties":{"month":{"type":"string","pattern":"^\\d{4}-\\d{2}$"},"status":{"type":"string","enum":["counted","unattributed_revenue","no_revenue"],"description":"counted: every revenue cent in the month has a client, so `activeClients` is exact. unattributed_revenue: some revenue has no client, so no count is published. no_revenue: no posted operating revenue lines in the month.\n"},"activeClients":{"type":["integer","null"],"minimum":0,"description":"Distinct clients with positive net revenue in the month; null unless status is counted."},"revenueCents":{"type":"integer","description":"Net posted operating revenue in the month, in cents."},"unattributedRevenueCents":{"type":"integer","description":"The part of revenueCents with no client provenance, in cents."}}},"ActiveClientsData":{"type":"object","required":["available","basis","currentMonth","asOf","months"],"properties":{"available":{"type":"boolean"},"reason":{"type":"string","enum":["no_revenue_accounts","mixed_currencies"],"description":"Present only when available is false."},"basis":{"type":"string","enum":["posted-revenue"]},"currentMonth":{"type":"string","pattern":"^\\d{4}-\\d{2}$","description":"The month in progress (UTC), counted month to date."},"asOf":{"type":"string","format":"date","description":"The last day counted (UTC today)."},"months":{"type":"array","description":"Oldest first; the last entry is currentMonth. Twelve entries when available, empty otherwise.","maxItems":12,"items":{"$ref":"#/components/schemas/ActiveClientsMonth"}}}},"ActiveClientsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/ActiveClientsData"}}},"CashHistoryPoint":{"type":"object","required":["date","balanceCents"],"properties":{"date":{"type":"string","format":"date"},"balanceCents":{"type":"integer","description":"Cumulative posted cash balance at the end of this date, in cents."}}},"CashHistoryData":{"type":"object","required":["available","basis","series"],"properties":{"available":{"type":"boolean","description":"False when the company has no cash accounts or no posted cash journal lines at all (series empty).\n"},"basis":{"type":"string","enum":["posted-books"]},"series":{"type":"array","description":"Ascending by date; one point per day with activity plus window-boundary points (a flat window is just the boundary points).\n","items":{"$ref":"#/components/schemas/CashHistoryPoint"}}}},"CashHistoryResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CashHistoryData"}}},"MonthlyCashHistoryMetricAuthority":{"type":"object","required":["companyId","entityId","basis","asOf"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"basis":{"type":"string","enum":["posted_books_cash"]},"asOf":{"type":"string","description":"Live ISO instant for `currentCash`; the window's last completed month (YYYY-MM) for `history` — deliberately different clocks.\n"},"startMonth":{"type":"string","example":"2026-05"},"endMonth":{"type":"string","example":"2026-07"},"monthKeys":{"type":"array","items":{"type":"string","example":"2026-05"}}}},"MonthlyCashHistoryData":{"type":"object","required":["granularity","currentCash","history"],"properties":{"granularity":{"type":"string","enum":["month"]},"currentCash":{"type":"object","description":"MetricResult of ExactMoney. available:false carries `reason` (insufficient_history | entity_scope_unavailable | incomplete_provenance | mixed_currency | truncated | failed) and never a value.\n","required":["available","completeness"],"properties":{"available":{"type":"boolean"},"reason":{"type":"string"},"value":{"$ref":"#/components/schemas/ExactMoney"},"authority":{"$ref":"#/components/schemas/MonthlyCashHistoryMetricAuthority"},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}},"history":{"type":"object","description":"MetricResult of a completed-month MoneySeries. Numeric slots are {month, state: observed|authoritative_zero, money: ExactMoney}; pre-history padding is omitted (authority.monthKeys names the full requested window); a wholly unavailable series returns nonnumeric slots in `diagnostic`.\n","required":["available","completeness"],"properties":{"available":{"type":"boolean"},"reason":{"type":"string"},"value":{"type":"object","required":["slots"],"properties":{"slots":{"type":"array","items":{"type":"object","required":["month","state","money"],"properties":{"month":{"type":"string","example":"2026-05"},"state":{"type":"string","enum":["observed","authoritative_zero"]},"money":{"$ref":"#/components/schemas/ExactMoney"}}}}}},"diagnostic":{"type":"object","properties":{"slots":{"type":"array","items":{"type":"object","required":["month","state"],"properties":{"month":{"type":"string","example":"2026-05"},"state":{"type":"string","enum":["unavailable","padding"]}}}}}},"authority":{"$ref":"#/components/schemas/MonthlyCashHistoryMetricAuthority"},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}}}},"MonthlyCashHistoryResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/MonthlyCashHistoryData"}}},"BurnRunwayData":{"type":"object","required":["headline","series","runway"],"properties":{"headline":{"type":"object","description":"MetricResult of ExactMoney: the trailing-three-completed-month signed net burn average (single BigInt half-away-from-zero divide). available:false carries `reason` and, for insufficient_history, `diagnostic.missingMonths` — never a value.\n","required":["available","completeness"],"properties":{"available":{"type":"boolean"},"reason":{"type":"string"},"value":{"$ref":"#/components/schemas/ExactMoney"},"diagnostic":{"type":"object","properties":{"missingMonths":{"type":"array","items":{"type":"string","example":"2026-05"}}}},"authority":{"type":"object","required":["companyId","entityId","basis","asOf","operatingCostsNumeratorMinor","uncategorizedCostsNumeratorMinor"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"basis":{"type":"string","enum":["posted_operating_net_burn"]},"asOf":{"type":"string"},"startMonth":{"type":"string","example":"2026-05"},"endMonth":{"type":"string","example":"2026-07"},"monthKeys":{"type":"array","items":{"type":"string","example":"2026-05"}},"numeratorMinor":{"type":"string","pattern":"^-?\\d+$","description":"Exact signed three-month numerator, before the single divide."},"operatingCostsNumeratorMinor":{"type":"string","pattern":"^-?\\d+$","description":"Exact three-month posted operating cost total (minor units, headline currency and scale) behind the runway gate's uncategorized share."},"uncategorizedCostsNumeratorMinor":{"type":"string","pattern":"^-?\\d+$","description":"Exact three-month posted operating cost (minor units) sitting on uncategorized accounts. The runway composite refuses with `incomplete_provenance` when this exceeds one third of `operatingCostsNumeratorMinor`."},"denominatorMonths":{"type":"integer","enum":[3]}}},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}},"series":{"type":"object","description":"MetricResult of a completed-month MoneySeries: each numeric slot is the trailing-three-month average ending at that month ({month, state: observed|authoritative_zero, money: ExactMoney}); windows touching pre-history are omitted while authority.monthKeys names the full twelve-month window.\n","required":["available","completeness"],"properties":{"available":{"type":"boolean"},"reason":{"type":"string"},"value":{"type":"object","required":["slots"],"properties":{"slots":{"type":"array","items":{"type":"object","required":["month","state","money"],"properties":{"month":{"type":"string","example":"2026-05"},"state":{"type":"string","enum":["observed","authoritative_zero"]},"money":{"$ref":"#/components/schemas/ExactMoney"}}}}}},"diagnostic":{"type":"object","properties":{"slots":{"type":"array","items":{"type":"object","required":["month","state"],"properties":{"month":{"type":"string","example":"2026-05"},"state":{"type":"string","enum":["unavailable","padding"]}}}}}},"authority":{"type":"object","properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"basis":{"type":"string","enum":["posted_operating_net_burn"]},"asOf":{"type":"string"},"startMonth":{"type":"string"},"endMonth":{"type":"string"},"monthKeys":{"type":"array","items":{"type":"string"}}}},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}},"runway":{"type":"object","description":"MetricResult whose value is a discriminated state — {state: finite, monthsFloor} | {state: depleted, monthsFloor: 0} | {state: non_burning} — with composite authority carrying BOTH input authorities (cash, burn). Never a negative month count.\n","required":["available","completeness"],"properties":{"available":{"type":"boolean"},"reason":{"type":"string","description":"Why runway is withheld. Resolved in this precedence order. (1) `failed`: minted by the composite whenever EITHER input (the cash reading or the net-burn headline) is unavailable with reason `failed`; it outranks every other reason so a read fault is never masked as honest absence. (2) Otherwise, when the net-burn headline is unavailable its own `reason` passes through unchanged (e.g. `insufficient_history` for fewer than three completed months). (3) Otherwise, when the cash reading is unavailable its own `reason` passes through unchanged. (4) With both inputs available the composite mints, checked in this order: `entity_scope_unavailable` (an input authority is not the requested company and entity), `mixed_currency` (cash and burn disagree on currency or minor-unit exponent), then `incomplete_provenance` (more than one third of the three-month posted operating cost is uncategorized; the only reason that carries `diagnostic`). The composite itself never mints `insufficient_history`, `source_not_authorized`, `syncing`, `stale`, `insufficient_inputs` or `truncated`; those only ever pass through from an input.\n","enum":["insufficient_history","source_not_authorized","syncing","stale","failed","mixed_currency","entity_scope_unavailable","incomplete_provenance","insufficient_inputs","truncated"]},"value":{"type":"object","required":["state"],"properties":{"state":{"type":"string","enum":["finite","depleted","non_burning"]},"monthsFloor":{"type":"integer","minimum":0}}},"diagnostic":{"type":"object","description":"Present only on the composite's own `incomplete_provenance` refusal: the exact three-month window totals behind the one-third rule, so support can see how far over the line a customer sits without re-deriving it. Minor units in the net-burn headline's currency and scale; never a runway value.\n","required":["uncategorizedCostsMinor","operatingCostsMinor"],"properties":{"uncategorizedCostsMinor":{"type":"string","pattern":"^-?\\d+$"},"operatingCostsMinor":{"type":"string","pattern":"^-?\\d+$"}}},"authority":{"type":"object","properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"basis":{"type":"string","enum":["runway_composite"]},"asOf":{"type":"string"},"inputs":{"type":"object","properties":{"cash":{"type":"object"},"burn":{"type":"object"}}}}},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}}}},"BurnRunwayResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/BurnRunwayData"}}},"DailyTrendReason":{"type":"string","description":"Why a daily line is withheld. `failed` and `truncated` are the failure class; `not_configured` means the chart has no AR control account; `insufficient_history` means there is nothing to draw yet.\n","enum":["insufficient_history","not_configured","failed","truncated","mixed_currency","entity_scope_unavailable","incomplete_provenance"]},"DailyTrendAuthority":{"type":"object","required":["companyId","entityId","basis"],"properties":{"companyId":{"type":"string"},"entityId":{"type":"string"},"basis":{"type":"string","enum":["posted_books_trailing_90d_runway","posted_books_ar_control"]},"asOf":{"type":"string","format":"date"},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"}}},"DailyRunwayTrendMetric":{"type":"object","description":"Runway line, one point per day with posted P&L evidence in its 90-day window: `cash` is the day's closing posted-books cash, `netBurn` the trailing-90-day posted operating net burn ÷ 3 (the Live Monthly burn figure), and the state is finite (monthsFloor = floor(cash ÷ netBurn)), depleted (cash at or below zero, monthsFloor 0) or non_burning (netBurn at or below zero, no monthsFloor). Never a negative month count.\n","required":["available","completeness"],"properties":{"available":{"type":"boolean"},"reason":{"$ref":"#/components/schemas/DailyTrendReason"},"value":{"type":"object","required":["points"],"properties":{"points":{"type":"array","items":{"type":"object","required":["date","state","cash","netBurn"],"properties":{"date":{"type":"string","format":"date"},"state":{"type":"string","enum":["finite","depleted","non_burning"]},"monthsFloor":{"type":"integer","minimum":0},"cash":{"$ref":"#/components/schemas/ExactMoney"},"netBurn":{"$ref":"#/components/schemas/ExactMoney"}}}}}},"authority":{"$ref":"#/components/schemas/DailyTrendAuthority"},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}},"DailyReceivablesTrendMetric":{"type":"object","description":"Receivables line: the posted balance of the AR control accounts (AR_CONTROL role, the set the AR aging reconciles against) at the close of each day, from the first posted day of the books.\n","required":["available","completeness"],"properties":{"available":{"type":"boolean"},"reason":{"$ref":"#/components/schemas/DailyTrendReason"},"value":{"type":"object","required":["points"],"properties":{"points":{"type":"array","items":{"type":"object","required":["date","money"],"properties":{"date":{"type":"string","format":"date"},"money":{"$ref":"#/components/schemas/ExactMoney"}}}}}},"authority":{"$ref":"#/components/schemas/DailyTrendAuthority"},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}},"DailyTrendsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["runway","receivables"],"properties":{"runway":{"$ref":"#/components/schemas/DailyRunwayTrendMetric"},"receivables":{"$ref":"#/components/schemas/DailyReceivablesTrendMetric"}}}}},"ExpenseBreakdownMetric":{"type":"object","required":["available","authority","completeness"],"description":"Availability envelope. available:true carries value; available:false carries reason (insufficient_history, mixed_currency, incomplete_provenance, entity_scope_unavailable, truncated, failed) and never a numeric value. available:true additionally asserts that the posted-books month census covers EVERY window month: a window whose books start mid-range (or carry a mid-history gap) is insufficient_history with a missingMonths diagnostic, never a partial total captioned across months it does not cover.\n","properties":{"available":{"type":"boolean"},"reason":{"type":"string"},"diagnostic":{"type":"object","description":"Present on the insufficient_history census failure.\n","properties":{"missingMonths":{"type":"array","description":"Window months with no posted-books evidence.","items":{"type":"string"}}}},"authority":{"type":"object","required":["companyId","entityId","basis","asOf"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"basis":{"type":"string","enum":["posted_pnl_expense_breakdown"]},"asOf":{"type":"string"},"startMonth":{"type":"string"},"endMonth":{"type":"string"},"monthKeys":{"type":"array","items":{"type":"string"}},"postedThrough":{"type":"string","format":"date","description":"Live reads only (live=true). endMonth is the month in progress and its figures run to this date."}}},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"},"value":{"type":"object","required":["percentageStatus","total","rows"],"properties":{"percentageStatus":{"type":"string","enum":["available","unavailable_non_positive","unavailable_offsetting_rows"],"description":"unavailable_non_positive when the signed total is zero or negative, and unavailable_offsetting_rows when the total is positive but smaller in magnitude than at least one bucket (large offsetting buckets leaving a residue). In both cases rows and total are still returned exactly and percentages are not: a share of a non-positive base, or of a rounding residue, is not meaningful.\n"},"total":{"$ref":"#/components/schemas/ExactMoney"},"rows":{"type":"array","items":{"type":"object","required":["key","label","money"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"money":{"$ref":"#/components/schemas/ExactMoney"},"percentBasisPoints":{"type":"integer","minimum":-10000,"maximum":10000,"description":"Present only when percentageStatus is available, which also bounds it to [-10000, 10000]: no bucket's magnitude exceeds the total, so the value is always exactly representable. Negative for a bucket whose signed net is negative (refunds exceeding spend).\n"}}}}}}}},"ExpenseBreakdownResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/ExpenseBreakdownMetric"}}},"NetBurnCardResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["months","startMonth","endMonth","slots","average"],"properties":{"months":{"type":"integer","enum":[6]},"startMonth":{"type":"string"},"endMonth":{"type":"string"},"slots":{"type":"array","minItems":6,"maxItems":7,"description":"Six completed months, oldest first; a live=true read appends the month in progress as a seventh slot.","items":{"type":"object","required":["month","state"],"properties":{"month":{"type":"string"},"state":{"type":"string","enum":["observed","authoritative_zero","unavailable","padding"]},"money":{"$ref":"#/components/schemas/ExactMoney"}}}},"inProgress":{"type":"object","description":"Live reads only (live=true). The appended month and the day its figures run to. The average never includes it.","required":["month","postedThrough"],"properties":{"month":{"type":"string"},"postedThrough":{"type":"string","format":"date"}}},"average":{"type":"object","required":["available","completeness"],"properties":{"available":{"type":"boolean"},"reason":{"type":"string"},"value":{"$ref":"#/components/schemas/ExactMoney"},"diagnostic":{"type":"object","properties":{"missingMonths":{"type":"array","items":{"type":"string"}}}},"authority":{"type":"object","properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"basis":{"type":"string","enum":["posted_operating_net_burn"]},"asOf":{"type":"string"},"startMonth":{"type":"string"},"endMonth":{"type":"string"},"monthKeys":{"type":"array","items":{"type":"string"}}}},"completeness":{"$ref":"#/components/schemas/MetricCompleteness"}}}}}}},"CashByEntityRow":{"type":"object","required":["entityId","name","balanceCents","currency"],"properties":{"entityId":{"type":"string","format":"uuid"},"name":{"type":"string"},"balanceCents":{"type":"integer","description":"Cumulative posted cash balance for the entity, in cents, expressed in the entity's functional currency (never the company presentation currency).\n"},"currency":{"type":"string","pattern":"^[A-Z]{3}$","description":"The entity's functional currency (ISO 4217). The card formats each row with its own currency so foreign-functional entities are not mislabeled with the presentation symbol.\n"}}},"CashByEntityData":{"type":"object","required":["available","entities","asOf"],"properties":{"available":{"type":"boolean"},"reason":{"type":"string","enum":["single_entity","no_accessible_entities","no_cash_accounts"],"description":"Present only when available is false. single_entity: the company has at most one non-group legal entity (the card is only meaningful across entities). no_accessible_entities: the actor's entity grants cover none of the entities. no_cash_accounts: the company has no cash GL accounts.\n"},"entities":{"type":"array","description":"One row per authorized non-group legal entity; empty when available is false.\n","items":{"$ref":"#/components/schemas/CashByEntityRow"}},"asOf":{"type":"string","format":"date","description":"YYYY-MM-DD the balances are posted through (today)."}}},"CashByEntityResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CashByEntityData"}}},"HomeInsightItem":{"type":"object","required":["id","category","headline","detail","generatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"category":{"type":"string"},"headline":{"type":"string"},"detail":{"type":"string"},"generatedAt":{"type":"string","format":"date-time","description":"ISO timestamp the recommendation was generated."}}},"HomeInsightsData":{"type":"object","required":["available","items"],"properties":{"available":{"type":"boolean"},"reason":{"type":"string","enum":["last_n_months_closed","entity_scope_unavailable","not_ready"],"description":"Present only when available is false. last_n_months_closed: the insights-readiness gate's unmet requirement (recent months not closed). entity_scope_unavailable: an entityId was given but the company-wide recommendations cannot be honestly attributed to it (it is not the company's only non-group legal entity). not_ready: defensive fallback when readiness reports not-ready without naming a requirement.\n"},"items":{"type":"array","maxItems":5,"description":"Empty when available is false; newest first.","items":{"$ref":"#/components/schemas/HomeInsightItem"}}}},"HomeInsightsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/HomeInsightsData"}}},"CreateUserInput":{"type":"object","required":["email","name"],"properties":{"email":{"type":"string","format":"email","example":"alice@example.com"},"name":{"type":"string","minLength":1,"maxLength":200,"example":"Alice Smith"}}},"User":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"name":{"type":"string"},"phone":{"type":["string","null"]},"jobTitle":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"UserResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/User"}}},"UsersListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/User"}}}},"RegisterInput":{"type":"object","required":["email","password","name"],"properties":{"email":{"type":"string","format":"email","example":"alice@example.com"},"password":{"type":"string","minLength":8,"maxLength":72,"example":"supersecret123"},"name":{"type":"string","minLength":1,"maxLength":200,"example":"Alice Smith"}}},"LoginInput":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email","example":"alice@example.com"},"password":{"type":"string","minLength":1,"example":"supersecret123"}}},"PasswordResetRequestInput":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"recaptchaToken":{"type":"string"}}},"PasswordResetRequestResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"message":{"type":"string","example":"If an account exists for that email, a password reset link will be sent."}}}}},"PasswordResetInput":{"type":"object","required":["token","password"],"properties":{"token":{"type":"string","minLength":32,"maxLength":256},"password":{"type":"string","minLength":8,"maxLength":72},"recaptchaToken":{"type":"string"}}},"InviteTokenInput":{"type":"object","required":["token"],"properties":{"token":{"type":"string","minLength":32,"maxLength":256}}},"InviteSignupInput":{"allOf":[{"$ref":"#/components/schemas/InviteTokenInput"},{"type":"object","required":["name","password"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"password":{"type":"string","minLength":8,"maxLength":72},"recaptchaToken":{"type":"string"}}}]},"InvitePreview":{"type":"object","properties":{"email":{"type":"string","format":"email"},"companyId":{"type":"string","format":"uuid"},"companyName":{"type":["string","null"]},"role":{"type":"string","enum":["Admin","CFO","Member"]},"expiresAt":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["valid","expired","revoked","accepted"]},"existingAccount":{"type":"boolean","description":"True only when this valid high-entropy invite is bound to an existing Median account."}}},"InvitePreviewResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/InvitePreview"}}},"UserContextMembership":{"type":"object","properties":{"companyId":{"type":"string","format":"uuid"},"companyName":{"type":["string","null"]},"role":{"type":"string","enum":["owner","admin","cfo","member","viewer"]}}},"UserContext":{"type":"object","required":["companyId","role","onboardingComplete","onboardingStep","subscriptionStatus","platformItemState","canSeeInternalUi","featureFlags","memberships","onboardingV3Stage"],"properties":{"companyId":{"type":["string","null"],"format":"uuid"},"role":{"type":["string","null"],"enum":["owner","admin","cfo","member","viewer",null]},"onboardingComplete":{"type":"boolean"},"onboardingStep":{"type":"integer"},"subscriptionStatus":{"type":["string","null"],"description":"Missing or ambiguous platform items project needs_attention; cancellation takes precedence. Legacy billing-plan fallback is used only without a subscription row."},"platformItemState":{"type":["string","null"],"enum":["unverified","present","missing","ambiguous",null],"description":"Null when no Median subscription row exists."},"featureFlags":{"type":"object","additionalProperties":{"type":"boolean"}},"canSeeInternalUi":{"type":"boolean"},"onboardingV3Stage":{"description":"Stage of the caller's onboarding v3 flow, or null when they have none. A paying v3 customer holds a membership and an active subscription while setup tasks are still outstanding, so the client routes on this rather than on membership.","type":["string","null"],"enum":["auth","price","sales","subscribe","setup","books",null]},"memberships":{"type":"array","items":{"$ref":"#/components/schemas/UserContextMembership"}}}},"UserContextResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/UserContext"}}},"InviteAcceptResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"allOf":[{"$ref":"#/components/schemas/UserContext"},{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"}}}]}}},"RefreshInput":{"type":"object","properties":{"refreshToken":{"type":"string","description":"Optional when the refresh token is available in the HttpOnly cookie.","example":"a1b2c3d4..."},"companyId":{"type":"string","format":"uuid","description":"Preferred active company context for users with multiple memberships."}}},"LogoutInput":{"type":"object","required":["refreshToken"],"properties":{"refreshToken":{"type":"string","example":"a1b2c3d4..."}}},"TokenPair":{"type":"object","properties":{"accessToken":{"type":"string","description":"Short-lived JWT access token"},"refreshToken":{"type":"string","description":"Opaque refresh token (rotate on each use)"},"expiresIn":{"type":"integer","description":"Access token TTL in seconds","example":900}}},"AuthResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"},"accessToken":{"type":"string"},"refreshToken":{"type":"string"},"expiresIn":{"type":"integer","description":"Access token TTL in seconds"},"companyId":{"type":["string","null"],"description":"Primary company for customer-app session routing"},"canSeeInternalUi":{"type":"boolean","description":"True when the primary company is allowlisted for customer-app preview UI"},"memberships":{"type":"array","items":{"$ref":"#/components/schemas/UserContextMembership"}}}}}},"PasswordlessOtpStartInput":{"type":"object","additionalProperties":false,"required":["email","purpose","recaptchaToken"],"properties":{"email":{"type":"string","format":"email"},"purpose":{"type":"string","enum":["signup","signin"]},"fullName":{"type":"string","minLength":1,"maxLength":200},"recaptchaToken":{"type":"string"}},"allOf":[{"if":{"properties":{"purpose":{"const":"signup"}}},"then":{"properties":{"fullName":{"type":"string","minLength":1,"maxLength":200}},"required":["fullName"]}}]},"PasswordlessOtpVerifyInput":{"type":"object","additionalProperties":false,"required":["email","purpose","code","recaptchaToken"],"properties":{"email":{"type":"string","format":"email"},"purpose":{"type":"string","enum":["signup","signin"]},"code":{"type":"string","pattern":"^[0-9]{6}$"},"recaptchaToken":{"type":"string"}}},"PasswordlessOtpStartResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":false,"required":["accepted","resendAfterSeconds"],"properties":{"accepted":{"type":"boolean","const":true},"resendAfterSeconds":{"type":"integer","const":30},"existingAccount":{"type":"boolean","const":true,"description":"Present only for purpose=signup when the account already exists; no OTP is stored or delivered in this branch.\n"}}}}},"EmptyPasskeyOptionsInput":{"type":"object","additionalProperties":false,"maxProperties":0},"PasskeyAssertionOptionsInput":{"type":"object","additionalProperties":false,"required":["recaptchaToken"],"properties":{"recaptchaToken":{"type":"string"}}},"WebAuthnRegistrationCredential":{"type":"object","additionalProperties":false,"required":["id","rawId","type","response"],"properties":{"id":{"type":"string","minLength":1,"maxLength":2048},"rawId":{"type":"string","minLength":1,"maxLength":2048},"type":{"type":"string","const":"public-key"},"authenticatorAttachment":{"type":["string","null"],"enum":["platform","cross-platform",null]},"clientExtensionResults":{"type":"object","additionalProperties":true},"response":{"type":"object","additionalProperties":false,"required":["clientDataJSON","attestationObject"],"properties":{"clientDataJSON":{"type":"string","minLength":1,"maxLength":16384},"attestationObject":{"type":"string","minLength":1,"maxLength":65536},"transports":{"type":"array","maxItems":16,"items":{"type":"string","minLength":1,"maxLength":64}},"publicKeyAlgorithm":{"type":"integer"},"publicKey":{"type":["string","null"],"maxLength":16384},"authenticatorData":{"type":"string","maxLength":16384}}}}},"WebAuthnAssertionCredential":{"type":"object","additionalProperties":false,"required":["id","rawId","type","response"],"properties":{"id":{"type":"string","minLength":1,"maxLength":2048},"rawId":{"type":"string","minLength":1,"maxLength":2048},"type":{"type":"string","const":"public-key"},"authenticatorAttachment":{"type":["string","null"],"enum":["platform","cross-platform",null]},"clientExtensionResults":{"type":"object","additionalProperties":true},"response":{"type":"object","additionalProperties":false,"required":["clientDataJSON","authenticatorData","signature"],"properties":{"clientDataJSON":{"type":"string","minLength":1,"maxLength":16384},"authenticatorData":{"type":"string","minLength":1,"maxLength":16384},"signature":{"type":"string","minLength":1,"maxLength":8192},"userHandle":{"type":["string","null"],"maxLength":1024}}}}},"PasskeyRegistrationVerifyInput":{"type":"object","additionalProperties":false,"required":["response"],"properties":{"response":{"$ref":"#/components/schemas/WebAuthnRegistrationCredential"}}},"PasskeyAssertionVerifyInput":{"type":"object","additionalProperties":false,"required":["response","recaptchaToken"],"properties":{"response":{"$ref":"#/components/schemas/WebAuthnAssertionCredential"},"recaptchaToken":{"type":"string"}}},"PasskeyOptionsResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":false,"required":["options"],"properties":{"options":{"type":"object","additionalProperties":true}}}}},"PasskeyRegistrationOptionsResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"oneOf":[{"type":"object","additionalProperties":false,"required":["options"],"properties":{"options":{"type":"object","additionalProperties":true}}},{"type":"object","additionalProperties":false,"required":["alreadyComplete","verified","credentialId"],"properties":{"alreadyComplete":{"type":"boolean","const":true},"verified":{"type":"boolean","const":true},"credentialId":{"type":"string","minLength":1}}}]}}},"PasskeyRegistrationResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":false,"required":["verified","credentialId"],"properties":{"verified":{"type":"boolean","const":true},"credentialId":{"type":"string","minLength":1}}}}},"PasswordlessSessionResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["user","accessToken","refreshToken","expiresIn","isNewUser","companyId","canSeeInternalUi","featureFlags","memberships"],"properties":{"user":{"$ref":"#/components/schemas/User"},"accessToken":{"type":"string"},"refreshToken":{"type":"string"},"expiresIn":{"type":"integer","minimum":1},"isNewUser":{"type":"boolean"},"companyId":{"type":["string","null"],"format":"uuid"},"canSeeInternalUi":{"type":"boolean"},"featureFlags":{"type":"object","additionalProperties":{"type":"boolean"}},"memberships":{"type":"array","items":{"$ref":"#/components/schemas/UserContextMembership"}}}}}},"TokenPairResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"allOf":[{"$ref":"#/components/schemas/TokenPair"},{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"},"companyId":{"type":["string","null"]},"canSeeInternalUi":{"type":"boolean","description":"True when the primary company is allowlisted for customer-app preview UI"},"memberships":{"type":"array","items":{"$ref":"#/components/schemas/UserContextMembership"}}}}]}}},"CoaAccountExplanationPart":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"}}},"CoaAccountExplanation":{"type":"object","description":"Read-only COA account context returned only when the customer company is allowlisted by CUSTOMER_APP_INTELLIGENCE_HOME_COMPANY_IDS.\n","properties":{"accountType":{"$ref":"#/components/schemas/CoaAccountExplanationPart"},"detailType":{"$ref":"#/components/schemas/CoaAccountExplanationPart"},"reportSection":{"$ref":"#/components/schemas/CoaAccountExplanationPart"},"classification":{"oneOf":[{"$ref":"#/components/schemas/CoaAccountExplanationPart"},{"type":"null"}]}}},"GlAccount":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"code":{"type":"string","example":"1000"},"name":{"type":"string","example":"Cash"},"type":{"type":"string","enum":["Asset","Liability","Equity","Revenue","Expense"]},"subtype":{"type":["string","null"]},"parentAccountId":{"type":["string","null"],"format":"uuid"},"normalBalance":{"type":"string","enum":["debit","credit"]},"detailTypeKey":{"type":"string","description":"Canonical COA detail type used for report grouping."},"detailTypeLabel":{"type":"string"},"detailTypeDescription":{"type":"string"},"reportSectionKey":{"type":"string"},"reportSectionLabel":{"type":"string"},"accountExplanation":{"$ref":"#/components/schemas/CoaAccountExplanation"},"cashFlowSection":{"type":["string","null"],"enum":["operating","investing","financing","cash","non_cash",null]},"taxFormSectionKey":{"type":["string","null"]},"description":{"type":["string","null"]},"source":{"type":"string","enum":["system","template","integration","migration","manual","repair"]},"isSystem":{"type":"boolean"},"isLocked":{"type":"boolean","description":"Locked accounts cannot be selected for new direct posting."},"isPostable":{"type":"boolean","description":"False for parent, locked, inactive, or otherwise non-postable accounts."},"isParent":{"type":"boolean","description":"True when at least one active child account references this account."},"isActive":{"type":"boolean"},"isMonetary":{"type":["boolean","null"],"description":"Null is fail-closed and blocks foreign-balance revaluation."},"monetaryClassificationSource":{"type":["string","null"],"enum":["account_type_subtype","manual",null]},"monetaryClassifiedAt":{"type":["string","null"],"format":"date-time"},"monetaryClassifiedByUserId":{"type":["string","null"],"format":"uuid"},"deactivatedAt":{"type":["string","null"],"format":"date-time"},"deactivatedByUserId":{"type":["string","null"],"format":"uuid"},"deactivationReason":{"type":["string","null"]},"expectedNormalBalance":{"type":"string","enum":["debit","credit"]},"healthFindings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"severity":{"type":"string","enum":["critical","high","medium","low"]},"message":{"type":"string"}}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateGlAccountInput":{"type":"object","required":["code","name","type"],"properties":{"code":{"type":"string","minLength":1,"maxLength":20},"name":{"type":"string","minLength":1,"maxLength":255},"type":{"type":"string","enum":["Asset","Liability","Equity","Revenue","Expense"]},"subtype":{"type":"string","maxLength":100},"parentAccountId":{"type":"string","format":"uuid"},"normalBalance":{"type":"string","enum":["debit","credit"]},"detailTypeKey":{"type":["string","null"],"minLength":1,"maxLength":100},"reportSectionKey":{"type":["string","null"],"minLength":1,"maxLength":100},"description":{"type":["string","null"],"maxLength":1000}}},"UpdateGlAccountInput":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"subtype":{"type":["string","null"],"maxLength":100},"parentAccountId":{"type":["string","null"],"format":"uuid"},"isActive":{"type":"boolean"},"detailTypeKey":{"type":["string","null"],"minLength":1,"maxLength":100},"reportSectionKey":{"type":["string","null"],"minLength":1,"maxLength":100},"description":{"type":["string","null"],"maxLength":1000},"isLocked":{"type":"boolean"},"isPostable":{"type":"boolean"}}},"EditGlAccountIdentityInput":{"type":"object","description":"Change only an account's code and/or name (#2883). At least one of `code` and `name` is required. Unknown keys are refused.","additionalProperties":false,"required":["reason","expected"],"properties":{"code":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9.-]{0,6}$","description":"The new code. 1-7 letters, digits, dots or dashes, so it survives as a QuickBooks account number."},"name":{"type":"string","minLength":1,"maxLength":100,"description":"The new name. Single line, no HTML, no colon or double quote, not an account code (3-6 digits), no repeated spaces."},"reason":{"type":"string","minLength":3,"maxLength":1000,"description":"Why the account is being recoded or renamed; stored on the audit record."},"expected":{"type":"object","description":"The code and name the caller last read on the account. Anything else on the row is a 409 GL_ACCOUNT_IDENTITY_STALE.","additionalProperties":false,"required":["code","name"],"properties":{"code":{"type":"string","minLength":1,"maxLength":20},"name":{"type":"string","minLength":1,"maxLength":255}}}}},"GlAccountIdentityConflict":{"type":"object","description":"One entry of `error.extensions.conflicts` on a 409 GL_ACCOUNT_IDENTITY_CONFLICT (#2883). `kind: account` is another account that holds the target code or name, with what is known about it; `kind: merchant_rule` counts this company's merchant rules that target `code` (the code being left or the code being taken); `kind: quickbooks_writeback_item` counts live QuickBooks create-account write-back items for the account being edited.","required":["kind"],"properties":{"kind":{"type":"string","enum":["account","merchant_rule","quickbooks_writeback_item"]},"field":{"type":"string","enum":["code","name"],"description":"Which requested value conflicts. Absent for `quickbooks_writeback_item`."},"holderState":{"type":"string","enum":["active","inactive","retired"],"description":"`account` only. A retired (soft-deleted) holder still owns its code and is not shown by any chart read."},"accountId":{"type":"string","format":"uuid","description":"`account` only: the holder's id."},"code":{"type":"string","description":"The holder's code, or the code the merchant rules target."},"name":{"type":"string","description":"`account` only: the holder's name."},"isSystem":{"type":"boolean"},"isLocked":{"type":"boolean"},"source":{"type":["string","null"],"enum":["system","template","integration","migration","manual","repair",null]},"hasPostedLines":{"type":["boolean","null"],"description":"`account` only: whether the holder has posted journal lines. Null when unknown."},"postedBalanceCents":{"type":["integer","null"],"description":"`account` only: the holder's posted balance in its normal-balance direction, integer cents. Null when unknown."},"dependencies":{"type":"array","description":"`account` only: what still references the holder (bank and integration mappings, schedules, pending work).","items":{"type":"object","required":["kind","count","label"],"properties":{"kind":{"type":"string"},"count":{"type":"integer"},"label":{"type":"string"}}}},"count":{"type":"integer","description":"`merchant_rule` and `quickbooks_writeback_item` only."}}},"GlAccountResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/GlAccount"}}},"GlAccountsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/GlAccount"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"BankAccount":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"integrationId":{"type":["string","null"],"format":"uuid"},"provider":{"type":["string","null"]},"institutionName":{"type":"string"},"accountName":{"type":["string","null"]},"accountType":{"type":["string","null"],"enum":["checking","savings","credit","investment","processor"]},"mask":{"type":["string","null"]},"currency":{"type":"string","example":"USD"},"balanceCents":{"type":["integer","null"]},"status":{"type":"string","enum":["active","disconnected","error"]},"externalId":{"type":["string","null"]},"connectedAt":{"type":"string","format":"date-time"},"lastSyncedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateBankAccountInput":{"type":"object","required":["entityId","institutionName","currency"],"properties":{"entityId":{"type":"string","format":"uuid"},"institutionName":{"type":"string","minLength":1,"maxLength":255},"accountName":{"type":"string","maxLength":255},"accountType":{"type":"string","enum":["checking","savings","credit","investment","processor"]},"mask":{"type":"string","maxLength":10},"currency":{"type":"string","minLength":3,"maxLength":3,"pattern":"^[A-Z]{3}$"},"balanceCents":{"type":"integer"},"externalId":{"type":"string"}}},"CreateManualBankAccountInput":{"type":"object","additionalProperties":false,"required":["glAccountId","institutionName","type"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"institutionName":{"type":"string","minLength":1,"maxLength":255},"mask":{"type":"string","pattern":"^\\d{4}$","description":"Last 4 digits of the account number"},"type":{"type":"string","enum":["checking","savings","credit","investment","processor"]},"currency":{"type":"string","pattern":"^[A-Z]{3}$","description":"Defaults to the owning legal entity's functional currency"},"entityId":{"type":"string","format":"uuid","description":"Required only when the company has more than one legal entity"}}},"UpdateBankAccountInput":{"type":"object","properties":{"accountName":{"type":"string","maxLength":255},"accountType":{"type":"string","enum":["checking","savings","credit","investment","processor"]},"status":{"type":"string","enum":["active","disconnected","error"]},"balanceCents":{"type":"integer"}}},"BankAccountResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/BankAccount"}}},"BankAccountsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/BankAccount"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"Transaction":{"type":"object","properties":{"journalEntryUnavailableReason":{"type":"string","enum":["scope_mismatch","ambiguous_posting"],"description":"Detail responses only. Present when `journalEntry` is null although an entry is linked."},"matchedDocumentUnavailableReason":{"type":"string","enum":["scope_mismatch"],"description":"Detail responses only. Present when `matchedDocument` is null although a document is matched."},"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"occurredOn":{"type":"string","format":"date"},"description":{"type":"string"},"merchant":{"type":["string","null"]},"amountCents":{"type":"integer"},"currency":{"type":"string"},"direction":{"type":"string","enum":["in","out"]},"status":{"type":"string","enum":["needs_review","categorized"]},"categoryGlAccountId":{"type":["string","null"],"format":"uuid"},"classId":{"type":["string","null"],"format":"uuid"},"className":{"type":["string","null"]},"hasReceipt":{"type":"boolean"},"bankAccountId":{"type":["string","null"],"format":"uuid"},"merchantName":{"type":["string","null"]},"notes":{"type":["string","null"]},"isSplit":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateTransactionInput":{"type":"object","required":["entityId","occurredOn","description","amountCents","currency","direction"],"properties":{"entityId":{"type":"string","format":"uuid"},"occurredOn":{"type":"string","format":"date","example":"2024-01-15"},"description":{"type":"string","minLength":1,"maxLength":500},"merchant":{"type":"string","maxLength":255},"amountCents":{"type":"integer","minimum":1},"currency":{"type":"string","minLength":3,"maxLength":3},"direction":{"type":"string","enum":["in","out"]},"categoryGlAccountId":{"type":"string","format":"uuid"},"bankAccountId":{"type":"string","format":"uuid"},"notes":{"type":"string","maxLength":2000},"confirmDuplicate":{"type":"boolean","description":"Record this row even though an identical manual transaction was created in the last 60 s (the 409 TRANSACTION_DUPLICATE_MANUAL_CREATE case). The new row's metadata.manual_duplicate_confirmed_of names the earlier row."}}},"UpdateTransactionInput":{"type":"object","properties":{"description":{"type":"string","minLength":1,"maxLength":500},"merchant":{"type":"string","maxLength":255},"categoryGlAccountId":{"type":["string","null"],"format":"uuid"},"classId":{"type":["string","null"],"format":"uuid"},"notes":{"type":"string","maxLength":2000}}},"CustomerAccountingClass":{"type":"object","description":"Customer-facing accounting class. Only active classes approved for the company are returned; accountant-only metadata and proposal evidence are never included.\n","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"status":{"type":"string","enum":["active"]},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"AccountingClass":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"status":{"type":"string","enum":["draft","active","inactive"]},"source":{"type":"string","enum":["accountant","bookkeeping_engine","import"]},"isActive":{"type":"boolean"},"approvedAt":{"type":["string","null"],"format":"date-time"},"approvedByUserId":{"type":["string","null"],"format":"uuid"},"metadata":{"type":"object","additionalProperties":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateAccountingClassInput":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":["string","null"],"maxLength":500},"isActive":{"type":"boolean"},"status":{"type":"string","enum":["draft","active","inactive"]}}},"UpdateAccountingClassInput":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":["string","null"],"maxLength":500},"isActive":{"type":"boolean"},"status":{"type":"string","enum":["draft","active","inactive"]}}},"AccountingClassProposal":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"engineRunId":{"type":["string","null"],"format":"uuid"},"transactionId":{"type":["string","null"],"format":"uuid"},"transactionSplitId":{"type":["string","null"],"format":"uuid"},"proposedClassId":{"type":["string","null"],"format":"uuid"},"proposedClassName":{"type":["string","null"]},"proposedClass":{"oneOf":[{"$ref":"#/components/schemas/AccountingClass"},{"type":"null"}]},"approvedClassId":{"type":["string","null"],"format":"uuid"},"status":{"type":"string","enum":["proposed","approved","applied","rejected","correction_proposed"]},"confidence":{"type":["number","null"],"minimum":0,"maximum":1},"applyEligibility":{"type":"boolean"},"source":{"type":"string","enum":["bookkeeping_engine","accountant","import"]},"reasoningSummary":{"type":["string","null"]},"evidence":{"type":"object","additionalProperties":true},"metadata":{"type":"object","additionalProperties":true},"approvedAt":{"type":["string","null"],"format":"date-time"},"approvedByUserId":{"type":["string","null"],"format":"uuid"},"appliedAt":{"type":["string","null"],"format":"date-time"},"rejectedAt":{"type":["string","null"],"format":"date-time"},"rejectedByUserId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ApproveAccountingClassProposalInput":{"type":"object","properties":{"classId":{"type":"string","format":"uuid","description":"Optional active class to use instead of the proposed class."},"apply":{"type":"boolean","description":"Apply to the transaction when possible. Posted journal entries create correction proposals instead."}}},"RejectAccountingClassProposalInput":{"type":"object","properties":{"reason":{"type":"string","maxLength":500}}},"BulkAccountingClassProposalActionInput":{"oneOf":[{"type":"object","required":["action","proposalIds"],"properties":{"action":{"type":"string","enum":["approve"]},"proposalIds":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"string","format":"uuid"}},"apply":{"type":"boolean"}},"additionalProperties":false},{"type":"object","required":["action","proposalIds","classId"],"properties":{"action":{"type":"string","enum":["change"]},"proposalIds":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"string","format":"uuid"}},"classId":{"type":"string","format":"uuid"},"apply":{"type":"boolean"}},"additionalProperties":false},{"type":"object","required":["action","proposalIds"],"properties":{"action":{"type":"string","enum":["reject"]},"proposalIds":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"string","format":"uuid"}},"reason":{"type":"string","maxLength":500}},"additionalProperties":false}],"discriminator":{"propertyName":"action"}},"AccountingClassProposalActionResult":{"type":"object","properties":{"proposal":{"$ref":"#/components/schemas/AccountingClassProposal"},"outcome":{"type":"string","enum":["approved","applied","rejected","correction_proposed"]},"transactionId":{"type":["string","null"],"format":"uuid"},"classId":{"type":["string","null"],"format":"uuid"}}},"AccountingClassProposalActionResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/AccountingClassProposalActionResult"}}},"AccountingClassProposalBulkActionResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/AccountingClassProposalActionResult"}}}}}},"AccountingClassProposalsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/AccountingClassProposal"}}}},"AccountingClassResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/AccountingClass"}}},"AccountingTag":{"type":"object","required":["id","name","retired","retiredAt","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","maxLength":80},"retired":{"type":"boolean"},"retiredAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"AccountingTagResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/AccountingTag"}}},"AccountingTagsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/AccountingTag"}}}},"AccountingTagNameInput":{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"Plain text; unique per company among live tags ignoring case and repeated spaces"}}},"ReplaceTransactionTagsInput":{"type":"object","additionalProperties":false,"required":["tagIds","expectedRevision"],"properties":{"tagIds":{"type":"array","maxItems":20,"uniqueItems":true,"items":{"type":"string","format":"uuid"}},"expectedRevision":{"type":"integer","minimum":0}}},"TransactionTagAssignmentResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["transactionId","tagIds","revision"],"properties":{"transactionId":{"type":"string","format":"uuid"},"tagIds":{"type":"array","items":{"type":"string","format":"uuid"}},"revision":{"type":"integer","minimum":0,"description":"Accepted tag changes so far; send it back as expectedRevision"}}}}},"CustomerAccountingClassesListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/CustomerAccountingClass"}}}},"AccountingClassesListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/AccountingClass"}}}},"TransactionResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Transaction"}}},"TransactionsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Transaction"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"TransactionSummary":{"type":"object","properties":{"transactionCount":{"type":"integer"},"moneyInCents":{"type":"integer"},"moneyOutCents":{"type":"integer"},"netCents":{"type":"integer"},"dateFrom":{"type":["string","null"],"format":"date"},"dateTo":{"type":["string","null"],"format":"date"},"latestOccurredOn":{"type":["string","null"],"format":"date"}}},"TransactionSummaryResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TransactionSummary"}}},"TransactionSplit":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"transactionId":{"type":"string","format":"uuid"},"glAccountId":{"type":"string","format":"uuid"},"classId":{"type":["string","null"],"format":"uuid","description":"Line-level class dimension. Customer-facing responses include this field only when CUSTOMER_APP_INTELLIGENCE_HOME_COMPANY_IDS allowlists the company.\n"},"amountCents":{"type":"integer"},"currency":{"type":"string"},"memo":{"type":["string","null"]}}},"ReplaceSplitsInput":{"type":"object","required":["splits"],"properties":{"splits":{"type":"array","minItems":2,"items":{"type":"object","required":["glAccountId","amountCents"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"classId":{"type":["string","null"],"format":"uuid","description":"Optional split class. Omit to derive from the parent transaction class; set null for intentionally unassigned.\n"},"amountCents":{"type":"integer","minimum":1},"memo":{"type":"string","maxLength":500}}}}}},"TransactionSplitsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/TransactionSplit"}}}},"TransactionImportRow":{"type":"object","description":"One mapped bank-statement row. All fields are optional at the wire level; rows missing a valid `occurredOn` (YYYY-MM-DD), a non-empty `description`, a positive integer `amountCents`, or a `direction` are reported per-row with status `invalid` in the result instead of failing the whole request.\n","properties":{"rowNumber":{"type":"integer","minimum":1,"description":"1-based row position in the source CSV, echoed back in results"},"occurredOn":{"type":["string","null"],"maxLength":64,"description":"Posting date (YYYY-MM-DD)"},"description":{"type":["string","null"],"maxLength":2000},"amountCents":{"type":["integer","null"],"description":"Positive amount in cents; `direction` carries the sign"},"direction":{"type":["string","null"],"enum":["in","out",null]},"merchant":{"type":["string","null"],"maxLength":500},"merchantName":{"type":["string","null"],"maxLength":500},"currency":{"type":["string","null"],"maxLength":64,"description":"ISO 4217 code. When omitted, the row takes the resolved account's currency (the integration or bank account, or the sole bank account bound to a selected GL account) and must otherwise match it. A row with no currency on an account that has none is rejected as invalid. A value that is not an ISO 4217 code marks only that row invalid; the other rows still import.\n"},"sourceStatus":{"type":["string","null"],"maxLength":100},"sourceAccount":{"type":["string","null"],"maxLength":500},"bankDescription":{"type":["string","null"],"maxLength":2000},"memo":{"type":["string","null"],"maxLength":2000},"counterparty":{"type":["string","null"],"maxLength":500},"counterpartyId":{"type":["string","null"],"maxLength":255},"sourceCategory":{"type":["string","null"],"maxLength":500},"providerCategory":{"type":["string","null"],"maxLength":500},"merchantCategoryCode":{"type":["string","null"],"maxLength":64},"trackingId":{"type":["string","null"],"maxLength":255},"timestamp":{"type":["string","null"],"maxLength":255},"categoryAccountCode":{"type":["string","null"],"maxLength":64,"description":"Optional pre-categorization by Chart-of-Accounts code (e.g. \"4100\"). The row posts already categorized against the resolved account instead of landing in Uncategorized, and is excluded from the post-import rule engine. `categoryGlAccountId` wins when both are present.\n"},"categoryGlAccountId":{"type":["string","null"],"format":"uuid","description":"Optional pre-categorization by GL account id (must belong to the company and be active). Wins over `categoryAccountCode`.\n"}}},"ImportTransactionsCsvInput":{"type":"object","required":["accountId","rows"],"properties":{"accountId":{"type":"string","format":"uuid","description":"The \"deposit to\" account rows will post against. May be an integration_account id (Mercury/Ramp/Plaid), a bank_account id (legacy/manual), or a gl_account id (direct Chart-of-Accounts selection, e.g. Undeposited Funds); resolved server-side to a concrete GL account.\n"},"entityId":{"type":"string","format":"uuid","description":"Concrete legal entity that owns the import. Required for direct GL-account imports; when the selected account is connected, this value must match its immutable entity owner.\n"},"rows":{"type":"array","minItems":1,"maxItems":5000,"items":{"$ref":"#/components/schemas/TransactionImportRow"}},"csvFingerprint":{"type":["string","null"],"maxLength":128,"description":"Optional client-generated hash of the raw CSV content. Kept for tracing in raw payloads only; it does not scope row-level dedup.\n"}}},"TransactionImportResultItem":{"type":"object","properties":{"index":{"type":"integer","description":"0-based position of the row in the request `rows` array"},"rowNumber":{"type":"integer","description":"Echo of the request row's `rowNumber` when supplied"},"status":{"type":"string","enum":["imported","duplicate","invalid"]},"transactionId":{"type":"string","format":"uuid","description":"Created transaction id, or the existing transaction for duplicates"},"externalId":{"type":"string","description":"Stable dedup identity stored in `transactions.external_id`"},"reason":{"type":"string","description":"Why the row was skipped (`duplicate`) or rejected (`invalid`)"},"code":{"type":"string","description":"Error code behind an `invalid` row whose write failed (for example `CONFLICT`), when the failure carried one"},"postingError":{"type":"object","description":"Set on an `imported` row whose transaction was written but whose categorize update or journal posting then failed (#2930). The transaction is kept without a journal entry; `message` is the real failure.","required":["message"],"properties":{"message":{"type":"string"},"code":{"type":"string","description":"Error code of the failure, when it carried one"}}}}},"TransactionImportResolvedAccount":{"type":"object","description":"Which resolution path the polymorphic request `accountId` took and which account FKs the imported rows carry. `via: gl_account` (direct Chart-of-Accounts selection) leaves `integrationAccountId` null; `bankAccountId` is the sole non-personal bank account bound to that GL account when exactly one exists (the importer adopts it so rows stay reconcilable, #2119) and null when none or several are bound — the null case is a genuinely GL-only account with no linked bank feed, expected rather than orphaned data. Added by issue #1231; absent on summaries recorded before it shipped.\n","properties":{"via":{"type":"string","enum":["integration_account","bank_account","gl_account"],"description":"Which lookup matched the request `accountId` (table names)"},"glAccountId":{"type":"string","format":"uuid"},"integrationAccountId":{"type":["string","null"],"format":"uuid"},"bankAccountId":{"type":["string","null"],"format":"uuid"},"label":{"type":"string","example":"1015 Personal Checking"}}},"TransactionImportSummary":{"type":"object","description":"Final result of one CSV import run (`ImportSummary` in the API source)","properties":{"requested":{"type":"integer","description":"Number of rows in the request"},"imported":{"type":"integer"},"skipped":{"type":"integer","description":"duplicates + invalid"},"duplicates":{"type":"integer"},"sourceMapped":{"type":"integer","description":"Imported rows linked to an integration or bank account. A Chart-of-Accounts pick counts when the importer adopted the sole bank account bound to that GL (#2119); it is 0 only when no bank account could be resolved for the deposit-to account.\n"},"errors":{"type":"integer","description":"Mirrors `invalid`"},"invalid":{"type":"integer"},"results":{"type":"array","items":{"$ref":"#/components/schemas/TransactionImportResultItem"}},"categorizationTriggered":{"type":"boolean"},"engineSubmissionTriggered":{"type":"boolean"},"bookkeepingEngineTriggered":{"type":"boolean"},"bookkeepingEngineRunId":{"type":"string"},"balancesRecomputed":{"type":"boolean"},"resolvedAccount":{"$ref":"#/components/schemas/TransactionImportResolvedAccount"},"postingFailed":{"type":"integer","description":"Imported rows carrying `postingError` (#2930). Absent on summaries recorded before it shipped."}}},"TransactionImportJob":{"type":"object","description":"Async CSV import job as returned by the accountant portal. Counter fields report live progress while `status` is `pending` or `running`.\n","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"accountId":{"type":"string","format":"uuid","description":"The raw polymorphic `accountId` from the request; see `summary.resolvedAccount` for what it resolved to\n"},"status":{"type":"string","enum":["pending","running","completed","failed"]},"requested":{"type":"integer"},"processed":{"type":"integer","description":"Rows examined so far"},"imported":{"type":"integer"},"skipped":{"type":"integer"},"duplicates":{"type":"integer"},"invalid":{"type":"integer"},"errors":{"type":"integer"},"sourceMapped":{"type":"integer"},"csvFingerprint":{"type":["string","null"]},"requestId":{"type":["string","null"]},"summary":{"description":"Final import summary; null until the job completes","oneOf":[{"$ref":"#/components/schemas/TransactionImportSummary"},{"type":"null"}]},"errorMessage":{"type":["string","null"],"description":"Failure detail when `status` is `failed`"},"startedAt":{"type":["string","null"],"format":"date-time"},"completedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"TransactionImportJobResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TransactionImportJob"}}},"TransactionImportSummaryResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TransactionImportSummary"}}},"AccountantCustomerAccount":{"type":"object","description":"One \"deposit to\" account offered by the accountant CSV import modal (`GET /accountant/companies/{customerId}/accounts`). `type` says which source the row came from and which optional fields apply.\n","required":["id","type","label","currency","provider","mask","glAccountId","entityId","entityName"],"properties":{"id":{"type":"string","format":"uuid","description":"An integration_account, bank_account or gl_account id, by `type`; the polymorphic `accountId` the import endpoint accepts."},"type":{"type":"string","enum":["integration","bank","gl_account"]},"label":{"type":"string"},"currency":{"type":["string","null"],"description":"The currency a bank or connected account gives imported rows that carry none. Always null for a `gl_account` row; see `importCurrency`."},"provider":{"type":["string","null"]},"mask":{"type":["string","null"]},"glAccountId":{"type":["string","null"],"format":"uuid","description":"The GL account the row posts to; for a `gl_account` row, its own id."},"glAccountCode":{"type":["string","null"],"description":"`gl_account` rows only."},"glAccountType":{"type":["string","null"],"description":"`gl_account` rows only: Asset or Liability."},"entityId":{"type":["string","null"],"format":"uuid","description":"The owning legal entity of a bank or connected account. Null for a `gl_account` row, which is company-scoped; the import declares the entity."},"entityName":{"type":["string","null"]},"legalEntities":{"type":"array","description":"`gl_account` rows only: the legal entities the import may declare.","items":{"type":"object","required":["id","name","role"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"role":{"type":["string","null"]}}}},"canAddManualBankAccount":{"type":"boolean","description":"`gl_account` rows only (#2874): a manual bank account may be created on this GL account."},"importCurrency":{"type":["string","null"],"description":"`gl_account` rows only (#2162). The currency the importer gives rows that carry none when this row is picked: that of the sole non-personal bank account bound to the GL account, resolved with the same lookup and rule as the import itself (#2119, #3015). Null when no bank account is bound or several are, in which case the import needs a Currency column. Company-wide; the import itself also scopes the bound accounts to the declared legal entity.\n"}}},"AccountantCustomerAccountsResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/AccountantCustomerAccount"}}}},"Receipt":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"transactionId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"fileName":{"type":"string"},"fileUrl":{"type":"string","format":"uri"},"mimeType":{"type":["string","null"]},"sizeBytes":{"type":["integer","null"]},"uploadedBy":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"}}},"CreateReceiptInput":{"type":"object","required":["fileName","fileUrl"],"properties":{"fileName":{"type":"string","minLength":1,"maxLength":255},"fileUrl":{"type":"string","format":"uri"},"mimeType":{"type":"string","maxLength":100},"sizeBytes":{"type":"integer","minimum":1}}},"ReceiptResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Receipt"}}},"ReceiptsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Receipt"}}}},"GlPeriod":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"status":{"type":"string","enum":["open","closed"]},"closedAt":{"type":["string","null"],"format":"date-time"},"closedByUserId":{"type":["string","null"],"format":"uuid"},"filingLockedAt":{"type":["string","null"],"format":"date-time"},"filingLockedByUserId":{"type":["string","null"],"format":"uuid"}}},"CreateGlPeriodInput":{"type":"object","required":["startDate","endDate"],"properties":{"startDate":{"type":"string","format":"date","example":"2024-01-01"},"endDate":{"type":"string","format":"date","example":"2024-01-31"}}},"GlPeriodResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/GlPeriod"}}},"GlPeriodsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/GlPeriod"}}}},"CloseReadiness":{"type":"object","required":["companyId","ready","blockers","periodId"],"properties":{"companyId":{"type":"string","format":"uuid"},"ready":{"type":"boolean","description":"True when the resolved period has no blockers. An already-closed period is ready: false with an already_closed blocker.\n"},"blockers":{"type":"array","items":{"$ref":"#/components/schemas/CloseReadinessBlocker"}},"periodId":{"type":["string","null"],"format":"uuid","description":"The resolved period. Null only together with the `no_period` blocker."},"latestClosedPeriodEndDate":{"type":["string","null"],"format":"date","description":"Present only when no period resolves (end date of the latest ended closed period, or null) or when the resolved period is already closed (its own end date).\n"}}},"CloseReadinessBlocker":{"type":"object","required":["type","count","message"],"properties":{"type":{"type":"string","enum":["no_period","period_not_ended","already_closed","uncategorized_transactions","blocking_threads","close_blockers"]},"count":{"type":"integer","minimum":1},"message":{"type":"string"}}},"CloseReadinessResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/CloseReadiness"}}},"TriggerAutoCloseInput":{"type":"object","description":"Send `{}` to close the earliest ended open period.","properties":{"periodId":{"type":"string","format":"uuid","description":"GL period to close. Omitted, the earliest ended open period is used."}}},"AutoCloseResult":{"type":"object","required":["companyId","closed","periodId","reason"],"properties":{"companyId":{"type":"string","format":"uuid"},"closed":{"type":"boolean"},"periodId":{"type":["string","null"],"format":"uuid"},"reason":{"type":"string"},"closingEntryId":{"type":["string","null"],"format":"uuid","description":"Closing journal entry for the period, or null when none was posted. Absent when the close stopped before posting schedule entries."},"scheduledPostings":{"$ref":"#/components/schemas/AutoCloseScheduledPostings"}}},"AutoCloseScheduledPostings":{"type":"object","description":"Due schedule entries posted by this close. Absent when the close stopped before posting schedule entries.","required":["companyId","periodEndDate","postedCount","skippedCount","failedCount","postedEntryIds","failures"],"properties":{"companyId":{"type":"string","format":"uuid"},"periodEndDate":{"type":"string","format":"date"},"postedCount":{"type":"integer","minimum":0},"skippedCount":{"type":"integer","minimum":0},"failedCount":{"type":"integer","minimum":0},"postedEntryIds":{"type":"array","items":{"type":"string"}},"failures":{"type":"array","items":{"type":"object","required":["entryId","scheduleId","reason"],"properties":{"entryId":{"type":"string"},"scheduleId":{"type":"string"},"reason":{"type":"string"}}}}}},"AutoCloseResultResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/AutoCloseResult"}}},"GlAccountRoleMapping":{"type":"object","required":["id","companyId","role","glAccountId","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["TRANSFER_CLEARING","REALIZED_FX_GAIN_LOSS","UNREALIZED_FX_GAIN_LOSS"]},"glAccountId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"updatedByUserId":{"type":["string","null"],"format":"uuid"}}},"FxAccountingRoleAuthority":{"type":"object","required":["role"],"properties":{"role":{"type":"string","enum":["TRANSFER_CLEARING","REALIZED_FX_GAIN_LOSS","UNREALIZED_FX_GAIN_LOSS"]},"glAccountId":{"type":"string","format":"uuid"},"mapping":{"oneOf":[{"$ref":"#/components/schemas/GlAccountRoleMapping"},{"type":"null"}]},"account":{"oneOf":[{"$ref":"#/components/schemas/GlAccount"},{"type":"null"}]}}},"FxAccountingRoleResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/FxAccountingRoleAuthority"}}},"FxAccountingRolesResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/FxAccountingRoleAuthority"}}}},"FxRevaluationResult":{"type":"object","required":["runId","companyId","periodId","status","idempotent","positionsRevalued","netUnrealizedFxCents","journalEntryIds"],"properties":{"runId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"periodId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["in_progress","completed"]},"idempotent":{"type":"boolean"},"positionsRevalued":{"type":"integer","minimum":0},"netUnrealizedFxCents":{"type":"integer"},"journalEntryIds":{"type":"array","items":{"type":"string","format":"uuid"}}}},"FxRevaluationPosition":{"type":"object","properties":{"runId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"glAccountId":{"type":"string","format":"uuid"},"glAccountCode":{"type":"string"},"glAccountName":{"type":"string"},"isMonetary":{"type":"boolean","const":true},"transactionCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"functionalCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"foreignBalanceCents":{"type":"integer"},"carryingFunctionalCents":{"type":"integer"},"closingRateId":{"type":"string","format":"uuid"},"closingRate":{"type":"string"},"targetFunctionalCents":{"type":"integer"},"adjustmentCents":{"type":"integer"},"journalEntryId":{"type":"string","format":"uuid"}}},"FxRevaluationResultResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/FxRevaluationResult"}}},"FxRevaluationDetailResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"run":{"type":"object","description":"Durable claimed, completed, or failed run authority."},"positions":{"type":"array","items":{"$ref":"#/components/schemas/FxRevaluationPosition"}}}}}},"JournalLine":{"type":"object","required":["id","journalEntryId","glAccountId","debitCents","creditCents","currency","minorUnitExponent","ledgerDebitCents","ledgerCreditCents","ledgerCurrency","ledgerMinorUnitExponent"],"properties":{"id":{"type":"string","format":"uuid"},"journalEntryId":{"type":"string","format":"uuid"},"glAccountId":{"type":"string","format":"uuid"},"classId":{"type":["string","null"],"format":"uuid","description":"Line-level class dimension for downstream reporting. Accountant-portal responses always carry this field. Customer-facing responses do not carry it on journal lines.\n"},"className":{"type":["string","null"],"description":"Name of the class in `classId`, resolved from the company's class list. Accountant-portal responses only, present when the class is known.\n"},"classStatus":{"type":"string","enum":["draft","active","inactive"],"description":"Status of the class in `classId`. Accountant-portal responses only; never returned to the customer app.\n"},"debitCents":{"type":"integer"},"creditCents":{"type":"integer"},"currency":{"type":"string"},"memo":{"type":["string","null"]},"transactionId":{"type":["string","null"],"format":"uuid"},"documentId":{"type":["string","null"],"format":"uuid"}}},"JournalEntry":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":["string","null"],"format":"uuid","description":"Concrete legal posting entity. Null is legacy data and resolves to the primary entity."},"entryDate":{"type":"string","format":"date"},"description":{"type":"string"},"sourceType":{"type":"string","enum":["transaction","document","adjustment","system"]},"sourceId":{"type":["string","null"],"format":"uuid"},"periodId":{"type":["string","null"],"format":"uuid"},"status":{"type":"string","enum":["posted","void"]},"createdByUserId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":["string","null"],"format":"date-time"},"deletedByUserId":{"type":["string","null"],"format":"uuid"},"relatedJeId":{"type":["string","null"],"format":"uuid"},"adjustmentReason":{"type":["string","null"]},"isClosingEntry":{"type":"boolean","description":"A period-end closing entry (a system entry keyed on one of the company's periods). Reports leave these out of the P&L."},"sourceLabel":{"type":"string"},"sourceLink":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string"},"id":{"type":"string"}}},{"type":"null"}]},"lines":{"type":"array","items":{"$ref":"#/components/schemas/JournalLine"}}}},"AuditLogEntry":{"type":"object","required":["id","action","entityType","entityId","actorPrincipalType","actorId","actorApiKeyId","createdAt"],"properties":{"id":{"type":"string"},"companyId":{"type":["string","null"]},"userId":{"type":["string","null"]},"actorPrincipalType":{"type":["string","null"],"enum":["human","service","worker","system","unknown",null],"description":"Persisted provenance. Null legacy attribution is unknown, not system."},"actorId":{"type":["string","null"],"description":"Resolved principal UUID or server-owned worker/system identifier."},"actorApiKeyId":{"type":["string","null"],"format":"uuid","description":"Verified credential ID; never an API key secret."},"action":{"type":"string"},"entityType":{"type":"string"},"entityId":{"type":"string"},"changes":{"type":["object","null"],"additionalProperties":true},"createdAt":{"type":"string","format":"date-time"}}},"VoidJournalEntryRequest":{"type":"object","properties":{"reason":{"type":"string","maxLength":500}}},"CorrectJournalEntryDateRequest":{"type":"object","required":["entryDate","evidence"],"additionalProperties":false,"properties":{"entryDate":{"type":"string","format":"date","description":"Target posted date (YYYY-MM-DD) inside the ledger date domain."},"evidence":{"type":"string","minLength":8,"maxLength":500,"description":"Source of the corrected date (for example a QuickBooks TxnDate)."}}},"RepairTransactionBankOffsetRequest":{"type":"object","required":["categoryGlAccountId","reason"],"additionalProperties":false,"properties":{"categoryGlAccountId":{"type":"string","format":"uuid","description":"The GL account the counterpart line posts to and the transaction is categorized to. Never the transaction's own bank or card GL account."},"reason":{"type":"string","minLength":8,"maxLength":500,"description":"Why this journal entry is being repaired; kept in the audit row, never in the journal entry."},"dryRun":{"type":"boolean","default":true,"description":"When true (the default) the response shows the plan and nothing is written."},"expectedJournalEntryId":{"type":"string","format":"uuid","description":"The `journalEntryId` the dry run returned. Required when `dryRun` is false."}}},"BankOffsetRepairLine":{"type":"object","required":["glAccountId","glAccountCode","debitCents","creditCents"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"glAccountCode":{"type":["string","null"]},"debitCents":{"type":"integer","minimum":0},"creditCents":{"type":"integer","minimum":0}}},"BankOffsetRepairResult":{"type":"object","required":["status","transactionId","journalEntryId","replacementJournalEntryId","bankGlAccountId","categoryGlAccountIdBefore","categoryGlAccountIdAfter","suggestedCategoryGlAccountId","beforeLines","afterLines"],"properties":{"status":{"type":"string","enum":["dry_run","repaired","already_repaired"]},"transactionId":{"type":"string","format":"uuid"},"journalEntryId":{"type":"string","format":"uuid","description":"The posted journal entry the request examined; the one voided when `status` is `repaired`."},"replacementJournalEntryId":{"type":["string","null"],"format":"uuid","description":"The new posted journal entry; null unless `status` is `repaired`."},"bankGlAccountId":{"type":"string","format":"uuid","description":"GL account of the transaction's own bank or card account."},"categoryGlAccountIdBefore":{"type":["string","null"],"format":"uuid"},"categoryGlAccountIdAfter":{"type":["string","null"],"format":"uuid","description":"The category column as the apply leaves it, or as a dry run would leave it. An `already_repaired` reply that wrote nothing reports the column unchanged, which may differ from the requested category."},"suggestedCategoryGlAccountId":{"type":["string","null"],"format":"uuid","description":"Counterpart account of the most recent correct voided posting of this transaction, when there is one. A hint only; it is never applied."},"beforeLines":{"type":"array","items":{"$ref":"#/components/schemas/BankOffsetRepairLine"}},"afterLines":{"type":"array","items":{"$ref":"#/components/schemas/BankOffsetRepairLine"}}}},"BankOffsetRepairResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/BankOffsetRepairResult"}}},"CreateJournalEntryInput":{"type":"object","required":["entryDate","description","sourceType","lines"],"properties":{"entityId":{"type":"string","format":"uuid","description":"Concrete legal posting entity; defaults to the company's primary entity."},"entryDate":{"type":"string","format":"date","example":"2024-01-15"},"description":{"type":"string","minLength":1,"maxLength":500},"sourceType":{"type":"string","enum":["transaction","document","adjustment","system"]},"sourceId":{"type":"string","format":"uuid"},"periodId":{"type":"string","format":"uuid"},"postingKey":{"type":"string","description":"Optional identity a hand-written replacement can inherit from a voided transaction-sourced entry (`transaction:<uuid>`). Required to keep the engine from re-posting the same transaction (#1975).\n","pattern":"^transaction:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"},"lines":{"type":"array","minItems":2,"items":{"type":"object","required":["glAccountId"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"debitCents":{"type":"integer","minimum":0,"default":0},"creditCents":{"type":"integer","minimum":0,"default":0},"memo":{"type":"string","maxLength":500},"transactionId":{"type":"string","format":"uuid"},"documentId":{"type":"string","format":"uuid"}}}}}},"JournalEntryResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/JournalEntry"}}},"JournalEntriesListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/JournalEntry"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"GlBalanceMonthly":{"type":"object","required":["companyId","entityId","glAccountId","month","debitTotalCents","creditTotalCents","endingBalanceCents","currency"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid","description":"Immutable concrete legal-entity owner of this derived balance."},"glAccountId":{"type":"string","format":"uuid"},"month":{"type":"string","format":"date"},"debitTotalCents":{"type":"integer"},"creditTotalCents":{"type":"integer"},"endingBalanceCents":{"type":"integer"},"currency":{"type":"string"}}},"GlBalancesListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/GlBalanceMonthly"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"FixedAsset":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"name":{"type":"string"},"originalCostCents":{"type":"integer"},"currency":{"type":"string","example":"USD"},"inServiceDate":{"type":"string","format":"date"},"usefulLifeMonths":{"type":"integer"},"method":{"type":"string","enum":["straight_line"]},"salvageValueCents":{"type":"integer"},"glAssetAccountId":{"type":["string","null"],"format":"uuid"},"glDeprExpenseAccountId":{"type":["string","null"],"format":"uuid"},"glAccumDeprAccountId":{"type":["string","null"],"format":"uuid"},"status":{"type":"string","enum":["active","retired"]},"createdAt":{"type":"string","format":"date-time"}}},"DepreciationScheduleEntry":{"type":"object","properties":{"assetId":{"type":"string","format":"uuid"},"month":{"type":"string","format":"date"},"depreciationCents":{"type":"integer"},"accumulatedCents":{"type":"integer"},"netBookValueCents":{"type":"integer"}}},"CreateFixedAssetInput":{"type":"object","required":["name","originalCostCents","inServiceDate","usefulLifeMonths"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"originalCostCents":{"type":"integer","minimum":1},"inServiceDate":{"type":"string","format":"date","example":"2024-01-15"},"usefulLifeMonths":{"type":"integer","minimum":1},"currency":{"type":"string","minLength":3,"maxLength":3,"default":"USD"},"method":{"type":"string","enum":["straight_line"],"default":"straight_line"},"salvageValueCents":{"type":"integer","minimum":0,"default":0},"glAssetAccountId":{"type":"string","format":"uuid"},"glDeprExpenseAccountId":{"type":"string","format":"uuid"},"glAccumDeprAccountId":{"type":"string","format":"uuid"}}},"UpdateFixedAssetInput":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"glAssetAccountId":{"type":["string","null"],"format":"uuid"},"glDeprExpenseAccountId":{"type":["string","null"],"format":"uuid"},"glAccumDeprAccountId":{"type":["string","null"],"format":"uuid"}}},"FixedAssetResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/FixedAsset"}}},"FixedAssetsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/FixedAsset"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"DepreciationScheduleResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/DepreciationScheduleEntry"}}}},"Loan":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"lender":{"type":"string"},"originalAmountCents":{"type":"integer"},"currency":{"type":"string","example":"USD"},"startDate":{"type":"string","format":"date"},"interestRateBps":{"type":"integer","description":"Interest rate in basis points (500 = 5%)"},"termMonths":{"type":"integer"},"monthlyPaymentCents":{"type":"integer","description":"Computed from PMT formula"},"maturityDate":{"type":"string","format":"date","description":"Computed from startDate + termMonths"},"glLoanLiabilityAccountId":{"type":["string","null"],"format":"uuid"},"glInterestExpenseAccountId":{"type":["string","null"],"format":"uuid"},"glCashAccountId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"}}},"AmortizationScheduleEntry":{"type":"object","properties":{"loanId":{"type":"string","format":"uuid"},"paymentNumber":{"type":"integer"},"paymentDate":{"type":"string","format":"date"},"principalCents":{"type":"integer"},"interestCents":{"type":"integer"},"balanceCents":{"type":"integer"}}},"LoanPayment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"loanId":{"type":"string","format":"uuid"},"paymentDate":{"type":"string","format":"date"},"amountCents":{"type":"integer"},"currency":{"type":"string"},"transactionId":{"type":["string","null"],"format":"uuid"},"journalEntryId":{"type":["string","null"],"format":"uuid"}}},"CreateLoanInput":{"type":"object","required":["lender","originalAmountCents","startDate","interestRateBps","termMonths"],"properties":{"lender":{"type":"string","minLength":1,"maxLength":255},"originalAmountCents":{"type":"integer","minimum":1},"startDate":{"type":"string","format":"date","example":"2024-01-15"},"interestRateBps":{"type":"integer","minimum":0},"termMonths":{"type":"integer","minimum":1},"currency":{"type":"string","minLength":3,"maxLength":3,"default":"USD"},"glLoanLiabilityAccountId":{"type":"string","format":"uuid"},"glInterestExpenseAccountId":{"type":"string","format":"uuid"},"glCashAccountId":{"type":"string","format":"uuid"}}},"UpdateLoanInput":{"type":"object","properties":{"lender":{"type":"string","minLength":1,"maxLength":255},"glLoanLiabilityAccountId":{"type":["string","null"],"format":"uuid"},"glInterestExpenseAccountId":{"type":["string","null"],"format":"uuid"},"glCashAccountId":{"type":["string","null"],"format":"uuid"}}},"CreateLoanPaymentInput":{"type":"object","required":["paymentDate","amountCents"],"properties":{"paymentDate":{"type":"string","format":"date","example":"2024-02-15"},"amountCents":{"type":"integer","minimum":1},"currency":{"type":"string","minLength":3,"maxLength":3,"default":"USD"},"transactionId":{"type":"string","format":"uuid"},"journalEntryId":{"type":"string","format":"uuid"}}},"LoanResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Loan"}}},"LoansListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Loan"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"AmortizationScheduleResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/AmortizationScheduleEntry"}}}},"LoanPaymentResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/LoanPayment"}}},"LoanPaymentsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/LoanPayment"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"BooksStatus":{"type":"object","properties":{"companyId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["current","pending_user","pending_median"]},"lastCloseDate":{"type":["string","null"],"format":"date"},"dataAsOfDate":{"type":["string","null"],"format":"date"},"message":{"type":["string","null"]},"updatedAt":{"type":"string","format":"date-time"}}},"UpdateBooksStatusInput":{"type":"object","properties":{"status":{"type":"string","enum":["current","pending_user","pending_median"]},"lastCloseDate":{"type":["string","null"],"format":"date"},"dataAsOfDate":{"type":["string","null"],"format":"date"},"message":{"type":["string","null"],"maxLength":1000}}},"BooksStatusResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/BooksStatus"}}},"BooksIntegrityStatus":{"type":"object","additionalProperties":false,"required":["companyId","status","checkedAt"],"description":"The company's latest automated books integrity verdict (#2010). Built from each scheduled check window's latest passed or failed run; errored, skipped and operator runs are not verdicts. `failing` while any window's latest verdict failed on at least one invariant other than the books invariants I22–I30, or on the books invariant I25 (business event failed to post) or I29 (books differ from the bank balance). The other books invariants never make it `failing` by themselves. `not_checked` means no verdict exists and is not a failure. No invariant codes, counts or amounts are exposed.","properties":{"companyId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["failing","passing","not_checked"]},"checkedAt":{"type":["string","null"],"format":"date-time","description":"failing: when the most recent failing check finished. passing: when the most recent check finished. not_checked: null."}}},"BooksIntegrityStatusResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/BooksIntegrityStatus"}}},"WeeklyEmailSettings":{"type":"object","properties":{"companyId":{"type":"string","format":"uuid"},"enabled":{"type":"boolean"},"cadence":{"type":"string","enum":["weekly"]},"sendDay":{"type":"string","enum":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"]},"sendTime":{"type":"string","description":"HH:MM 24-hour local clock time in `timezone`"},"timezone":{"type":"string","description":"IANA time zone the send day and time are read in (#2656). Defaults to America/New_York.","example":"America/New_York"},"businessModel":{"type":"string","enum":["software","services","digital"],"description":"Effective copy variant, mapped from the company's stored business model (#1967). The per-settings value is used only when the company model cannot be read or is unset.\n"},"intro":{"type":["string","null"]},"enabledSections":{"type":"array","items":{"type":"string","enum":["snapshot","pl","changes"]}},"updatedAt":{"type":"string","format":"date-time"}},"required":["companyId","enabled","cadence","sendDay","sendTime","timezone","businessModel","enabledSections"]},"WeeklyEmailSettingsResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WeeklyEmailSettings"}}},"UpdateWeeklyEmailSettingsInput":{"type":"object","properties":{"enabled":{"type":"boolean"},"cadence":{"type":"string","enum":["weekly"]},"sendDay":{"type":"string","enum":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"]},"sendTime":{"type":"string"},"timezone":{"type":"string","maxLength":100,"description":"IANA time zone, e.g. America/New_York. Rejected with 422 when the zone is unknown."},"businessModel":{"type":"string","enum":["software","services","digital"],"deprecated":true,"description":"Deprecated (#1967): the company's stored business model decides the copy variant; this value is only the fallback when the company model cannot be read or is unset.\n"},"intro":{"type":["string","null"]},"enabledSections":{"type":"array","items":{"type":"string","enum":["snapshot","pl","changes"]}}}},"WeeklyEmailPreview":{"type":"object","description":"Fully-resolved email model; preview renders this exactly as sent.","properties":{"mode":{"type":"string","enum":["weekly","firstOfMonth"]},"from":{"type":"string"},"to":{"type":"array","items":{"type":"string"}},"subject":{"type":"string"},"intro":{"type":"string"},"snapshot":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"value":{"type":"string"},"amountCents":{"type":["integer","null"]},"sub":{"type":["string","null"]}}}},"sections":{"type":"array","items":{"type":"object","properties":{"tone":{"type":"string","enum":["good","watch","attention"]},"text":{"type":"string"}}}},"monthlyClose":{"type":["object","null"],"properties":{"month":{"type":"string"},"priorMonth":{"type":["string","null"]},"headline":{"type":"string"},"netIncomeValue":{"type":"string"},"stats":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"value":{"type":"string"},"currentCents":{"type":"integer"},"priorCents":{"type":["integer","null"]},"goodWhenUp":{"type":"boolean"}}}}}},"omittedSections":{"type":"array","description":"Sections dropped because no real metric backed them (anti-hallucination).","items":{"type":"string"}}},"required":["mode","from","to","subject","intro","snapshot","sections","omittedSections"]},"WeeklyEmailPreviewResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WeeklyEmailPreview"}}},"CommsSettings":{"type":"object","properties":{"companyId":{"type":"string","format":"uuid"},"preferredChannel":{"type":"string","enum":["email","iMessage","sms","whatsapp","slack","phone_call"]},"frequency":{"type":"string","enum":["realtime","daily","weekly","biweekly","monthly"]},"updatedAt":{"type":"string","format":"date-time"}}},"UpdateCommsSettingsInput":{"type":"object","properties":{"preferredChannel":{"type":"string","enum":["email","iMessage","sms","whatsapp","slack","phone_call"]},"frequency":{"type":"string","enum":["realtime","daily","weekly","biweekly","monthly"],"readOnly":true,"description":"Accepted for backwards compatibility but IGNORED. Delivery cadence is derived from preferredChannel: Slack means realtime thread mirroring, every other channel means the daily digest. The digest only ever selected frequency = 'daily', so letting clients set this silently muted any company holding another value."}}},"CommsSettingsResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/CommsSettings"}}},"CommsContact":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"name":{"type":"string"},"email":{"type":["string","null"],"format":"email"},"phone":{"type":["string","null"]},"role":{"type":"string","enum":["primary","backup"]},"createdAt":{"type":"string","format":"date-time"}}},"CreateCommsContactInput":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"email":{"type":"string","format":"email","maxLength":255},"phone":{"type":"string","maxLength":50},"role":{"type":"string","enum":["primary","backup"],"default":"primary"}}},"UpdateCommsContactInput":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"email":{"type":["string","null"],"format":"email","maxLength":255},"phone":{"type":["string","null"],"maxLength":50},"role":{"type":"string","enum":["primary","backup"]}}},"CommsContactResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/CommsContact"}}},"CommsContactsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/CommsContact"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"ConsolidationMethod":{"type":"string","enum":["full","equity","proportional"]},"ConsolidationGroupCompany":{"type":"object","additionalProperties":false,"required":["companyId","parentCompanyId","ownershipPct","consolidationMethod"],"properties":{"companyId":{"type":"string","format":"uuid"},"parentCompanyId":{"type":["string","null"],"format":"uuid"},"ownershipPct":{"type":"number","exclusiveMinimum":0,"maximum":100,"multipleOf":0.0001},"consolidationMethod":{"$ref":"#/components/schemas/ConsolidationMethod"}}},"ConsolidationGroupVersion":{"type":"object","additionalProperties":false,"required":["id","effectiveFrom","effectiveTo","presentationCurrency","companies"],"properties":{"id":{"type":"string","format":"uuid"},"effectiveFrom":{"type":"string","format":"date"},"effectiveTo":{"type":["string","null"],"format":"date","description":"Exclusive end date, or null for the open effective version."},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"companies":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ConsolidationGroupCompany"}}}},"ConsolidationGroup":{"type":"object","additionalProperties":false,"required":["id","name","createdByUserId","createdAt","version"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","minLength":1,"maxLength":200},"createdByUserId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"version":{"$ref":"#/components/schemas/ConsolidationGroupVersion"}}},"CreateConsolidationGroupInput":{"type":"object","additionalProperties":false,"required":["name","presentationCurrency","effectiveFrom","companies"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"effectiveFrom":{"type":"string","format":"date"},"companies":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ConsolidationGroupCompany"}}}},"ConsolidationGroupResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ConsolidationGroup"}}},"ConsolidationGroupsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ConsolidationGroup"}}}},"ConsolidationRollupManifestItem":{"type":"object","additionalProperties":false,"required":["companyId","snapshotId"],"properties":{"companyId":{"type":"string","format":"uuid"},"snapshotId":{"type":"string","format":"uuid"}}},"CreateConsolidationRollupInput":{"oneOf":[{"$ref":"#/components/schemas/CreateProfitAndLossConsolidationRollupInput"},{"$ref":"#/components/schemas/CreateBalanceSheetConsolidationRollupInput"}],"discriminator":{"propertyName":"reportType","mapping":{"profit_and_loss":"#/components/schemas/CreateProfitAndLossConsolidationRollupInput","balance_sheet":"#/components/schemas/CreateBalanceSheetConsolidationRollupInput"}}},"CreateProfitAndLossConsolidationRollupInput":{"type":"object","additionalProperties":false,"required":["reportType","constituentSnapshots"],"properties":{"reportType":{"type":"string","const":"profit_and_loss"},"constituentSnapshots":{"type":"array","minItems":2,"maxItems":250,"description":"Exact manifest: one immutable standalone presentation snapshot for every company in the sealed group version, with no extras.\n","items":{"$ref":"#/components/schemas/ConsolidationRollupManifestItem"}}}},"CreateBalanceSheetConsolidationRollupInput":{"type":"object","additionalProperties":false,"required":["reportType","constituentSnapshots","translationAdjustmentSnapshotId"],"properties":{"reportType":{"type":"string","const":"balance_sheet"},"constituentSnapshots":{"type":"array","minItems":2,"maxItems":250,"description":"Exact manifest: one immutable standalone balance-sheet presentation snapshot for every company in the sealed group version. The manifest must exactly match the named CTA snapshot.\n","items":{"$ref":"#/components/schemas/ConsolidationRollupManifestItem"}},"translationAdjustmentSnapshotId":{"type":"string","format":"uuid","description":"Exact sealed CTA snapshot for this group version, period, currency, and standalone snapshot manifest. No latest-snapshot selection occurs.\n"}}},"ConsolidationRollupConstituentSnapshot":{"type":"object","additionalProperties":false,"required":["companyId","snapshotId","snapshotOutputHash"],"properties":{"companyId":{"type":"string","format":"uuid"},"snapshotId":{"type":"string","format":"uuid"},"snapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"}}},"ConsolidationRollupContribution":{"type":"object","additionalProperties":false,"required":["companyId","snapshotId","sourceAccountId","sourceCode","presentationAmountCents"],"properties":{"companyId":{"type":"string","format":"uuid"},"snapshotId":{"type":"string","format":"uuid"},"sourceAccountId":{"type":"string","format":"uuid"},"sourceCode":{"type":"string"},"presentationAmountCents":{"type":"integer"}}},"ConsolidationRollupLine":{"type":"object","additionalProperties":false,"required":["code","name","reportSection","reportSectionLabel","presentationAmountCents","contributions"],"properties":{"code":{"type":"string"},"name":{"type":"string"},"reportSection":{"type":"string"},"reportSectionLabel":{"type":"string"},"presentationAmountCents":{"type":"integer"},"contributions":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/ConsolidationRollupContribution"}}}},"ConsolidationRollupConstituentSummary":{"type":"object","additionalProperties":false,"required":["companyId","parentCompanyId","ownershipPct","consolidationMethod","snapshotId","snapshotOutputHash","totals"],"properties":{"companyId":{"type":"string","format":"uuid"},"parentCompanyId":{"type":["string","null"],"format":"uuid"},"ownershipPct":{"type":"number","exclusiveMinimum":0,"maximum":100},"consolidationMethod":{"type":"string","const":"full"},"snapshotId":{"type":"string","format":"uuid"},"snapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"totals":{"$ref":"#/components/schemas/PresentationProfitAndLossTotals"}}},"ConsolidationProfitAndLossRollupPayload":{"type":"object","additionalProperties":false,"required":["reportType","stage","gaapStatus","isConsolidatedFinancialStatement","accountMappingStatus","pendingProcedures","hasData","nciPending","constituents","lines","totals"],"properties":{"reportType":{"type":"string","const":"profit_and_loss"},"stage":{"type":"string","const":"pre_elimination_management_rollup"},"gaapStatus":{"type":"string","const":"incomplete"},"isConsolidatedFinancialStatement":{"type":"boolean","const":false},"accountMappingStatus":{"type":"string","const":"shared_chart_exact_only"},"pendingProcedures":{"type":"array","minItems":3,"maxItems":3,"prefixItems":[{"type":"string","const":"uniform_accounting_policy_adjustments"},{"type":"string","const":"intercompany_eliminations"},{"type":"string","const":"nci_attribution"}],"items":false},"hasData":{"type":"boolean"},"nciPending":{"type":"boolean","description":"True when a fully consolidated non-root constituent is less than 100 percent owned. The rollup includes 100 percent of that company; no ownership multiplication or NCI attribution is performed here.\n"},"constituents":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ConsolidationRollupConstituentSummary"}},"lines":{"type":"array","items":{"$ref":"#/components/schemas/ConsolidationRollupLine"}},"totals":{"$ref":"#/components/schemas/PresentationProfitAndLossTotals"}}},"ConsolidationBalanceSheetContribution":{"type":"object","additionalProperties":false,"required":["companyId","snapshotId","sourceAccountId","sourceCode","presentationAmountCents"],"properties":{"companyId":{"type":"string","format":"uuid"},"snapshotId":{"type":"string","format":"uuid"},"sourceAccountId":{"type":["string","null"],"format":"uuid"},"sourceCode":{"type":["string","null"]},"presentationAmountCents":{"type":"integer"}}},"ConsolidationBalanceSheetLine":{"type":"object","additionalProperties":false,"required":["sourceKind","sourceAccountId","code","name","reportSection","reportSectionLabel","statementClass","translationMethod","presentationAmountCents","isPostedToLedger","contributions"],"properties":{"sourceKind":{"type":"string","enum":["account","current_earnings","translation_adjustment"]},"sourceAccountId":{"type":"null"},"code":{"type":["string","null"]},"name":{"type":"string"},"reportSection":{"type":"string"},"reportSectionLabel":{"type":"string"},"statementClass":{"type":"string","enum":["asset","liability","equity","current_earnings"]},"translationMethod":{"type":"string","enum":["closing","historical","average","identity","mixed","cta"]},"presentationAmountCents":{"type":"integer"},"isPostedToLedger":{"type":"boolean","const":false},"contributions":{"type":"array","items":{"$ref":"#/components/schemas/ConsolidationBalanceSheetContribution"}}}},"ConsolidationBalanceSheetTotals":{"type":"object","additionalProperties":false,"required":["assetsCents","liabilitiesCents","equityBeforeTranslationAdjustmentCents","cumulativeTranslationAdjustmentCents","equityIncludingTranslationAdjustmentCents","liabilitiesAndEquityCents","differenceCents"],"properties":{"assetsCents":{"type":"integer"},"liabilitiesCents":{"type":"integer"},"equityBeforeTranslationAdjustmentCents":{"type":"integer"},"cumulativeTranslationAdjustmentCents":{"type":"integer"},"equityIncludingTranslationAdjustmentCents":{"type":"integer"},"liabilitiesAndEquityCents":{"type":"integer"},"differenceCents":{"type":"integer","const":0}}},"ConsolidationBalanceSheetConstituentSummary":{"type":"object","additionalProperties":false,"required":["companyId","parentCompanyId","ownershipPct","consolidationMethod","snapshotId","snapshotOutputHash","totals"],"properties":{"companyId":{"type":"string","format":"uuid"},"parentCompanyId":{"type":["string","null"],"format":"uuid"},"ownershipPct":{"type":"number","exclusiveMinimum":0,"maximum":100},"consolidationMethod":{"type":"string","const":"full"},"snapshotId":{"type":"string","format":"uuid"},"snapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"totals":{"$ref":"#/components/schemas/PresentationBalanceSheetPresentationTotals"}}},"ConsolidationRollupTranslationAdjustmentAuthority":{"type":"object","additionalProperties":false,"required":["snapshotId","snapshotOutputHash","cumulativeTranslationAdjustmentCents","isPostedToLedger"],"properties":{"snapshotId":{"type":"string","format":"uuid"},"snapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"cumulativeTranslationAdjustmentCents":{"type":"integer"},"isPostedToLedger":{"type":"boolean","const":false}}},"ConsolidationRollupTranslationAdjustmentSnapshot":{"type":"object","additionalProperties":false,"required":["snapshotId","snapshotOutputHash"],"properties":{"snapshotId":{"type":"string","format":"uuid"},"snapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"}}},"ConsolidationBalanceSheetRollupPayload":{"type":"object","additionalProperties":false,"required":["reportType","stage","gaapStatus","isConsolidatedFinancialStatement","accountMappingStatus","pendingProcedures","hasData","nciPending","constituents","translationAdjustmentAuthority","lines","totals"],"properties":{"reportType":{"type":"string","const":"balance_sheet"},"stage":{"type":"string","const":"pre_elimination_management_rollup"},"gaapStatus":{"type":"string","const":"incomplete"},"isConsolidatedFinancialStatement":{"type":"boolean","const":false},"accountMappingStatus":{"type":"string","const":"shared_chart_exact_only"},"pendingProcedures":{"type":"array","minItems":5,"maxItems":5,"prefixItems":[{"type":"string","const":"uniform_accounting_policy_adjustments"},{"type":"string","const":"parent_investment_subsidiary_equity_elimination"},{"type":"string","const":"intercompany_eliminations"},{"type":"string","const":"nci_attribution"},{"type":"string","const":"disposal_reclassification"}],"items":false},"hasData":{"type":"boolean"},"nciPending":{"type":"boolean"},"constituents":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ConsolidationBalanceSheetConstituentSummary"}},"translationAdjustmentAuthority":{"$ref":"#/components/schemas/ConsolidationRollupTranslationAdjustmentAuthority"},"lines":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/ConsolidationBalanceSheetLine"}},"totals":{"$ref":"#/components/schemas/ConsolidationBalanceSheetTotals"}}},"ConsolidationRollupPayload":{"oneOf":[{"$ref":"#/components/schemas/ConsolidationProfitAndLossRollupPayload"},{"$ref":"#/components/schemas/ConsolidationBalanceSheetRollupPayload"}],"discriminator":{"propertyName":"reportType","mapping":{"profit_and_loss":"#/components/schemas/ConsolidationProfitAndLossRollupPayload","balance_sheet":"#/components/schemas/ConsolidationBalanceSheetRollupPayload"}}},"ConsolidationRollupSnapshot":{"type":"object","additionalProperties":false,"required":["id","groupId","groupVersionId","reportType","periodStart","periodEnd","presentationCurrency","sourceHash","outputHash","fingerprint","payload","constituentSnapshots","translationAdjustmentSnapshot","createdByUserId","createdAt","sealedAt"],"properties":{"id":{"type":"string","format":"uuid"},"groupId":{"type":"string","format":"uuid"},"groupVersionId":{"type":"string","format":"uuid"},"reportType":{"type":"string","enum":["profit_and_loss","balance_sheet"]},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"sourceHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"outputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"payload":{"$ref":"#/components/schemas/ConsolidationRollupPayload"},"constituentSnapshots":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ConsolidationRollupConstituentSnapshot"}},"translationAdjustmentSnapshot":{"description":"Null for P&L rollups. Balance-sheet rollups name the exact sealed CTA snapshot and output hash consumed by the immutable result.\n","oneOf":[{"$ref":"#/components/schemas/ConsolidationRollupTranslationAdjustmentSnapshot"},{"type":"null"}]},"createdByUserId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"sealedAt":{"type":"string","format":"date-time"}}},"ConsolidationRollupSnapshotResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ConsolidationRollupSnapshot"}}},"ConsolidationRollupSnapshotsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ConsolidationRollupSnapshot"}}}},"CreateConsolidationTranslationAdjustmentInput":{"type":"object","additionalProperties":false,"required":["reportType","constituentSnapshots"],"properties":{"reportType":{"type":"string","enum":["balance_sheet"]},"constituentSnapshots":{"type":"array","minItems":2,"maxItems":250,"description":"Exact manifest: one immutable standalone balance-sheet presentation snapshot for every company in the sealed group version, with no extras.\n","items":{"$ref":"#/components/schemas/ConsolidationRollupManifestItem"}}}},"ConsolidationTranslationAdjustmentContribution":{"type":"object","additionalProperties":false,"required":["companyId","parentCompanyId","ownershipPct","consolidationMethod","snapshotId","snapshotOutputHash","functionalCurrency","presentationCurrency","closingRateId","closingRateType","closingRate","closingRateSourceKind","closingRateSource","closingRateRevision","closingRateRequestedDate","closingRateEffectiveAt","translationDifferenceCents"],"properties":{"companyId":{"type":"string","format":"uuid"},"parentCompanyId":{"type":["string","null"],"format":"uuid"},"ownershipPct":{"type":"number","exclusiveMinimum":0,"maximum":100,"multipleOf":0.0001},"consolidationMethod":{"type":"string","const":"full"},"snapshotId":{"type":"string","format":"uuid"},"snapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"functionalCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"closingRateId":{"type":["string","null"],"format":"uuid"},"closingRateType":{"type":"string","enum":["closing","identity"]},"closingRate":{"type":"string","pattern":"^[0-9]+\\.[0-9]{15}$"},"closingRateSourceKind":{"type":"string","enum":["identity","provider","manual"]},"closingRateSource":{"type":"string","minLength":1},"closingRateRevision":{"type":"integer","minimum":0},"closingRateRequestedDate":{"type":"string","format":"date"},"closingRateEffectiveAt":{"type":"string","format":"date-time"},"translationDifferenceCents":{"type":"integer"}}},"ConsolidationTranslationAdjustmentPayload":{"type":"object","additionalProperties":false,"required":["reportType","stage","gaapStatus","isConsolidatedFinancialStatement","recognition","equityPresentation","calculationMethod","isPostedToLedger","pendingProcedures","hasData","nciAllocationStatus","contributions","cumulativeTranslationAdjustmentCents"],"properties":{"reportType":{"type":"string","const":"balance_sheet"},"stage":{"type":"string","const":"pre_elimination_translation_adjustment_audit"},"gaapStatus":{"type":"string","const":"incomplete"},"isConsolidatedFinancialStatement":{"type":"boolean","const":false},"recognition":{"type":"string","const":"other_comprehensive_income"},"equityPresentation":{"type":"string","const":"separate_component"},"calculationMethod":{"type":"string","const":"sum_of_immutable_standalone_translation_differences"},"isPostedToLedger":{"type":"boolean","const":false},"pendingProcedures":{"type":"array","minItems":5,"maxItems":5,"prefixItems":[{"type":"string","const":"uniform_accounting_policy_adjustments"},{"type":"string","const":"parent_investment_subsidiary_equity_elimination"},{"type":"string","const":"intercompany_eliminations"},{"type":"string","const":"nci_attribution"},{"type":"string","const":"disposal_reclassification"}],"items":false},"hasData":{"type":"boolean"},"nciAllocationStatus":{"type":"string","enum":["pending","not_applicable"],"description":"Pending when a fully consolidated non-root constituent is less than 100 percent owned. This audit includes 100 percent of standalone CTA; NCI allocation is a later procedure.\n"},"contributions":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ConsolidationTranslationAdjustmentContribution"}},"cumulativeTranslationAdjustmentCents":{"type":"integer"}}},"ConsolidationTranslationAdjustmentSnapshot":{"type":"object","additionalProperties":false,"required":["id","groupId","groupVersionId","reportType","periodStart","periodEnd","presentationCurrency","sourceHash","outputHash","fingerprint","payload","constituentSnapshots","createdByUserId","createdAt","sealedAt"],"properties":{"id":{"type":"string","format":"uuid"},"groupId":{"type":"string","format":"uuid"},"groupVersionId":{"type":"string","format":"uuid"},"reportType":{"type":"string","const":"balance_sheet"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"sourceHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"outputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"payload":{"$ref":"#/components/schemas/ConsolidationTranslationAdjustmentPayload"},"constituentSnapshots":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ConsolidationRollupConstituentSnapshot"}},"createdByUserId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"sealedAt":{"type":"string","format":"date-time"}}},"ConsolidationTranslationAdjustmentSnapshotResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ConsolidationTranslationAdjustmentSnapshot"}}},"ConsolidationTranslationAdjustmentSnapshotsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ConsolidationTranslationAdjustmentSnapshot"}}}},"CreatePresentationReportSnapshotInput":{"type":"object","additionalProperties":false,"required":["reportType","glPeriodId"],"properties":{"reportType":{"type":"string","enum":["profit_and_loss","balance_sheet"]},"glPeriodId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid","description":"Required when the company has multiple concrete legal entities."},"supersedesSnapshotId":{"type":"string","format":"uuid"},"restatementReason":{"type":"string","minLength":1,"maxLength":1000}}},"PresentationReportRate":{"type":"object","additionalProperties":false,"required":["id","rateType","rate","sourceKind","source","revision","requestedDate","periodStart","effectiveAt","fetchedAt"],"properties":{"id":{"type":["string","null"],"format":"uuid","description":"Null only for a same-currency identity translation."},"rateType":{"type":"string","enum":["average","closing","historical","identity"]},"rate":{"type":"string","pattern":"^[0-9]{1,15}\\.[0-9]{15}$","example":"1.250000000000000"},"sourceKind":{"type":"string","enum":["identity","provider","manual"]},"source":{"type":"string"},"revision":{"type":"integer","minimum":0},"requestedDate":{"type":"string","format":"date"},"periodStart":{"type":["string","null"],"format":"date"},"effectiveAt":{"type":"string","format":"date-time"},"fetchedAt":{"type":"string","format":"date-time"}}},"PresentationProfitAndLossLine":{"type":"object","additionalProperties":false,"required":["accountId","code","name","reportSection","reportSectionLabel","functionalAmountCents","presentationAmountCents"],"properties":{"accountId":{"type":"string","format":"uuid"},"code":{"type":"string"},"name":{"type":"string"},"reportSection":{"type":"string"},"reportSectionLabel":{"type":"string"},"functionalAmountCents":{"type":"integer"},"presentationAmountCents":{"type":"integer"}}},"PresentationProfitAndLossTotals":{"type":"object","additionalProperties":false,"description":"New snapshots separate Other Income from operating Revenue. The two added totals are absent on historical issued snapshots, which retain their original combined Revenue and hashes.","required":["revenueCents","cogsCents","opexCents","expensesCents","netIncomeCents"],"properties":{"revenueCents":{"type":"integer"},"cogsCents":{"type":"integer"},"opexCents":{"type":"integer"},"expensesCents":{"type":"integer"},"netIncomeCents":{"type":"integer"},"otherIncomeCents":{"type":"integer","description":"Signed non-operating income, included in net income but excluded from Revenue and expenses."},"operatingIncomeCents":{"type":"integer","description":"Revenue minus total expenses; net income equals this amount plus Other Income."}}},"PresentationProfitAndLossPayload":{"type":"object","additionalProperties":false,"required":["hasData","lines","totals"],"properties":{"hasData":{"type":"boolean"},"lines":{"type":"array","items":{"$ref":"#/components/schemas/PresentationProfitAndLossLine"}},"totals":{"type":"object","additionalProperties":false,"required":["functional","presentation","presentationAggregateAtRate","roundingDifferenceCents"],"properties":{"functional":{"$ref":"#/components/schemas/PresentationProfitAndLossTotals"},"presentation":{"$ref":"#/components/schemas/PresentationProfitAndLossTotals"},"presentationAggregateAtRate":{"$ref":"#/components/schemas/PresentationProfitAndLossTotals"},"roundingDifferenceCents":{"$ref":"#/components/schemas/PresentationProfitAndLossTotals"}}}}},"PresentationHistoricalEquityComponent":{"type":"object","additionalProperties":false,"required":["kind","sourceDate","functionalAmountCents","presentationAmountCents","rate"],"properties":{"kind":{"type":"string","const":"historical_equity"},"sourceDate":{"type":"string","format":"date"},"functionalAmountCents":{"type":"integer"},"presentationAmountCents":{"type":"integer"},"rate":{"$ref":"#/components/schemas/PresentationReportRate"}}},"PresentationPeriodAverageEarningsComponent":{"type":"object","additionalProperties":false,"required":["kind","glPeriodId","periodStart","periodEnd","periodClosedAt","functionalAmountCents","presentationAmountCents","rate"],"properties":{"kind":{"type":"string","const":"period_average_earnings"},"glPeriodId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"periodClosedAt":{"type":"string","format":"date-time"},"functionalAmountCents":{"type":"integer"},"presentationAmountCents":{"type":"integer"},"rate":{"$ref":"#/components/schemas/PresentationReportRate"}}},"PresentationBalanceSheetLine":{"type":"object","additionalProperties":false,"required":["sourceKind","accountId","code","name","reportSection","reportSectionLabel","statementClass","functionalAmountCents","presentationAmountCents","translationMethod","components"],"properties":{"sourceKind":{"type":"string","enum":["account","current_earnings"]},"accountId":{"type":["string","null"],"format":"uuid"},"code":{"type":["string","null"]},"name":{"type":"string"},"reportSection":{"type":"string"},"reportSectionLabel":{"type":"string"},"statementClass":{"type":"string","enum":["asset","liability","equity","current_earnings"]},"functionalAmountCents":{"type":"integer"},"presentationAmountCents":{"type":"integer"},"translationMethod":{"type":"string","enum":["closing","historical","average","identity"]},"components":{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/PresentationHistoricalEquityComponent"},{"$ref":"#/components/schemas/PresentationPeriodAverageEarningsComponent"}]}}}},"PresentationBalanceSheetFunctionalTotals":{"type":"object","additionalProperties":false,"required":["assetsCents","liabilitiesCents","equityCents","liabilitiesAndEquityCents","differenceCents"],"properties":{"assetsCents":{"type":"integer"},"liabilitiesCents":{"type":"integer"},"equityCents":{"type":"integer"},"liabilitiesAndEquityCents":{"type":"integer"},"differenceCents":{"type":"integer"}}},"PresentationBalanceSheetPresentationTotals":{"type":"object","additionalProperties":false,"required":["assetsCents","liabilitiesCents","equityBeforeTranslationDifferenceCents","translationDifferenceCents","equityIncludingTranslationDifferenceCents","liabilitiesAndEquityCents","differenceCents"],"properties":{"assetsCents":{"type":"integer"},"liabilitiesCents":{"type":"integer"},"equityBeforeTranslationDifferenceCents":{"type":"integer"},"translationDifferenceCents":{"type":"integer","description":"Report-time balancing residual from applying closing, historical, and period-average rates. It is not posted or labeled as consolidated CTA until the #917 consolidation authority consumes it.\n"},"equityIncludingTranslationDifferenceCents":{"type":"integer"},"liabilitiesAndEquityCents":{"type":"integer"},"differenceCents":{"type":"integer"}}},"PresentationBalanceSheetPayload":{"type":"object","additionalProperties":false,"required":["hasData","lines","totals"],"properties":{"hasData":{"type":"boolean"},"lines":{"type":"array","items":{"$ref":"#/components/schemas/PresentationBalanceSheetLine"}},"totals":{"type":"object","additionalProperties":false,"required":["functional","presentation"],"properties":{"functional":{"$ref":"#/components/schemas/PresentationBalanceSheetFunctionalTotals"},"presentation":{"$ref":"#/components/schemas/PresentationBalanceSheetPresentationTotals"}}}}},"PresentationReportSnapshot":{"type":"object","additionalProperties":false,"required":["id","companyId","entityId","revision","supersedesSnapshotId","restatementReason","restatedByUserId","glPeriodId","reportType","periodStart","periodEnd","periodClosedAt","functionalCurrency","presentationCurrency","rate","sourceHash","outputHash","fingerprint","payload","createdByUserId","createdAt","sealedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"revision":{"type":"integer","minimum":1},"supersedesSnapshotId":{"type":["string","null"],"format":"uuid"},"restatementReason":{"type":["string","null"]},"restatedByUserId":{"type":["string","null"],"format":"uuid"},"glPeriodId":{"type":"string","format":"uuid"},"reportType":{"type":"string","enum":["profit_and_loss","balance_sheet"]},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"periodClosedAt":{"type":"string","format":"date-time"},"functionalCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"rate":{"$ref":"#/components/schemas/PresentationReportRate"},"sourceHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"outputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"payload":{"oneOf":[{"$ref":"#/components/schemas/PresentationProfitAndLossPayload"},{"$ref":"#/components/schemas/PresentationBalanceSheetPayload"}]},"createdByUserId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"sealedAt":{"type":"string","format":"date-time"}}},"PresentationReportSnapshotResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/PresentationReportSnapshot"}}},"PresentationReportSnapshotsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PresentationReportSnapshot"}}}},"CreateReportingTrialBalanceInput":{"type":"object","additionalProperties":false,"required":["glPeriodId"],"properties":{"glPeriodId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid","description":"Concrete same-company legal entity; defaults only to the primary entity."},"supersedesSnapshotId":{"type":"string","format":"uuid"},"restatementReason":{"type":"string","minLength":1,"maxLength":1000}}},"ReportingTrialBalanceRateAuthority":{"type":"object","additionalProperties":false,"required":["id","rateType","rate","sourceKind","source","revision","requestedDate","periodStart","effectiveAt","fetchedAt"],"properties":{"id":{"type":["string","null"],"format":"uuid"},"rateType":{"type":"string","enum":["identity","closing","historical","average"]},"rate":{"type":"string","pattern":"^[0-9]+(\\.[0-9]+)?$"},"sourceKind":{"type":"string","enum":["identity","provider","manual"]},"source":{"type":"string"},"revision":{"type":"integer","minimum":0},"requestedDate":{"type":"string","format":"date"},"periodStart":{"type":["string","null"],"format":"date"},"effectiveAt":{"type":"string","format":"date-time"},"fetchedAt":{"type":"string","format":"date-time"}}},"ReportingTrialBalanceRateComponent":{"type":"object","additionalProperties":false,"required":["rateKey","translationMethod","rate","functionalBalanceCents","presentationBalanceCents","sourceJournalLineIds"],"properties":{"rateKey":{"type":"string","pattern":"^[a-f0-9]{64}$"},"translationMethod":{"type":"string","enum":["closing","historical","average"]},"rate":{"$ref":"#/components/schemas/ReportingTrialBalanceRateAuthority"},"functionalBalanceCents":{"type":"integer"},"presentationBalanceCents":{"type":"integer"},"sourceJournalLineIds":{"type":"array","minItems":1,"uniqueItems":true,"items":{"type":"string","format":"uuid"}}}},"ReportingTrialBalanceAccountLine":{"type":"object","additionalProperties":false,"required":["sourceKind","accountId","code","name","accountType","normalBalance","reportSection","reportSectionLabel","functionalBeginningBalanceCents","functionalPeriodDebitCents","functionalPeriodCreditCents","functionalEndingBalanceCents","presentationEndingBalanceCents","endingDebitCents","endingCreditCents","components"],"properties":{"sourceKind":{"type":"string","const":"account"},"accountId":{"type":"string","format":"uuid"},"code":{"type":"string"},"name":{"type":"string"},"accountType":{"type":"string","enum":["Asset","Liability","Equity","Revenue","Expense"]},"normalBalance":{"type":"string","enum":["debit","credit"]},"reportSection":{"type":"string"},"reportSectionLabel":{"type":"string"},"functionalBeginningBalanceCents":{"type":"integer"},"functionalPeriodDebitCents":{"type":"integer","minimum":0},"functionalPeriodCreditCents":{"type":"integer","minimum":0},"functionalEndingBalanceCents":{"type":"integer"},"presentationEndingBalanceCents":{"type":"integer"},"endingDebitCents":{"type":"integer","minimum":0},"endingCreditCents":{"type":"integer","minimum":0},"components":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/ReportingTrialBalanceRateComponent"}}}},"ReportingTrialBalanceTranslationAdjustmentLine":{"type":"object","additionalProperties":false,"required":["sourceKind","accountId","code","name","accountType","normalBalance","reportSection","reportSectionLabel","functionalBeginningBalanceCents","functionalPeriodDebitCents","functionalPeriodCreditCents","functionalEndingBalanceCents","presentationEndingBalanceCents","endingDebitCents","endingCreditCents","components","isPostedToLedger"],"properties":{"sourceKind":{"type":"string","const":"translation_adjustment"},"accountId":{"type":"null"},"code":{"type":"null"},"name":{"type":"string","const":"Cumulative Translation Adjustment"},"accountType":{"type":"string","const":"Equity"},"normalBalance":{"type":"string","const":"credit"},"reportSection":{"type":"string","const":"equity"},"reportSectionLabel":{"type":"string","const":"Equity"},"functionalBeginningBalanceCents":{"type":"integer","const":0},"functionalPeriodDebitCents":{"type":"integer","const":0},"functionalPeriodCreditCents":{"type":"integer","const":0},"functionalEndingBalanceCents":{"type":"integer","const":0},"presentationEndingBalanceCents":{"type":"integer"},"endingDebitCents":{"type":"integer","minimum":0},"endingCreditCents":{"type":"integer","minimum":0},"components":{"type":"array","maxItems":0},"isPostedToLedger":{"type":"boolean","const":false}}},"ReportingTrialBalanceTotals":{"type":"object","additionalProperties":false,"required":["debitCents","creditCents","differenceCents"],"properties":{"debitCents":{"type":"integer","minimum":0},"creditCents":{"type":"integer","minimum":0},"differenceCents":{"type":"integer"}}},"ReportingTrialBalancePayload":{"type":"object","additionalProperties":false,"required":["basis","gaapStatus","isConsolidatedFinancialStatement","isPostedToLedger","hasData","functionalCurrency","presentationCurrency","coaMappingRevisionHash","rateSetRevisionHash","cumulativeTranslationAdjustmentCents","lines","totals"],"properties":{"basis":{"type":"string","const":"adjusted_pre_closing"},"gaapStatus":{"type":"string","const":"control_schedule"},"isConsolidatedFinancialStatement":{"type":"boolean","const":false},"isPostedToLedger":{"type":"boolean","const":false},"hasData":{"type":"boolean"},"functionalCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"coaMappingRevisionHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"rateSetRevisionHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"cumulativeTranslationAdjustmentCents":{"type":"integer"},"lines":{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/ReportingTrialBalanceAccountLine"},{"$ref":"#/components/schemas/ReportingTrialBalanceTranslationAdjustmentLine"}]}},"totals":{"type":"object","additionalProperties":false,"required":["functional","presentationBeforeTranslationAdjustment","presentation"],"properties":{"functional":{"$ref":"#/components/schemas/ReportingTrialBalanceTotals"},"presentationBeforeTranslationAdjustment":{"$ref":"#/components/schemas/ReportingTrialBalanceTotals"},"presentation":{"$ref":"#/components/schemas/ReportingTrialBalanceTotals"}}}}},"ReportingTrialBalanceSourceAuthority":{"type":"object","additionalProperties":false,"required":["journalEntryId","journalLineId","accountId","entryDate","functionalDebitCents","functionalCreditCents","translationMethod","rateKey","rate"],"properties":{"journalEntryId":{"type":"string","format":"uuid"},"journalLineId":{"type":"string","format":"uuid"},"accountId":{"type":"string","format":"uuid"},"entryDate":{"type":"string","format":"date"},"functionalDebitCents":{"type":"integer","minimum":0},"functionalCreditCents":{"type":"integer","minimum":0},"translationMethod":{"type":"string","enum":["closing","historical","average"]},"rateKey":{"type":"string","pattern":"^[a-f0-9]{64}$"},"rate":{"$ref":"#/components/schemas/ReportingTrialBalanceRateAuthority"}}},"ReportingTrialBalanceSnapshot":{"type":"object","additionalProperties":false,"required":["id","companyId","entityId","revision","supersedesSnapshotId","restatementReason","restatedByUserId","glPeriodId","periodStart","periodEnd","periodClosedAt","functionalCurrency","presentationCurrency","coaMappingRevisionHash","rateSetRevisionHash","sourceHash","outputHash","fingerprint","payload","sourceAuthorities","createdByUserId","createdAt","sealedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"revision":{"type":"integer","minimum":1},"supersedesSnapshotId":{"type":["string","null"],"format":"uuid"},"restatementReason":{"type":["string","null"]},"restatedByUserId":{"type":["string","null"],"format":"uuid"},"glPeriodId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"periodClosedAt":{"type":"string","format":"date-time"},"functionalCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"coaMappingRevisionHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"rateSetRevisionHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"sourceHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"outputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"payload":{"$ref":"#/components/schemas/ReportingTrialBalancePayload"},"sourceAuthorities":{"type":"array","items":{"$ref":"#/components/schemas/ReportingTrialBalanceSourceAuthority"}},"createdByUserId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"sealedAt":{"type":"string","format":"date-time"}}},"ReportingTrialBalanceResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ReportingTrialBalanceSnapshot"}}},"ReportingTrialBalancesResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ReportingTrialBalanceSnapshot"}}}},"ReportingScope":{"type":"object","additionalProperties":false,"description":"A read-only consolidated reporting identity within one company. It is not a legal entity and cannot own postings, integrations, schedules, AR/AP items, Forecast state, or any other accounting fact.\n","required":["id","companyId","kind","label","rootEntityId","createdByUserId","createdAt","retiredAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["consolidated"]},"label":{"type":"string","minLength":1,"maxLength":200},"rootEntityId":{"type":"string","format":"uuid","description":"The company's one persisted primary legal entity."},"createdByUserId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"retiredAt":{"type":["string","null"],"format":"date-time"}}},"CreateReportingScopeInput":{"type":"object","additionalProperties":false,"required":["label"],"properties":{"label":{"type":"string","minLength":1,"maxLength":200}}},"ReportingScopeVersionEntity":{"type":"object","additionalProperties":false,"required":["entityId","parentEntityId","ownershipPct","consolidationMethod"],"properties":{"entityId":{"type":"string","format":"uuid"},"parentEntityId":{"type":["string","null"],"format":"uuid"},"ownershipPct":{"type":"number","exclusiveMinimum":0,"maximum":100,"multipleOf":0.000001},"consolidationMethod":{"type":"string","enum":["full","equity","proportional"]}}},"CreateReportingScopeVersionInput":{"type":"object","additionalProperties":false,"required":["effectiveFrom","presentationCurrency","entities"],"properties":{"effectiveFrom":{"type":"string","format":"date"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"entities":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ReportingScopeVersionEntity"}}}},"ReportingScopeVersion":{"type":"object","additionalProperties":false,"required":["id","reportingScopeId","companyId","effectiveFrom","effectiveTo","presentationCurrency","createdByUserId","createdAt","sealedAt","entities"],"properties":{"id":{"type":"string","format":"uuid"},"reportingScopeId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"effectiveFrom":{"type":"string","format":"date"},"effectiveTo":{"type":["string","null"],"format":"date"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"createdByUserId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"sealedAt":{"type":"string","format":"date-time"},"entities":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ReportingScopeVersionEntity"}}}},"ReportingScopeResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ReportingScope"}}},"ReportingScopesResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ReportingScope"}}}},"ReportingScopeVersionResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ReportingScopeVersion"}}},"ReportingScopeVersionsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ReportingScopeVersion"}}}},"ReportingScopeWorksheetUnavailableReason":{"type":["string","null"],"description":"Honest-unavailable reason. no_consolidation_scope = the scope does not exist for this company; no_sealed_version = no sealed hierarchy version; no_sealed_worksheet = the version (or requested period) has no sealed rollup authority. Null when available is true.\n","enum":["no_consolidation_scope","no_sealed_version","no_sealed_worksheet",null]},"ReportingScopeWorksheetStageAvailability":{"type":"object","additionalProperties":false,"required":["trialBalanceRollup","profitAndLoss","balanceSheet","translationAdjustment","eliminations","nci"],"properties":{"trialBalanceRollup":{"type":"boolean"},"profitAndLoss":{"type":"boolean"},"balanceSheet":{"type":"boolean"},"translationAdjustment":{"type":"boolean"},"eliminations":{"type":"boolean"},"nci":{"type":"boolean"}}},"ReportingScopeWorksheetPeriodSummary":{"type":"object","additionalProperties":false,"required":["reportingScopeVersionId","periodStart","periodEnd","presentationCurrency","glPeriodId","stages"],"properties":{"reportingScopeVersionId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"glPeriodId":{"type":["string","null"],"format":"uuid"},"stages":{"$ref":"#/components/schemas/ReportingScopeWorksheetStageAvailability"}}},"ReportingScopeWorksheetPeriods":{"type":"object","additionalProperties":false,"required":["available","reason","scope","periods"],"properties":{"available":{"type":"boolean"},"reason":{"$ref":"#/components/schemas/ReportingScopeWorksheetUnavailableReason"},"scope":{"oneOf":[{"$ref":"#/components/schemas/ReportingScope"},{"type":"null"}]},"periods":{"type":"array","items":{"$ref":"#/components/schemas/ReportingScopeWorksheetPeriodSummary"}}}},"ReportingScopeWorksheetPeriodsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ReportingScopeWorksheetPeriods"}}},"ReportingScopeWorksheetPeriod":{"type":"object","additionalProperties":false,"required":["periodStart","periodEnd","presentationCurrency","glPeriodId"],"properties":{"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"glPeriodId":{"type":["string","null"],"format":"uuid"}}},"ReportingScopeWorksheet":{"type":"object","additionalProperties":false,"description":"Sealed consolidation worksheet for one reporting scope, hierarchy version, and period. Every non-null stage is a curated projection of a persisted sealed authority — only the figures the read-only worksheet renders. The persisted source/output/fingerprint hashes, constituent snapshot manifests, elimination source projections, and NCI source manifests never cross to the customer payload. A stage that has not been sealed is null. When available is false the reason is populated and the stage fields are null.\n","required":["available","reason","scope","version","period","trialBalanceRollup","profitAndLoss","balanceSheet","translationAdjustment","eliminations","nci"],"properties":{"available":{"type":"boolean"},"reason":{"$ref":"#/components/schemas/ReportingScopeWorksheetUnavailableReason"},"scope":{"oneOf":[{"$ref":"#/components/schemas/ReportingScope"},{"type":"null"}]},"version":{"oneOf":[{"$ref":"#/components/schemas/ReportingScopeVersion"},{"type":"null"}]},"period":{"oneOf":[{"$ref":"#/components/schemas/ReportingScopeWorksheetPeriod"},{"type":"null"}]},"trialBalanceRollup":{"oneOf":[{"$ref":"#/components/schemas/WorksheetTrialBalanceRollup"},{"type":"null"}]},"profitAndLoss":{"oneOf":[{"$ref":"#/components/schemas/WorksheetRollup"},{"type":"null"}]},"balanceSheet":{"oneOf":[{"$ref":"#/components/schemas/WorksheetRollup"},{"type":"null"}]},"translationAdjustment":{"oneOf":[{"$ref":"#/components/schemas/WorksheetTranslationAdjustment"},{"type":"null"}]},"eliminations":{"oneOf":[{"$ref":"#/components/schemas/WorksheetEliminations"},{"type":"null"}]},"nci":{"oneOf":[{"$ref":"#/components/schemas/WorksheetNci"},{"type":"null"}]}}},"WorksheetControlTotals":{"type":"object","additionalProperties":false,"required":["debitCents","creditCents","differenceCents"],"properties":{"debitCents":{"type":"integer"},"creditCents":{"type":"integer"},"differenceCents":{"type":"integer"}}},"WorksheetTrialBalanceRollup":{"type":"object","additionalProperties":false,"description":"Curated pre-elimination reporting-scope trial-balance rollup: only the per-entity contributions and the pre-elimination rollup figures the worksheet renders. Per-line journal-line ids, rate keys, constituent snapshot ids, and the source/output/fingerprint hashes are dropped.\n","required":["periodEnd","payload"],"properties":{"periodEnd":{"type":"string","format":"date"},"payload":{"type":"object","additionalProperties":false,"required":["lines","totals"],"properties":{"lines":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["sourceKind","code","name","reportSection","reportSectionLabel","presentationEndingBalanceCents","contributions"],"properties":{"sourceKind":{"type":"string","enum":["account","translation_adjustment"]},"code":{"type":["string","null"]},"name":{"type":"string"},"reportSection":{"type":"string"},"reportSectionLabel":{"type":"string"},"presentationEndingBalanceCents":{"type":"integer"},"contributions":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["entityId","presentationEndingBalanceCents"],"properties":{"entityId":{"type":"string","format":"uuid"},"presentationEndingBalanceCents":{"type":"integer"}}}}}}},"totals":{"$ref":"#/components/schemas/WorksheetControlTotals"}}}}},"WorksheetRollup":{"type":"object","additionalProperties":false,"description":"Curated pre-elimination management P&L or balance-sheet rollup: per-entity contributions, the pre-elimination line total, constituent net totals, and the report totals. Constituent snapshot ids/hashes and per-line source account identifiers are dropped.\n","required":["reportType","payload"],"properties":{"reportType":{"type":"string","enum":["profit_and_loss","balance_sheet"]},"payload":{"type":"object","additionalProperties":false,"required":["constituents","lines","totals"],"properties":{"constituents":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["entityId","totals"],"properties":{"entityId":{"type":"string","format":"uuid"},"totals":{"type":"object","additionalProperties":{"type":"integer"}}}}},"lines":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["code","name","reportSection","reportSectionLabel","presentationAmountCents","contributions"],"properties":{"code":{"type":["string","null"]},"name":{"type":"string"},"reportSection":{"type":"string"},"reportSectionLabel":{"type":"string"},"presentationAmountCents":{"type":"integer"},"contributions":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["entityId","presentationAmountCents"],"properties":{"entityId":{"type":"string","format":"uuid"},"presentationAmountCents":{"type":"integer"}}}}}}},"totals":{"type":"object","additionalProperties":{"type":"integer"}}}}}},"WorksheetTranslationAdjustment":{"type":"object","additionalProperties":false,"description":"Curated cumulative-translation-adjustment authority: per-entity translation differences (functional currency, closing rate, difference) and the cumulative CTA. Rate ids/revisions, snapshot ids, and hashes are dropped.\n","required":["payload"],"properties":{"payload":{"type":"object","additionalProperties":false,"required":["contributions","cumulativeTranslationAdjustmentCents"],"properties":{"contributions":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["entityId","functionalCurrency","closingRate","translationDifferenceCents"],"properties":{"entityId":{"type":"string","format":"uuid"},"functionalCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"closingRate":{"type":"string"},"translationDifferenceCents":{"type":"integer"}}}},"cumulativeTranslationAdjustmentCents":{"type":"integer"}}}}},"WorksheetEliminations":{"oneOf":[{"$ref":"#/components/schemas/WorksheetActiveEliminations"},{"$ref":"#/components/schemas/WorksheetReversedEliminations"}],"discriminator":{"propertyName":"status","mapping":{"active":"#/components/schemas/WorksheetActiveEliminations","reversed":"#/components/schemas/WorksheetReversedEliminations"}}},"WorksheetActiveEliminations":{"type":"object","additionalProperties":false,"description":"The applied intercompany elimination with the sealed per-account deltas.","required":["status","direction","matchIds","payload"],"properties":{"status":{"type":"string","const":"active"},"direction":{"type":"string","const":"eliminate"},"matchIds":{"type":"array","items":{"type":"string","format":"uuid"}},"payload":{"type":"object","additionalProperties":false,"required":["lines","totals"],"properties":{"lines":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["code","name","eliminationDeltaCents"],"properties":{"code":{"type":["string","null"]},"name":{"type":"string"},"eliminationDeltaCents":{"type":"integer"}}}},"totals":{"type":"object","additionalProperties":false,"required":["debitCents","creditCents"],"properties":{"debitCents":{"type":"integer"},"creditCents":{"type":"integer"}}}}}}},"WorksheetReversedEliminations":{"type":"object","additionalProperties":false,"description":"A terminal reversed intercompany-elimination authority. The most recently sealed snapshot for the period is a reversal, so no elimination is applied and no live deltas are returned; the worksheet renders \"eliminations reversed for this period\".\n","required":["status","direction","matchIds"],"properties":{"status":{"type":"string","const":"reversed"},"direction":{"type":"string","const":"reverse"},"matchIds":{"type":"array","items":{"type":"string","format":"uuid"}}}},"WorksheetNci":{"type":"object","additionalProperties":false,"description":"Curated non-controlling-interest attribution: the sealed per-subsidiary debit/credit control totals and NCI share, plus the revision. The source manifest (journal-line ids, snapshot ids, rate keys) and per-adjustment allocation/line detail are dropped.\n","required":["revision","adjustments"],"properties":{"revision":{"type":"integer"},"adjustments":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["subsidiaryEntityId","nonControllingOwnershipPercentage","currency","totalDebit","totalCredit"],"properties":{"subsidiaryEntityId":{"type":"string","format":"uuid"},"nonControllingOwnershipPercentage":{"type":"string"},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"totalDebit":{"type":"string"},"totalCredit":{"type":"string"}}}}}},"ReportingScopeWorksheetResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ReportingScopeWorksheet"}}},"ModelAIntercompanyClassification":{"type":"string","enum":["revenue_expense","receivable_payable","loan_principal","loan_interest","fee"]},"ModelAIntercompanyRole":{"type":"string","enum":["seller_revenue","buyer_expense","receivable","payable","lender_due_from","borrower_due_to","lender_interest_income","borrower_interest_expense","fee_revenue","fee_expense"]},"ModelAIntercompanyDirection":{"type":"string","enum":["standard","reversal"]},"ModelAIntercompanyMatchShape":{"type":"string","enum":["exact","partial","many_to_one","many_to_many"]},"CreateModelAIntercompanyDesignationInput":{"type":"object","additionalProperties":false,"required":["entityId","counterpartyEntityId","journalEntryId","journalLineId","classification","role","direction","reason"],"properties":{"entityId":{"type":"string","format":"uuid"},"counterpartyEntityId":{"type":"string","format":"uuid"},"journalEntryId":{"type":"string","format":"uuid"},"journalLineId":{"type":"string","format":"uuid"},"classification":{"$ref":"#/components/schemas/ModelAIntercompanyClassification"},"role":{"$ref":"#/components/schemas/ModelAIntercompanyRole"},"direction":{"$ref":"#/components/schemas/ModelAIntercompanyDirection"},"reason":{"type":"string","minLength":1,"maxLength":500},"supersedesDesignationId":{"type":["string","null"],"format":"uuid"}}},"ModelAIntercompanyDesignation":{"type":"object","additionalProperties":false,"required":["id","companyId","reportingScopeId","reportingScopeVersionId","entityId","counterpartyEntityId","journalEntryId","journalLineId","glAccountId","classification","role","direction","sourceEntryDate","sourceType","sourceId","transactionCurrency","transactionDebitCents","transactionCreditCents","functionalCurrency","functionalDebitCents","functionalCreditCents","fxRate","fxRateId","fxRateRevision","currencyAuthorityVersion","sourceFingerprint","fingerprint","designatedByUserId","reason","supersedesDesignationId","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"reportingScopeId":{"type":"string","format":"uuid"},"reportingScopeVersionId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"counterpartyEntityId":{"type":"string","format":"uuid"},"journalEntryId":{"type":"string","format":"uuid"},"journalLineId":{"type":"string","format":"uuid"},"glAccountId":{"type":"string","format":"uuid"},"classification":{"$ref":"#/components/schemas/ModelAIntercompanyClassification"},"role":{"$ref":"#/components/schemas/ModelAIntercompanyRole"},"direction":{"$ref":"#/components/schemas/ModelAIntercompanyDirection"},"sourceEntryDate":{"type":"string","format":"date"},"sourceType":{"type":"string"},"sourceId":{"type":["string","null"]},"transactionCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"transactionDebitCents":{"type":"integer","format":"int64","minimum":0},"transactionCreditCents":{"type":"integer","format":"int64","minimum":0},"functionalCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"functionalDebitCents":{"type":"integer","format":"int64","minimum":0},"functionalCreditCents":{"type":"integer","format":"int64","minimum":0},"fxRate":{"type":"string","pattern":"^[0-9]+\\.[0-9]{15}$"},"fxRateId":{"type":["string","null"],"format":"uuid"},"fxRateRevision":{"type":"integer","minimum":0},"currencyAuthorityVersion":{"type":"integer","enum":[1]},"sourceFingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"designatedByUserId":{"type":"string","format":"uuid"},"reason":{"type":"string","minLength":1,"maxLength":500},"supersedesDesignationId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"}}},"ModelAIntercompanyDesignationResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ModelAIntercompanyDesignation"}}},"ModelAIntercompanyDesignationsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelAIntercompanyDesignation"}}}},"ModelAIntercompanyAllocation":{"type":"object","additionalProperties":false,"required":["designationId","transactionAmountCents"],"properties":{"designationId":{"type":"string","format":"uuid"},"transactionAmountCents":{"type":"integer","format":"int64","minimum":1}}},"ModelAIntercompanyProposal":{"type":"object","additionalProperties":false,"required":["proposalKey","companyId","reportingScopeId","reportingScopeVersionId","classification","direction","transactionCurrency","periodStart","periodEnd","entityIds","matchShape","timingDifference","matchedTransactionAmountCents","allocations"],"properties":{"proposalKey":{"type":"string","pattern":"^[a-f0-9]{64}$"},"companyId":{"type":"string","format":"uuid"},"reportingScopeId":{"type":"string","format":"uuid"},"reportingScopeVersionId":{"type":"string","format":"uuid"},"classification":{"$ref":"#/components/schemas/ModelAIntercompanyClassification"},"direction":{"$ref":"#/components/schemas/ModelAIntercompanyDirection"},"transactionCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"entityIds":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"string","format":"uuid"}},"matchShape":{"$ref":"#/components/schemas/ModelAIntercompanyMatchShape"},"timingDifference":{"type":"boolean"},"matchedTransactionAmountCents":{"type":"integer","format":"int64","minimum":1},"allocations":{"type":"array","minItems":2,"maxItems":500,"items":{"$ref":"#/components/schemas/ModelAIntercompanyAllocation"}}}},"ModelAIntercompanyException":{"type":"object","additionalProperties":false,"required":["designationId","reason","remainingTransactionAmountCents"],"properties":{"designationId":{"type":"string","format":"uuid"},"reason":{"type":"string","enum":["missing_reciprocal","amount_difference","currency_difference","stale_open","period_cutoff"]},"remainingTransactionAmountCents":{"type":"integer","format":"int64","minimum":1}}},"ModelAIntercompanyExceptionAuthority":{"allOf":[{"$ref":"#/components/schemas/ModelAIntercompanyException"},{"type":"object","required":["designation"],"properties":{"designation":{"$ref":"#/components/schemas/ModelAIntercompanyDesignation"}}}]},"ModelAIntercompanyProposalResultResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":false,"required":["proposals","exceptions"],"properties":{"proposals":{"type":"array","items":{"$ref":"#/components/schemas/ModelAIntercompanyProposal"}},"exceptions":{"type":"array","items":{"$ref":"#/components/schemas/ModelAIntercompanyException"}}}}}},"ModelAIntercompanyExceptionsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelAIntercompanyExceptionAuthority"}}}},"CreateModelAIntercompanyMatchInput":{"type":"object","additionalProperties":false,"required":["glPeriodId","proposalKey","allocations","reason"],"properties":{"glPeriodId":{"type":"string","format":"uuid"},"proposalKey":{"type":"string","pattern":"^[a-f0-9]{64}$"},"allocations":{"type":"array","minItems":2,"maxItems":500,"items":{"$ref":"#/components/schemas/ModelAIntercompanyAllocation"}},"reason":{"type":"string","minLength":1,"maxLength":500}}},"ModelAIntercompanyMatchAllocationAuthority":{"type":"object","additionalProperties":false,"required":["designationId","transactionAmountCents","designation"],"properties":{"designationId":{"type":"string","format":"uuid"},"transactionAmountCents":{"type":"integer","format":"int64","minimum":1},"designation":{"$ref":"#/components/schemas/ModelAIntercompanyDesignation"}}},"ModelAIntercompanyMatch":{"type":"object","additionalProperties":false,"required":["id","companyId","reportingScopeId","reportingScopeVersionId","glPeriodId","proposalKey","periodStart","periodEnd","classification","direction","transactionCurrency","entityIds","matchShape","timingDifference","transactionAmountCents","allocations","sourceHash","fingerprint","createdByUserId","reason","createdAt","sealedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"reportingScopeId":{"type":"string","format":"uuid"},"reportingScopeVersionId":{"type":"string","format":"uuid"},"glPeriodId":{"type":"string","format":"uuid"},"proposalKey":{"type":"string","pattern":"^[a-f0-9]{64}$"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"classification":{"$ref":"#/components/schemas/ModelAIntercompanyClassification"},"direction":{"$ref":"#/components/schemas/ModelAIntercompanyDirection"},"transactionCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"entityIds":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"string","format":"uuid"}},"matchShape":{"$ref":"#/components/schemas/ModelAIntercompanyMatchShape"},"timingDifference":{"type":"boolean"},"transactionAmountCents":{"type":"integer","format":"int64","minimum":1},"allocations":{"type":"array","minItems":2,"maxItems":500,"items":{"$ref":"#/components/schemas/ModelAIntercompanyMatchAllocationAuthority"}},"sourceHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"createdByUserId":{"type":"string","format":"uuid"},"reason":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"sealedAt":{"type":"string","format":"date-time"}}},"ModelAIntercompanyMatchResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ModelAIntercompanyMatch"}}},"ModelAIntercompanyMatchesResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelAIntercompanyMatch"}}}},"CreateModelAIntercompanyEliminationInput":{"type":"object","additionalProperties":false,"required":["baseSnapshotId","matchIds","reason"],"properties":{"baseSnapshotId":{"type":"string","format":"uuid"},"matchIds":{"type":"array","minItems":0,"maxItems":1000,"uniqueItems":true,"items":{"type":"string","format":"uuid"}},"reason":{"type":"string","minLength":1,"maxLength":500}}},"ReverseModelAIntercompanyEliminationInput":{"type":"object","additionalProperties":false,"required":["reason"],"properties":{"reason":{"type":"string","minLength":1,"maxLength":500}}},"ModelAIntercompanyElimination":{"type":"object","additionalProperties":false,"required":["id","companyId","reportingScopeId","reportingScopeVersionId","glPeriodId","periodStart","periodEnd","presentationCurrency","baseSnapshotId","baseSnapshotOutputHash","direction","reversalOfFingerprint","reversalOfSnapshotId","matchIds","sourceHash","outputHash","fingerprint","adjustments","sourceProjections","payload","createdByUserId","reason","createdAt","sealedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"reportingScopeId":{"type":"string","format":"uuid"},"reportingScopeVersionId":{"type":"string","format":"uuid"},"glPeriodId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"baseSnapshotId":{"type":"string","format":"uuid"},"baseSnapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"direction":{"type":"string","enum":["eliminate","reverse"]},"reversalOfFingerprint":{"type":["string","null"],"pattern":"^[a-f0-9]{64}$"},"reversalOfSnapshotId":{"type":["string","null"],"format":"uuid"},"matchIds":{"type":"array","minItems":0,"uniqueItems":true,"items":{"type":"string","format":"uuid"}},"sourceHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"outputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"adjustments":{"type":"array","minItems":0,"description":"Balanced virtual adjustments, one per exact match, with stable idempotency and exact reversal keys.\n","items":{"type":"object","additionalProperties":true}},"sourceProjections":{"type":"array","minItems":0,"description":"Exact designation, journal-line, standalone-snapshot, posting-FX, and presentation-rate projections used by the virtual adjustment.\n","items":{"type":"object","additionalProperties":true}},"payload":{"type":"object","description":"Post-elimination or exactly restored reporting-scope trial balance. The payload remains unposted and retains pending consolidation procedures that have not yet received separate authority.\n","additionalProperties":true},"createdByUserId":{"type":"string","format":"uuid"},"reason":{"type":"string","minLength":1,"maxLength":500},"createdAt":{"type":"string","format":"date-time"},"sealedAt":{"type":"string","format":"date-time"}}},"ModelAIntercompanyEliminationResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ModelAIntercompanyElimination"}}},"ModelAIntercompanyEliminationsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelAIntercompanyElimination"}}}},"CreateModelANciLifecycleEventInput":{"type":"object","additionalProperties":false,"required":["kind","effectiveDate","glPeriodId","subsidiaryEntityId","sourceId","reason"],"properties":{"kind":{"type":"string","enum":["acquisition","distribution","ownership_change_without_loss_of_control","loss_of_control"]},"effectiveDate":{"type":"string","format":"date"},"glPeriodId":{"type":"string","format":"uuid"},"subsidiaryEntityId":{"type":"string","format":"uuid"},"sourceId":{"type":"string","format":"uuid","description":"Reviewed document for valuation/ownership events or posted journal for distributions."},"reason":{"type":"string","minLength":1,"maxLength":1000}}},"ModelANciLifecycleEventRecord":{"type":"object","additionalProperties":false,"required":["companyId","reportingScopeId","reportingScopeVersionId","glPeriodId","subsidiaryEntityId","event","payload","fingerprint","createdByUserId","reason","createdAt","sealedAt"],"properties":{"companyId":{"type":"string","format":"uuid"},"reportingScopeId":{"type":"string","format":"uuid"},"reportingScopeVersionId":{"type":"string","format":"uuid"},"glPeriodId":{"type":"string","format":"uuid"},"subsidiaryEntityId":{"type":"string","format":"uuid"},"event":{"type":"object","additionalProperties":true,"required":["id","kind","effectiveDate","source"],"properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["acquisition","distribution","ownership_change_without_loss_of_control","loss_of_control"]},"effectiveDate":{"type":"string","format":"date"},"source":{"type":"object","additionalProperties":false,"required":["sourceType","sourceId","sourceHash"],"properties":{"sourceType":{"type":"string","enum":["journal_entry","document"]},"sourceId":{"type":"string","format":"uuid"},"sourceHash":{"type":"string","pattern":"^[a-f0-9]{64}$"}}}}},"payload":{"type":"object","additionalProperties":true},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"createdByUserId":{"type":"string","format":"uuid"},"reason":{"type":"string","minLength":1,"maxLength":1000},"createdAt":{"type":"string","format":"date-time"},"sealedAt":{"type":"string","format":"date-time"}}},"ModelANciLifecycleEventResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ModelANciLifecycleEventRecord"}}},"ModelANciLifecycleEventsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelANciLifecycleEventRecord"}}}},"CreateModelANciRollforwardInput":{"type":"object","additionalProperties":false,"required":["glPeriodId","subsidiaryEntityId","reason"],"properties":{"glPeriodId":{"type":"string","format":"uuid"},"subsidiaryEntityId":{"type":"string","format":"uuid"},"supersedesSnapshotId":{"type":"string","format":"uuid"},"restatementReason":{"type":"string","minLength":1,"maxLength":1000},"reason":{"type":"string","minLength":1,"maxLength":1000}}},"ModelANciRollforward":{"type":"object","additionalProperties":false,"required":["id","companyId","reportingScopeId","reportingScopeVersionId","glPeriodId","periodStart","periodEnd","presentationCurrency","nciSnapshotId","nciSnapshotOutputHash","subsidiaryEntityId","openingRollforwardId","openingRollforwardOutputHash","openingNciCents","sourceNciCents","profitOrLossCents","otherComprehensiveIncomeCents","openingNciCtaCents","sourceNciCtaCents","endingNciCtaCents","ctaMovementCents","ctaReattributionToNciCents","acquisitionCents","distributionsCents","ownershipChangeCents","parentEquityTransactionCents","disposalDerecognitionCents","nciCtaDerecognizedCents","parentCtaReclassifiedToProfitOrLossCents","disposalGainLossBeforeCtaCents","disposalGainLossAfterCtaCents","endingNciCents","reconciliationDifferenceCents","eventIds","sourceHash","outputHash","revision","supersedesSnapshotId","restatementReason","fingerprint","payload","createdByUserId","reason","createdAt","sealedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"reportingScopeId":{"type":"string","format":"uuid"},"reportingScopeVersionId":{"type":"string","format":"uuid"},"glPeriodId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"nciSnapshotId":{"type":"string","format":"uuid"},"nciSnapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"subsidiaryEntityId":{"type":"string","format":"uuid"},"openingRollforwardId":{"type":["string","null"],"format":"uuid"},"openingRollforwardOutputHash":{"type":["string","null"],"pattern":"^[a-f0-9]{64}$"},"openingNciCents":{"type":"integer","format":"int64"},"sourceNciCents":{"type":"integer","format":"int64"},"profitOrLossCents":{"type":"integer","format":"int64"},"otherComprehensiveIncomeCents":{"type":"integer","format":"int64"},"openingNciCtaCents":{"type":"integer","format":"int64"},"sourceNciCtaCents":{"type":"integer","format":"int64"},"endingNciCtaCents":{"type":"integer","format":"int64"},"ctaMovementCents":{"type":"integer","format":"int64"},"ctaReattributionToNciCents":{"type":"integer","format":"int64"},"acquisitionCents":{"type":"integer","format":"int64"},"distributionsCents":{"type":"integer","format":"int64"},"ownershipChangeCents":{"type":"integer","format":"int64"},"parentEquityTransactionCents":{"type":"integer","format":"int64"},"disposalDerecognitionCents":{"type":"integer","format":"int64"},"nciCtaDerecognizedCents":{"type":"integer","format":"int64"},"parentCtaReclassifiedToProfitOrLossCents":{"type":"integer","format":"int64"},"disposalGainLossBeforeCtaCents":{"type":"integer","format":"int64"},"disposalGainLossAfterCtaCents":{"type":"integer","format":"int64"},"endingNciCents":{"type":"integer","format":"int64"},"reconciliationDifferenceCents":{"type":"integer","enum":[0]},"eventIds":{"type":"array","uniqueItems":true,"items":{"type":"string","format":"uuid"}},"sourceHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"outputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"revision":{"type":"integer","minimum":1},"supersedesSnapshotId":{"type":["string","null"],"format":"uuid"},"restatementReason":{"type":["string","null"],"maxLength":1000},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"payload":{"type":"object","additionalProperties":true},"createdByUserId":{"type":"string","format":"uuid"},"reason":{"type":"string","minLength":1,"maxLength":1000},"createdAt":{"type":"string","format":"date-time"},"sealedAt":{"type":"string","format":"date-time"}}},"ModelANciRollforwardResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ModelANciRollforward"}}},"ModelANciRollforwardsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelANciRollforward"}}}},"ModelANciSourcePolicy":{"type":"object","additionalProperties":false,"required":["sourceKind","sourceAccountId","component","parentAttributionAccountId","nonControllingInterestAccountId"],"properties":{"sourceKind":{"type":"string","enum":["account","translation_adjustment"]},"sourceAccountId":{"type":["string","null"],"format":"uuid","description":"Null only for a translation-adjustment CTA source."},"component":{"type":"string","enum":["profit_or_loss","other_comprehensive_income","cta","net_assets"]},"parentAttributionAccountId":{"type":"string","format":"uuid"},"nonControllingInterestAccountId":{"type":"string","format":"uuid"}}},"ModelANciSubsidiaryPolicy":{"type":"object","additionalProperties":false,"required":["subsidiaryEntityId","sources"],"properties":{"subsidiaryEntityId":{"type":"string","format":"uuid"},"sources":{"type":"array","minItems":0,"maxItems":1000,"items":{"$ref":"#/components/schemas/ModelANciSourcePolicy"}}}},"CreateModelANciSnapshotInput":{"type":"object","additionalProperties":false,"required":["eliminationSnapshotId","subsidiaryPolicies","reason"],"properties":{"eliminationSnapshotId":{"type":"string","format":"uuid"},"subsidiaryPolicies":{"type":"array","minItems":0,"maxItems":250,"uniqueItems":true,"items":{"$ref":"#/components/schemas/ModelANciSubsidiaryPolicy"}},"supersedesSnapshotId":{"type":"string","format":"uuid"},"restatementReason":{"type":"string","minLength":1,"maxLength":1000},"reason":{"type":"string","minLength":1,"maxLength":500}}},"ModelANciSourceManifestEntry":{"type":"object","additionalProperties":false,"required":["sourceKind","sourceAccountId","component","parentAttributionAccountId","nonControllingInterestAccountId","subsidiaryEntityId","sourceLineId","sourceSnapshotId","sourceSnapshotOutputHash","signedPresentationCents","sourceJournalLineIds","rateKeys","eliminationAuthorityKeys"],"properties":{"sourceKind":{"type":"string","enum":["account","translation_adjustment"]},"sourceAccountId":{"type":["string","null"],"format":"uuid"},"component":{"type":"string","enum":["profit_or_loss","other_comprehensive_income","cta","net_assets"]},"parentAttributionAccountId":{"type":"string","format":"uuid"},"nonControllingInterestAccountId":{"type":"string","format":"uuid"},"subsidiaryEntityId":{"type":"string","format":"uuid"},"sourceLineId":{"type":"string","minLength":1},"sourceSnapshotId":{"type":"string","format":"uuid"},"sourceSnapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"signedPresentationCents":{"type":"integer","format":"int64"},"sourceJournalLineIds":{"type":"array","uniqueItems":true,"items":{"type":"string"}},"rateKeys":{"type":"array","uniqueItems":true,"items":{"type":"string"}},"eliminationAuthorityKeys":{"type":"array","uniqueItems":true,"items":{"type":"string"}}}},"ModelANciSnapshot":{"type":"object","additionalProperties":false,"required":["id","companyId","reportingScopeId","reportingScopeVersionId","glPeriodId","periodStart","periodEnd","presentationCurrency","eliminationSnapshotId","eliminationSnapshotOutputHash","subsidiaryEntityIds","sourceHash","outputHash","fingerprint","sourceManifest","adjustments","payload","revision","supersedesSnapshotId","restatementReason","createdByUserId","reason","createdAt","sealedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"reportingScopeId":{"type":"string","format":"uuid"},"reportingScopeVersionId":{"type":"string","format":"uuid"},"glPeriodId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"eliminationSnapshotId":{"type":"string","format":"uuid"},"eliminationSnapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"subsidiaryEntityIds":{"type":"array","uniqueItems":true,"items":{"type":"string","format":"uuid"}},"sourceHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"outputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"sourceManifest":{"type":"array","items":{"$ref":"#/components/schemas/ModelANciSourceManifestEntry"}},"adjustments":{"type":"array","items":{"type":"object","additionalProperties":true}},"payload":{"type":"object","description":"Exact post-elimination NCI source-allocation control schedule. It remains unposted, keeps NCI rollforward and disposal procedures pending, and cannot be represented as a final consolidated financial statement.\n","additionalProperties":true},"revision":{"type":"integer","minimum":1},"supersedesSnapshotId":{"type":["string","null"],"format":"uuid"},"restatementReason":{"type":["string","null"],"maxLength":1000},"createdByUserId":{"type":"string","format":"uuid"},"reason":{"type":"string","minLength":1,"maxLength":500},"createdAt":{"type":"string","format":"date-time"},"sealedAt":{"type":"string","format":"date-time"}}},"ModelANciSnapshotResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ModelANciSnapshot"}}},"ModelANciSnapshotsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelANciSnapshot"}}}},"CreateModelAIssuedConsolidatedStatementInput":{"type":"object","additionalProperties":false,"required":["baseNciSnapshotId","procedureDocumentIds","reason"],"properties":{"baseNciSnapshotId":{"type":"string","format":"uuid","description":"Exact current sealed post-NCI source snapshot."},"procedureDocumentIds":{"type":"array","minItems":1,"maxItems":100,"uniqueItems":true,"description":"Reviewed persisted documents containing strict consolidation procedure metadata. Accounting amounts are read from these sources, never accepted directly from this request.\n","items":{"type":"string","format":"uuid"}},"supersedesSnapshotId":{"type":"string","format":"uuid"},"restatementReason":{"type":"string","minLength":1,"maxLength":1000},"reason":{"type":"string","minLength":1,"maxLength":1000}}},"ModelAIssuedConsolidatedStatementPayload":{"type":"object","additionalProperties":true,"required":["consolidationStatus","gaapStatus","isConsolidatedFinancialStatement","isPostedToLedger","nciPending","pendingProcedures","baseNciSnapshotId","baseNciSnapshotOutputHash","procedureAuthorities","nciRollforwardAuthorities","lines","totals"],"properties":{"profitAndLossPresentation":{"type":"object","additionalProperties":false,"description":"Server-resolved account classification sealed into the source and output hashes of new issues or controlled restatements. Absent on legacy issues, whose Revenue grouping remains unchanged.","required":["version","otherIncomeAccountIds"],"properties":{"version":{"type":"integer","enum":[1]},"otherIncomeAccountIds":{"type":"array","uniqueItems":true,"items":{"type":"string","format":"uuid"}}}},"consolidationStatus":{"type":"string","enum":["issued_consolidated"]},"gaapStatus":{"type":"string","enum":["issued"]},"isConsolidatedFinancialStatement":{"type":"boolean","enum":[true]},"isPostedToLedger":{"type":"boolean","enum":[false]},"nciPending":{"type":"boolean","enum":[false]},"pendingProcedures":{"type":"array","maxItems":0,"items":{"type":"string"}},"baseNciSnapshotId":{"type":"string","format":"uuid"},"baseNciSnapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"procedureAuthorities":{"type":"array","minItems":1,"description":"Exact reviewed-document hashes, assertions, covered entities, and source-backed procedure lines used to form the issued statement.\n","items":{"type":"object","additionalProperties":true}},"nciRollforwardAuthorities":{"type":"array","description":"Exact current NCI lifecycle rollforwards used by the statement.","items":{"type":"object","additionalProperties":false,"required":["id","outputHash","fingerprint","subsidiaryEntityId","endingNciCents","endingNciCtaCents"],"properties":{"id":{"type":"string","format":"uuid"},"outputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"subsidiaryEntityId":{"type":"string","format":"uuid"},"endingNciCents":{"type":"integer","format":"int64"},"endingNciCtaCents":{"type":"integer","format":"int64"}}}},"lines":{"type":"array","description":"Final presentation-currency trial-balance lines with standalone, FX, intercompany, NCI, policy, investment-equity, and disposal source provenance preserved for drilldown.\n","items":{"type":"object","additionalProperties":true}},"totals":{"type":"object","additionalProperties":false,"required":["debitCents","creditCents","differenceCents"],"properties":{"debitCents":{"type":"integer","format":"int64"},"creditCents":{"type":"integer","format":"int64"},"differenceCents":{"type":"integer","enum":[0]}}}}},"ModelAIssuedConsolidatedStatement":{"type":"object","additionalProperties":false,"required":["id","companyId","reportingScopeId","reportingScopeVersionId","glPeriodId","periodStart","periodEnd","presentationCurrency","baseNciSnapshotId","baseNciSnapshotOutputHash","procedureDocumentIds","nciRollforwardIds","sourceHash","outputHash","fingerprint","payload","revision","supersedesSnapshotId","restatementReason","createdByUserId","reason","createdAt","sealedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"reportingScopeId":{"type":"string","format":"uuid"},"reportingScopeVersionId":{"type":"string","format":"uuid"},"glPeriodId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"baseNciSnapshotId":{"type":"string","format":"uuid"},"baseNciSnapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"procedureDocumentIds":{"type":"array","uniqueItems":true,"items":{"type":"string","format":"uuid"}},"nciRollforwardIds":{"type":"array","uniqueItems":true,"items":{"type":"string","format":"uuid"}},"sourceHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"outputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"payload":{"$ref":"#/components/schemas/ModelAIssuedConsolidatedStatementPayload"},"revision":{"type":"integer","minimum":1},"supersedesSnapshotId":{"type":["string","null"],"format":"uuid"},"restatementReason":{"type":["string","null"],"maxLength":1000},"createdByUserId":{"type":"string","format":"uuid"},"reason":{"type":"string","minLength":1,"maxLength":1000},"createdAt":{"type":"string","format":"date-time"},"sealedAt":{"type":"string","format":"date-time"}}},"ModelAIssuedConsolidatedStatementResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ModelAIssuedConsolidatedStatement"}}},"ModelAIssuedConsolidatedStatementsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelAIssuedConsolidatedStatement"}}}},"ModelAIntercompanyBalanceRollforward":{"type":"object","additionalProperties":false,"required":["companyId","reportingScopeId","reportingScopeVersionId","glPeriodId","periodStart","periodEnd","classification","transactionCurrency","creditorEntityId","debtorEntityId","openingDueFromCents","openingDueToCents","periodDueFromMovementCents","periodDueToMovementCents","closingDueFromCents","closingDueToCents","closingDifferenceCents","matchedInPeriodCents","matchedThroughPeriodCents","sourceDesignationIds","matchIds"],"properties":{"companyId":{"type":"string","format":"uuid"},"reportingScopeId":{"type":"string","format":"uuid"},"reportingScopeVersionId":{"type":"string","format":"uuid"},"glPeriodId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"classification":{"type":"string","enum":["receivable_payable","loan_principal"]},"transactionCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"creditorEntityId":{"type":"string","format":"uuid"},"debtorEntityId":{"type":"string","format":"uuid"},"openingDueFromCents":{"type":"integer","format":"int64"},"openingDueToCents":{"type":"integer","format":"int64"},"periodDueFromMovementCents":{"type":"integer","format":"int64"},"periodDueToMovementCents":{"type":"integer","format":"int64"},"closingDueFromCents":{"type":"integer","format":"int64"},"closingDueToCents":{"type":"integer","format":"int64"},"closingDifferenceCents":{"type":"integer","format":"int64"},"matchedInPeriodCents":{"type":"integer","format":"int64","minimum":0},"matchedThroughPeriodCents":{"type":"integer","format":"int64","minimum":0},"sourceDesignationIds":{"type":"array","items":{"type":"string","format":"uuid"}},"matchIds":{"type":"array","items":{"type":"string","format":"uuid"}}}},"ModelAIntercompanyBalanceRollforwardsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelAIntercompanyBalanceRollforward"}}}},"ReportingScopeRollupManifestItem":{"type":"object","additionalProperties":false,"required":["entityId","snapshotId"],"properties":{"entityId":{"type":"string","format":"uuid"},"snapshotId":{"type":"string","format":"uuid"}}},"ReportingScopeRollupConstituentSnapshot":{"allOf":[{"$ref":"#/components/schemas/ReportingScopeRollupManifestItem"},{"type":"object","additionalProperties":false,"required":["snapshotOutputHash"],"properties":{"entityId":{"type":"string","format":"uuid"},"snapshotId":{"type":"string","format":"uuid"},"snapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"}}}]},"ReportingScopeTrialBalanceConstituentSnapshot":{"allOf":[{"$ref":"#/components/schemas/ReportingScopeRollupManifestItem"},{"type":"object","additionalProperties":false,"required":["snapshotOutputHash","coaMappingRevisionHash","rateSetRevisionHash"],"properties":{"entityId":{"type":"string","format":"uuid"},"snapshotId":{"type":"string","format":"uuid"},"snapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"coaMappingRevisionHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"rateSetRevisionHash":{"type":"string","pattern":"^[a-f0-9]{64}$"}}}]},"CreateReportingScopeTrialBalanceInput":{"type":"object","additionalProperties":false,"required":["constituentSnapshots"],"properties":{"constituentSnapshots":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ReportingScopeRollupManifestItem"}}}},"ReportingScopeTrialBalance":{"type":"object","additionalProperties":false,"required":["id","companyId","reportingScopeId","reportingScopeVersionId","glPeriodId","periodStart","periodEnd","presentationCurrency","sourceHash","outputHash","fingerprint","payload","constituentSnapshots","createdByUserId","createdAt","sealedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"reportingScopeId":{"type":"string","format":"uuid"},"reportingScopeVersionId":{"type":"string","format":"uuid"},"glPeriodId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"sourceHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"outputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"payload":{"type":"object","description":"Adjusted pre-closing, pre-elimination control schedule with exact entity, standalone snapshot, GL account, journal line, and FX-rate provenance. It explicitly remains incomplete, non-consolidated, and unposted to the ledger.\n","additionalProperties":true},"constituentSnapshots":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ReportingScopeTrialBalanceConstituentSnapshot"}},"createdByUserId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"sealedAt":{"type":"string","format":"date-time"}}},"ReportingScopeTrialBalanceResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ReportingScopeTrialBalance"}}},"ReportingScopeTrialBalancesResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ReportingScopeTrialBalance"}}}},"CreateReportingScopeProfitAndLossRollupInput":{"type":"object","additionalProperties":false,"required":["reportType","constituentSnapshots"],"properties":{"reportType":{"type":"string","enum":["profit_and_loss"]},"constituentSnapshots":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ReportingScopeRollupManifestItem"}}}},"CreateReportingScopeBalanceSheetRollupInput":{"type":"object","additionalProperties":false,"required":["reportType","constituentSnapshots","translationAdjustmentSnapshotId"],"properties":{"reportType":{"type":"string","enum":["balance_sheet"]},"constituentSnapshots":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ReportingScopeRollupManifestItem"}},"translationAdjustmentSnapshotId":{"type":"string","format":"uuid"}}},"CreateReportingScopeRollupInput":{"oneOf":[{"$ref":"#/components/schemas/CreateReportingScopeProfitAndLossRollupInput"},{"$ref":"#/components/schemas/CreateReportingScopeBalanceSheetRollupInput"}]},"CreateReportingScopeTranslationAdjustmentInput":{"type":"object","additionalProperties":false,"required":["constituentSnapshots"],"properties":{"constituentSnapshots":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ReportingScopeRollupManifestItem"}}}},"ReportingScopeRollupTranslationAdjustmentSnapshot":{"type":"object","additionalProperties":false,"required":["snapshotId","snapshotOutputHash"],"properties":{"snapshotId":{"type":"string","format":"uuid"},"snapshotOutputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"}}},"ReportingScopeRollup":{"type":"object","additionalProperties":false,"required":["id","companyId","reportingScopeId","reportingScopeVersionId","reportType","periodStart","periodEnd","presentationCurrency","sourceHash","outputHash","fingerprint","payload","constituentSnapshots","translationAdjustmentSnapshot","createdByUserId","createdAt","sealedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"reportingScopeId":{"type":"string","format":"uuid"},"reportingScopeVersionId":{"type":"string","format":"uuid"},"reportType":{"type":"string","enum":["profit_and_loss","balance_sheet"]},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"sourceHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"outputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"payload":{"type":"object","description":"Entity-keyed pre-elimination P&L or balance-sheet calculation with exact contribution provenance. It explicitly sets gaapStatus to incomplete and isConsolidatedFinancialStatement to false.\n","additionalProperties":true},"constituentSnapshots":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ReportingScopeRollupConstituentSnapshot"}},"translationAdjustmentSnapshot":{"oneOf":[{"$ref":"#/components/schemas/ReportingScopeRollupTranslationAdjustmentSnapshot"},{"type":"null"}]},"createdByUserId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"sealedAt":{"type":"string","format":"date-time"}}},"ReportingScopeRollupResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ReportingScopeRollup"}}},"ReportingScopeRollupsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ReportingScopeRollup"}}}},"ReportingScopeTranslationAdjustment":{"type":"object","additionalProperties":false,"required":["id","companyId","reportingScopeId","reportingScopeVersionId","periodStart","periodEnd","presentationCurrency","sourceHash","outputHash","fingerprint","payload","constituentSnapshots","createdByUserId","createdAt","sealedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"reportingScopeId":{"type":"string","format":"uuid"},"reportingScopeVersionId":{"type":"string","format":"uuid"},"periodStart":{"type":"string","format":"date"},"periodEnd":{"type":"string","format":"date"},"presentationCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"sourceHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"outputHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"payload":{"type":"object","description":"Entity-keyed IAS 21 translation audit with exact contribution and FX-revision provenance. It is recognized in OCI, remains separate equity authority, and is never a ledger posting.\n","additionalProperties":true},"constituentSnapshots":{"type":"array","minItems":2,"maxItems":250,"items":{"$ref":"#/components/schemas/ReportingScopeRollupConstituentSnapshot"}},"createdByUserId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"sealedAt":{"type":"string","format":"date-time"}}},"ReportingScopeTranslationAdjustmentResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ReportingScopeTranslationAdjustment"}}},"ReportingScopeTranslationAdjustmentsResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ReportingScopeTranslationAdjustment"}}}},"Entity":{"type":"object","description":"A concrete legal entity under a company. Consolidated read identities live exclusively in ReportingScope and never appear as entities.\n","required":["id","companyId","name","functionalCurrency","isGroup","isPrimary"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"name":{"type":"string"},"shortName":{"type":["string","null"]},"role":{"type":["string","null"]},"functionalCurrency":{"type":"string","description":"ISO 4217 functional currency code (e.g. USD, GBP).","pattern":"^[A-Z]{3}$"},"ownershipPct":{"type":["number","null"],"description":"Parent's ownership percentage of this entity, or null for the group/parent."},"parentEntityId":{"type":["string","null"],"format":"uuid"},"isGroup":{"type":"boolean","enum":[false],"description":"Deprecated compatibility field; Model A entities are always concrete."},"isPrimary":{"type":"boolean","description":"True for the one legal entity that owns legacy or otherwise unscoped accounting facts."}}},"CreateLegalEntityInput":{"type":"object","additionalProperties":false,"required":["name","functionalCurrency"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"shortName":{"type":["string","null"],"minLength":1,"maxLength":200},"role":{"type":["string","null"],"minLength":1,"maxLength":200},"functionalCurrency":{"type":"string","pattern":"^[A-Z]{3}$","example":"BRL"},"ownershipPct":{"type":["number","null"],"minimum":0,"maximum":100},"parentEntityId":{"type":["string","null"],"format":"uuid"}}},"UpdateLegalEntityInput":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"shortName":{"type":["string","null"],"minLength":1,"maxLength":200},"role":{"type":["string","null"],"minLength":1,"maxLength":200},"ownershipPct":{"type":["number","null"],"minimum":0,"maximum":100},"parentEntityId":{"type":["string","null"],"format":"uuid"}}},"EntityResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Entity"}}},"EntitiesResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Entity"}}}},"EntityAccessSummary":{"type":"object","additionalProperties":false,"required":["companyId","userId","scope","entityIds"],"properties":{"companyId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"scope":{"type":"string","enum":["all_entities","entities"]},"entityIds":{"type":"array","maxItems":250,"items":{"type":"string","format":"uuid"}}}},"ReplaceEntityAccessInput":{"oneOf":[{"type":"object","additionalProperties":false,"required":["scope"],"properties":{"scope":{"type":"string","enum":["all_entities"]}}},{"type":"object","additionalProperties":false,"required":["scope","entityIds"],"properties":{"scope":{"type":"string","enum":["entities"]},"entityIds":{"type":"array","minItems":1,"maxItems":250,"items":{"type":"string","format":"uuid"}}}}],"discriminator":{"propertyName":"scope"}},"EntityAccessSummaryResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/EntityAccessSummary"}}},"EntityAccessSummaryListResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/EntityAccessSummary"}}}},"FunctionalCurrencyHistoryRecord":{"type":"object","required":["id","companyId","entityId","currencyCode","effectiveFrom","reason","createdByUserId","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"currencyCode":{"type":"string","pattern":"^[A-Z]{3}$"},"effectiveFrom":{"type":"string","format":"date"},"reason":{"type":"string"},"createdByUserId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"}}},"ChangeFunctionalCurrencyInput":{"type":"object","additionalProperties":false,"required":["currency","effectiveFrom","reason"],"properties":{"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"effectiveFrom":{"type":"string","format":"date"},"reason":{"type":"string","minLength":1,"maxLength":500}}},"FunctionalCurrencyHistoryResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/FunctionalCurrencyHistoryRecord"}}}},"FunctionalCurrencyTransitionResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/FunctionalCurrencyHistoryRecord"}}},"FxRate":{"type":"object","required":["id","companyId","baseCurrency","quoteCurrency","requestedDate","periodStart","effectiveAt","rateType","rate","source","sourceKind","providerReference","fetchedAt","metadata","revision","supersedesRateId","createdByUserId","createdAt"],"properties":{"id":{"type":["string","null"],"format":"uuid"},"companyId":{"type":"string","format":"uuid"},"baseCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"quoteCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"requestedDate":{"type":"string","format":"date"},"periodStart":{"type":["string","null"],"format":"date"},"effectiveAt":{"type":"string","format":"date-time"},"rateType":{"type":"string","enum":["spot","closing","average","historical"]},"rate":{"type":"string","pattern":"^\\d+(?:\\.\\d+)?$"},"source":{"type":"string"},"sourceKind":{"type":"string","enum":["identity","provider","manual"]},"providerReference":{"type":["string","null"]},"fetchedAt":{"type":"string","format":"date-time"},"metadata":{"type":"object","additionalProperties":true},"revision":{"type":"integer","minimum":1},"supersedesRateId":{"type":["string","null"],"format":"uuid"},"createdByUserId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"}}},"CreateManualFxRateInput":{"type":"object","additionalProperties":false,"required":["baseCurrency","quoteCurrency","requestedDate","effectiveAt","rateType","rate","source","supersedesRateId"],"properties":{"baseCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"quoteCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"requestedDate":{"type":"string","format":"date"},"effectiveAt":{"type":"string","format":"date-time"},"rateType":{"type":"string","enum":["spot","closing","average","historical"]},"rate":{"type":"string","pattern":"^\\d+(?:\\.\\d+)?$"},"source":{"type":"string","minLength":1,"maxLength":500},"supersedesRateId":{"type":["string","null"],"format":"uuid"},"metadata":{"type":"object","additionalProperties":true,"default":{}},"periodStart":{"type":"string","format":"date"}}},"FxRatesResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/FxRate"}}}},"FxRateResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/FxRate"}}},"Currency":{"type":"object","description":"An enabled business currency with display metadata and its rate to the presentation currency.","required":["code","symbol","label","locale","rateToPresentation"],"properties":{"code":{"type":"string","description":"ISO 4217 currency code.","pattern":"^[A-Z]{3}$"},"symbol":{"type":"string"},"label":{"type":"string"},"locale":{"type":"string","description":"BCP 47 locale used to format amounts in this currency."},"rateToPresentation":{"type":"number","description":"Rate to convert one unit of this currency to the presentation currency."}}},"CurrenciesView":{"type":"object","required":["presentationCurrency","asOf","currencies"],"properties":{"presentationCurrency":{"type":"string","description":"ISO 4217 code of the company's presentation currency."},"asOf":{"type":["string","null"],"format":"date","description":"The FX as-of date for the returned rates, or null when no persisted rate exists."},"currencies":{"type":"array","items":{"$ref":"#/components/schemas/Currency"}}}},"CurrenciesViewResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/CurrenciesView"}}},"SetPresentationCurrencyInput":{"type":"object","required":["currency"],"additionalProperties":false,"properties":{"currency":{"type":"string","description":"The ISO 4217 presentation currency to set.","pattern":"^[A-Z]{3}$"}}},"Thread":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"subject":{"type":"string"},"status":{"type":"string","enum":["open","resolved"]},"agentType":{"type":"string","enum":["human","ai"]},"agentName":{"type":["string","null"]},"initiatedByUserId":{"type":["string","null"],"format":"uuid"},"createdBy":{"type":["string","null"],"format":"uuid"},"resolvedBy":{"type":["string","null"],"format":"uuid"},"resolvedAt":{"type":["string","null"],"format":"date-time"},"lastActivityAt":{"type":"string","format":"date-time"},"lastMessageAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}},"CreateThreadInput":{"type":"object","required":["subject"],"properties":{"subject":{"type":"string","minLength":1,"maxLength":1000},"agentType":{"type":"string","enum":["human","ai"],"default":"human"},"agentName":{"type":"string","maxLength":255}}},"UpdateThreadInput":{"type":"object","properties":{"subject":{"type":"string","minLength":1,"maxLength":1000},"status":{"type":"string","enum":["open","resolved"]}}},"ThreadResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Thread"}}},"ThreadsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Thread"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"ThreadAttachment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"messageId":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["file","link","document","transaction","schedule_proposal"]},"label":{"type":["string","null"]},"url":{"type":["string","null"],"description":"The stored link of a `link` or `transaction` attachment: an http(s) URL or a root-relative path. Always null for a `document` or `file` attachment, whose link is `downloadUrl`."},"refId":{"type":["string","null"],"format":"uuid","description":"The referenced document or transaction. It is resolved only inside the thread's own company."},"available":{"type":"boolean","description":"False when a `document` or `file` attachment does not resolve for this caller: the reference is missing, belongs elsewhere, is outside the caller's authority, or its stored file is not servable. The reason is not disclosed. Always true for other kinds."},"downloadUrl":{"type":["string","null"],"description":"A download link minted for this caller on this read, valid until `downloadUrlExpiresAt`. Root-relative. Null unless the attachment is an available `document` or `file`. The download endpoint checks the caller's access again when the link is used."},"downloadUrlExpiresAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","messageId","type","label","url","refId","available","downloadUrl","downloadUrlExpiresAt","createdAt"]},"ThreadMessage":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"threadId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"authorId":{"type":["string","null"],"format":"uuid"},"body":{"type":"string"},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/ThreadAttachment"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ThreadAttachmentInput":{"type":"object","description":"A user attachment. `document`, or `file` with a `refId`: `refId` is required and names an uploaded document of the thread's company; a `url` may be sent (or null) and is discarded; the attachment is stored as `document`. `file` without `refId` is refused. `link`: `url` is required. `transaction`: `refId` is required. Internal kinds such as `schedule_proposal` are never accepted.","properties":{"type":{"type":"string","enum":["file","link","document","transaction"],"default":"file"},"label":{"type":"string","maxLength":255},"url":{"type":["string","null"],"description":"An http(s) URL or a root-relative path. Required for `link`; ignored for `document` and `file`."},"refId":{"type":"string","format":"uuid","description":"Required for `document`, `file` and `transaction`."}}},"CreateThreadMessageInput":{"type":"object","description":"Either a non-empty body or at least one attachment is required; an attachment-only message may omit the body or send it empty.","properties":{"body":{"type":"string","default":""},"attachments":{"type":"array","maxItems":20,"items":{"$ref":"#/components/schemas/ThreadAttachmentInput"}}}},"CreateAccountantThreadInput":{"type":"object","required":["subject"],"properties":{"customerId":{"type":"string","format":"uuid","description":"The customer company. Required on `/accountant/threads`, where the path does not name it."},"companyId":{"type":"string","format":"uuid","description":"Accepted as an alias of `customerId`."},"subject":{"type":"string","minLength":1,"maxLength":1000},"content":{"type":["string","null"],"default":"","description":"Text of the first message. May be empty when attachments are present."},"transactionIds":{"type":"array","items":{"type":"string","minLength":1}},"category":{"type":"string","enum":["categorization","documentation","approval","general"]},"blocksClose":{"type":"boolean"},"attachments":{"type":"array","maxItems":20,"items":{"$ref":"#/components/schemas/ThreadAttachmentInput"}}}},"AccountantThreadAttachment":{"type":"object","required":["name","type","url","refId","available","downloadUrl","downloadUrlExpiresAt"],"properties":{"name":{"type":"string","description":"The attachment's label, falling back to its reference id or url."},"type":{"type":"string","enum":["file","link","document","transaction","schedule_proposal"]},"url":{"type":["string","null"],"description":"The stored link of a `link` or `transaction` attachment. Always null for a `document` or `file` attachment, whose link is `downloadUrl`."},"refId":{"type":["string","null"],"format":"uuid"},"available":{"type":"boolean","description":"False when a `document` or `file` attachment does not resolve for this caller. The reason is not disclosed."},"downloadUrl":{"type":["string","null"],"description":"A download link minted for this caller on this read. Root-relative. Null unless the attachment is an available `document` or `file`."},"downloadUrlExpiresAt":{"type":["string","null"],"format":"date-time"}}},"AccountantThreadMessage":{"type":"object","required":["id","sender","senderName","senderAvatarUrl","content","timestamp","attachments"],"properties":{"id":{"type":"string","format":"uuid"},"sender":{"type":"string"},"senderName":{"type":"string"},"senderAvatarUrl":{"type":["string","null"]},"content":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/AccountantThreadAttachment"}}}},"AccountantThreadMessageResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/AccountantThreadMessage"}}},"AccountantThreadMessagesListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/AccountantThreadMessage"}},"meta":{"type":"object","properties":{"nextCursor":{"type":["string","null"]},"hasMore":{"type":"boolean"}}}}},"AccountantThreadSummaryResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","description":"The thread summary the accountant thread list returns. It carries no attachments.","additionalProperties":true}}},"ThreadMessageResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ThreadMessage"}}},"ThreadMessagesListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ThreadMessage"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"ScheduledCall":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"scheduledBy":{"type":["string","null"],"format":"uuid"},"scheduledAt":{"type":"string","format":"date-time"},"durationMinutes":{"type":"integer"},"status":{"type":"string","enum":["scheduled","completed","cancelled"]},"notes":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateScheduledCallInput":{"type":"object","required":["scheduledAt"],"properties":{"scheduledAt":{"type":"string","format":"date-time","example":"2026-06-15T10:00:00Z"},"durationMinutes":{"type":"integer","minimum":5,"maximum":480,"default":30},"notes":{"type":"string","maxLength":2000}}},"UpdateScheduledCallInput":{"type":"object","properties":{"scheduledAt":{"type":"string","format":"date-time"},"durationMinutes":{"type":"integer","minimum":5,"maximum":480},"status":{"type":"string","enum":["scheduled","completed","cancelled"]},"notes":{"type":["string","null"],"maxLength":2000}}},"ScheduledCallResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ScheduledCall"}}},"ScheduledCallsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ScheduledCall"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"Document":{"type":"object","additionalProperties":false,"required":["id","entityId","type","status","name","vendorName","customerName","invoiceNumber","amountCents","amountPaidCents","outstandingAmountCents","currency","minorUnitExponent","uploadedAt","dueDate","sizeBytes","transactionId","category","docDate","paymentStatus","sourceProvider","sourceRefs","externalViewUrl","hasProposedMatch","possibleDuplicateOf"],"properties":{"id":{"type":"string","format":"uuid"},"entityId":{"type":["string","null"],"format":"uuid"},"type":{"type":"string","enum":["invoice","bill","receipt","contract","statement"]},"status":{"type":"string","enum":["needs_review","reviewed","processed","archived"]},"name":{"type":"string"},"vendorName":{"type":["string","null"]},"customerName":{"type":["string","null"]},"invoiceNumber":{"type":["string","null"]},"amountCents":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991,"description":"Document total in the persisted currency's authoritative minor units; null only for true-empty intake."},"amountPaidCents":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991,"description":"Server-owned sum of applied, same-entity, same-currency payment matches; null with a true-empty document amount."},"outstandingAmountCents":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991,"description":"Exact amountCents minus amountPaidCents; null with a true-empty document amount."},"currency":{"type":["string","null"],"pattern":"^[A-Z]{3}$","description":"Certified ISO 4217 currency; null only for true-empty document money."},"minorUnitExponent":{"type":["integer","null"],"enum":[2,null],"description":"Public scale authority for every non-null document amount."},"paymentStatus":{"type":["string","null"],"enum":["open","partial","paid",null],"description":"Server-owned bill rollup status; null for non-bills."},"uploadedAt":{"type":"string","format":"date-time"},"dueDate":{"type":["string","null"],"format":"date"},"sizeBytes":{"type":["integer","null"]},"transactionId":{"type":["string","null"],"format":"uuid"},"category":{"type":["string","null"]},"docDate":{"type":["string","null"],"format":"date"},"sourceProvider":{"type":["string","null"]},"sourceRefs":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["type","id","label"],"properties":{"type":{"type":"string"},"id":{"type":"string"},"label":{"type":["string","null"]}}}},"externalViewUrl":{"type":["string","null"]},"hasProposedMatch":{"type":"boolean","description":"Derived. True when the engine has a proposed (not yet applied) match for this document. Drives the feed's \"Review match\" call-to-action."},"possibleDuplicateOf":{"type":["object","null"],"additionalProperties":false,"required":["id","name"],"description":"Derived on the documents list only; null on every other response. The earliest-created live document of the same company, entity and type with the same counterparty (vendor, or customer when there is no vendor), invoice number, document date and amount. Null when this document is that earliest one, has no such twin, or is missing any of the four fields. A marker only: both documents stay listed.","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"downloadUrl":{"type":"string","description":"Optional short-lived signed download authority when a file is available to the authenticated actor."}}},"ScheduleProposalClarificationThread":{"type":"object","required":["id","status","ownership","blocksClose","initialMessageId","hasCustomerReply","customerReplyCount"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["open","resolved","archived"]},"ownership":{"type":"string","enum":["ai","accountant"]},"blocksClose":{"type":"boolean","const":false},"initialMessageId":{"type":"string","format":"uuid"},"hasCustomerReply":{"type":"boolean"},"customerReplyCount":{"type":"integer","minimum":0},"lastCustomerReplyAt":{"type":["string","null"],"format":"date-time"}}},"ScheduleProposalClarification":{"type":"object","required":["state","question","draftedAt"],"properties":{"state":{"type":"string","enum":["draft","sent"]},"question":{"type":"string"},"draftedAt":{"type":"string","format":"date-time"},"sentAt":{"type":"string","format":"date-time"},"sentByUserId":{"type":["string","null"],"format":"uuid"},"threadId":{"type":"string","format":"uuid"},"initialMessageId":{"type":"string","format":"uuid"},"thread":{"$ref":"#/components/schemas/ScheduleProposalClarificationThread"}}},"CreateDocumentInput":{"type":"object","required":["type","name"],"dependentRequired":{"amountCents":["currency"],"currency":["amountCents"]},"properties":{"entityId":{"type":"string","format":"uuid","description":"Concrete legal entity selected from the authenticated actor's authorized entity scope. Omit only for restricted, non-financial intake that must be assigned by an administrator.\n"},"type":{"type":"string","enum":["invoice","bill","receipt","contract","statement"]},"name":{"type":"string","minLength":1,"maxLength":500},"vendorName":{"type":"string"},"customerName":{"type":"string"},"invoiceNumber":{"type":"string"},"amountCents":{"type":"integer","minimum":0,"maximum":9007199254740991},"currency":{"type":"string","pattern":"^[A-Za-z]{3}$","description":"Required with amountCents; accepted case-insensitively, normalized to uppercase, and restricted to registered scale-two ISO 4217 currencies."},"categoryGlAccountId":{"type":"string","format":"uuid"},"dueDate":{"type":"string","format":"date"},"fileKey":{"type":"string","description":"Optional. Must reference an accepted stored file of the same company (a `clean` file, or the file the upload flow stored for it); any other key, including a quarantine key, is rejected with 422."},"fileUrl":{"type":"string"},"sizeBytes":{"type":"integer"},"fileName":{"type":"string"},"mimeType":{"type":"string"},"transactionId":{"type":"string","format":"uuid"},"category":{"type":"string"},"docDate":{"type":"string","format":"date"},"notes":{"type":"string"},"metadata":{"type":"object","additionalProperties":true,"default":{}}}},"AssignDocumentEntityInput":{"type":"object","additionalProperties":false,"required":["entityId","reason"],"properties":{"entityId":{"type":"string","format":"uuid"},"reason":{"type":"string","minLength":1,"maxLength":2000}}},"UpdateDocumentInput":{"type":"object","dependentRequired":{"amountCents":["currency"],"currency":["amountCents"]},"allOf":[{"if":{"required":["amountCents"],"properties":{"amountCents":{"type":"null"}}},"then":{"properties":{"currency":{"type":"null"}}}},{"if":{"required":["currency"],"properties":{"currency":{"type":"null"}}},"then":{"properties":{"amountCents":{"type":"null"}}}}],"properties":{"type":{"type":"string","enum":["invoice","bill","receipt","contract","statement"]},"status":{"type":"string","enum":["needs_review","reviewed","processed","archived"]},"name":{"type":"string","minLength":1,"maxLength":500},"vendorName":{"type":["string","null"]},"customerName":{"type":["string","null"]},"invoiceNumber":{"type":["string","null"]},"amountCents":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"currency":{"type":["string","null"],"pattern":"^[A-Za-z]{3}$","description":"Must be supplied atomically with amountCents; non-null values are normalized to uppercase and restricted to registered scale-two ISO 4217 currencies."},"categoryGlAccountId":{"type":["string","null"]},"dueDate":{"type":["string","null"]},"fileKey":{"type":["string","null"],"description":"`null` detaches the file. A string must reference an accepted stored file of the same company (a `clean` file, or the file the upload flow stored for it); any other key, including a quarantine key, is rejected with 422."},"fileUrl":{"type":["string","null"]},"sizeBytes":{"type":["integer","null"]},"fileName":{"type":["string","null"]},"mimeType":{"type":["string","null"]},"transactionId":{"type":["string","null"]},"category":{"type":["string","null"]},"docDate":{"type":["string","null"]},"notes":{"type":["string","null"]},"metadata":{"type":"object","additionalProperties":true}}},"DocumentResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Document"}}},"DocumentsListResponse":{"type":"object","required":["success","data","meta"],"properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Document"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"MatchDocumentInput":{"type":"object","additionalProperties":false,"required":["transactionId"],"properties":{"transactionId":{"type":"string","format":"uuid"}}},"DocumentIdInput":{"type":"object","additionalProperties":false,"required":["documentId"],"properties":{"documentId":{"type":"string","format":"uuid"}}},"DocumentMatchAllocationsInput":{"type":"object","additionalProperties":false,"required":["allocations"],"properties":{"allocations":{"type":"array","minItems":1,"items":{"type":"object","additionalProperties":false,"required":["documentId","amountCents"],"properties":{"documentId":{"type":"string","format":"uuid"},"amountCents":{"type":"integer","minimum":1,"maximum":9007199254740991}}}}}},"DocumentMatchReasonInput":{"type":"object","additionalProperties":false,"properties":{"reason":{"type":"string","minLength":1}}},"ConfirmDocumentMatchProposalsInput":{"type":"object","additionalProperties":false,"required":["pairs"],"properties":{"dryRun":{"type":"boolean","default":false},"pairs":{"type":"array","minItems":1,"items":{"type":"object","additionalProperties":false,"required":["documentId","transactionId"],"properties":{"documentId":{"type":"string","format":"uuid"},"transactionId":{"type":"string","format":"uuid"}}}}}},"DocumentMatchTransaction":{"type":"object","additionalProperties":false,"required":["id","entityId","occurredOn","description","merchantName","amountCents","currency","minorUnitExponent","direction","sourceAccountName","sourceProviderLabel"],"properties":{"id":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"occurredOn":{"type":"string","format":"date"},"description":{"type":"string"},"merchantName":{"type":["string","null"]},"amountCents":{"type":"integer","minimum":0,"maximum":9007199254740991},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer","const":2},"direction":{"type":"string","enum":["in","out"]},"sourceAccountName":{"type":["string","null"]},"sourceProviderLabel":{"type":["string","null"]}}},"CustomerDocumentMatch":{"type":"object","additionalProperties":false,"required":["id","status","transactionId","amountCents","currency","minorUnitExponent"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["proposed","applied","rejected"]},"transactionId":{"type":"string","format":"uuid"},"amountCents":{"type":["integer","null"],"minimum":1,"maximum":9007199254740991},"currency":{"type":["string","null"],"pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":["integer","null"],"enum":[2,null]}},"oneOf":[{"properties":{"amountCents":{"type":"integer","minimum":1,"maximum":9007199254740991},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer","const":2}}},{"properties":{"status":{"type":"string","enum":["proposed","rejected"]},"amountCents":{"type":"null"},"currency":{"type":"null"},"minorUnitExponent":{"type":"null"}}}],"allOf":[{"if":{"properties":{"status":{"const":"applied"}},"required":["status"]},"then":{"properties":{"amountCents":{"type":"integer","minimum":1,"maximum":9007199254740991},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer","const":2}}}}]},"AccountantDocumentMatchProposal":{"type":"object","additionalProperties":false,"required":["id","status","transactionId","amountCents","currency","minorUnitExponent","method","confidence"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["proposed","applied","rejected"]},"transactionId":{"type":"string","format":"uuid"},"amountCents":{"type":["integer","null"],"minimum":1,"maximum":9007199254740991},"currency":{"type":["string","null"],"pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":["integer","null"],"enum":[2,null]},"method":{"type":["string","null"]},"confidence":{"type":["number","null"]}},"oneOf":[{"properties":{"amountCents":{"type":"integer","minimum":1,"maximum":9007199254740991},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer","const":2}}},{"properties":{"status":{"type":"string","enum":["proposed","rejected"]},"amountCents":{"type":"null"},"currency":{"type":"null"},"minorUnitExponent":{"type":"null"}}}]},"AccountantDocumentMatch":{"type":"object","additionalProperties":false,"required":["id","documentId","transactionId","status","method","confidence","amountCents","currency","minorUnitExponent"],"properties":{"id":{"type":"string","format":"uuid"},"documentId":{"type":"string","format":"uuid"},"transactionId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["proposed","applied","rejected"]},"method":{"type":["string","null"]},"confidence":{"type":["number","null"]},"amountCents":{"type":["integer","null"],"minimum":1,"maximum":9007199254740991},"currency":{"type":["string","null"],"pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":["integer","null"],"enum":[2,null]}},"oneOf":[{"properties":{"amountCents":{"type":"integer","minimum":1,"maximum":9007199254740991},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer","const":2}}},{"properties":{"status":{"type":"string","enum":["proposed","rejected"]},"amountCents":{"type":"null"},"currency":{"type":"null"},"minorUnitExponent":{"type":"null"}}}]},"QuickBooksDocumentCandidates":{"type":"object","required":["documentId","state","reason","snapshot","candidates","truncated"],"properties":{"documentId":{"type":"string","format":"uuid"},"state":{"type":"string","enum":["ready","disabled","unavailable","missing_fields","none"]},"reason":{"type":["string","null"],"enum":["not_configured","no_connection","ambiguous_connection","sync_in_progress","no_completed_snapshot","snapshot_failed","unassigned_document","missing_vendor_or_date","candidate_limit",null]},"snapshot":{"type":["object","null"],"required":["runId","completedAt"],"properties":{"runId":{"type":"string","format":"uuid"},"completedAt":{"type":"string","format":"date-time"}}},"truncated":{"type":"boolean"},"candidates":{"type":"array","maxItems":20,"items":{"type":"object","required":["objectType","providerId","documentNumber","vendorName","txnDate","amountMinorUnits","currency","minorUnitExponent","grade","signals"],"properties":{"objectType":{"type":"string","enum":["Bill","Purchase","VendorCredit"]},"providerId":{"type":"string"},"documentNumber":{"type":["string","null"]},"vendorName":{"type":"string"},"txnDate":{"type":"string","format":"date"},"amountMinorUnits":{"type":["string","null"],"pattern":"^-?[0-9]+$"},"currency":{"type":["string","null"]},"minorUnitExponent":{"type":["integer","null"],"minimum":0,"maximum":9},"grade":{"type":"string","enum":["exact","probable"]},"signals":{"type":"object","required":["number","vendor","date","amount"],"properties":{"number":{"type":"boolean"},"vendor":{"type":"boolean"},"date":{"type":"boolean"},"amount":{"type":["boolean","null"]}}}}}}}},"CustomerDocumentMatchCandidate":{"type":"object","additionalProperties":false,"required":["transaction"],"properties":{"transaction":{"$ref":"#/components/schemas/DocumentMatchTransaction"}}},"AccountantDocumentMatchCandidate":{"type":"object","additionalProperties":false,"required":["transaction","score","amountDiffCents","dateDiffDays","textScore"],"properties":{"transaction":{"$ref":"#/components/schemas/DocumentMatchTransaction"},"score":{"type":"number","minimum":0,"maximum":100},"amountDiffCents":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991,"description":"Exact difference in the nested transaction currency and minorUnitExponent."},"dateDiffDays":{"type":["integer","null"],"minimum":0},"textScore":{"type":["number","null"]}}},"CustomerDocumentMatchProposalData":{"oneOf":[{"type":"object","additionalProperties":false,"required":["match","transaction"],"properties":{"match":{"type":"null"},"transaction":{"type":"null"}}},{"type":"object","additionalProperties":false,"required":["match","transaction"],"properties":{"match":{"$ref":"#/components/schemas/CustomerDocumentMatch"},"transaction":{"$ref":"#/components/schemas/DocumentMatchTransaction"}}}]},"AccountantDocumentMatchProposalData":{"oneOf":[{"type":"object","additionalProperties":false,"required":["match","transaction"],"properties":{"match":{"type":"null"},"transaction":{"type":"null"}}},{"type":"object","additionalProperties":false,"required":["match","transaction"],"properties":{"match":{"$ref":"#/components/schemas/AccountantDocumentMatchProposal"},"transaction":{"$ref":"#/components/schemas/DocumentMatchTransaction"}}}]},"TransactionDocumentCandidate":{"type":"object","description":"One document offered for a transaction; the mirror of a document match candidate (#2013).","properties":{"document":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"fileName":{"type":"string"},"type":{"type":"string","enum":["invoice","bill","receipt","contract","statement"],"description":"The DISPLAYED type, re-derived from metadata; may differ from the stored column."},"status":{"type":"string"},"vendorName":{"type":["string","null"]},"customerName":{"type":["string","null"]},"invoiceNumber":{"type":["string","null"]},"amountCents":{"type":["integer","null"]},"currency":{"type":["string","null"]},"minorUnitExponent":{"type":["integer","null"]},"docDate":{"type":["string","null"]},"paymentStatus":{"type":["string","null"]}}},"attachedTransactionId":{"type":["string","null"],"description":"The transaction this document is already attached to, or null when it is free. A matched but unpaid bill keeps this while its status stays `reviewed`, so status alone cannot tell the two apart. Attaching a marked candidate REPLACES the existing link."},"score":{"type":"integer","minimum":0,"maximum":100},"amountDiffCents":{"type":["integer","null"]},"dateDiffDays":{"type":["integer","null"]},"textScore":{"type":"number"}}},"CustomerDocumentMatchCandidatesResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":false,"required":["candidates"],"properties":{"candidates":{"type":"array","items":{"$ref":"#/components/schemas/CustomerDocumentMatchCandidate"}}}}}},"AccountantDocumentMatchCandidatesResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":false,"required":["candidates"],"properties":{"candidates":{"type":"array","items":{"$ref":"#/components/schemas/AccountantDocumentMatchCandidate"}}}}}},"CustomerDocumentMatchProposalResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/CustomerDocumentMatchProposalData"}}},"AccountantDocumentMatchProposalResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/AccountantDocumentMatchProposalData"}}},"AccountantDocumentMatchHistoryItem":{"type":"object","additionalProperties":false,"required":["id","documentId","transactionId","status","method","confidence","amountCents","currency","minorUnitExponent","appliedByActorType","createdAt","updatedAt","rejectedAt","rejectionReason","unmatchedAt","unmatchReason"],"properties":{"id":{"type":"string","format":"uuid"},"documentId":{"type":"string","format":"uuid"},"transactionId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["proposed","applied","rejected"]},"method":{"type":["string","null"]},"confidence":{"type":["number","null"]},"amountCents":{"type":["integer","null"]},"currency":{"type":["string","null"],"pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":["integer","null"],"enum":[2,null]},"appliedByActorType":{"type":["string","null"],"enum":["engine","system","accountant","founder",null]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"rejectedAt":{"type":["string","null"]},"rejectionReason":{"type":["string","null"]},"unmatchedAt":{"type":["string","null"]},"unmatchReason":{"type":["string","null"]}}},"AccountantDocumentMatchHistoryResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":false,"required":["matches"],"properties":{"matches":{"type":"array","items":{"$ref":"#/components/schemas/AccountantDocumentMatchHistoryItem"}}}}}},"AccountantDocumentMatchResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":false,"required":["match"],"properties":{"match":{"$ref":"#/components/schemas/AccountantDocumentMatch"}}}}},"AccountantDocumentUnmatchResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":false,"required":["match","document","replacementJeId","voidedJeId","affectedTransactionIds"],"properties":{"match":{"$ref":"#/components/schemas/AccountantDocumentMatch"},"document":{"oneOf":[{"$ref":"#/components/schemas/Document"},{"type":"null"}]},"replacementJeId":{"type":["string","null"],"format":"uuid"},"voidedJeId":{"type":["string","null"],"format":"uuid"},"affectedTransactionIds":{"type":"array","items":{"type":"string","format":"uuid"}}}}}},"AccountantDocumentMatchMutation":{"type":"object","additionalProperties":false,"required":["matchId","documentId","transactionId","status","method","confidence","amountCents","currency","minorUnitExponent"],"properties":{"matchId":{"type":"string","format":"uuid"},"documentId":{"type":"string","format":"uuid"},"transactionId":{"type":"string","format":"uuid"},"status":{"type":"string","const":"applied"},"method":{"type":["string","null"]},"confidence":{"type":["number","null"]},"amountCents":{"type":"integer","minimum":1,"maximum":9007199254740991},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer","const":2}}},"AccountantDocumentMatchMutationResult":{"allOf":[{"$ref":"#/components/schemas/AccountantDocumentMatchMutation"},{"type":"object","properties":{"replacementJeId":{"type":["string","null"],"format":"uuid"},"voidedJeId":{"type":["string","null"],"format":"uuid"},"jeMutated":{"type":"boolean"}}}],"unevaluatedProperties":false},"AccountantDocumentMatchMutationResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/AccountantDocumentMatchMutationResult"}}},"AccountantDocumentMatchBulkMutationResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":false,"required":["matches","replacementJeId","voidedJeId"],"properties":{"matches":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/AccountantDocumentMatchMutation"}},"replacementJeId":{"type":["string","null"],"format":"uuid"},"voidedJeId":{"type":["string","null"],"format":"uuid"}}}}},"DocumentMatchAutoApplyResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":false,"required":["scanned","applied","skipped","skipReasons","appliedPairs"],"properties":{"scanned":{"type":"integer","minimum":0},"applied":{"type":"integer","minimum":0},"skipped":{"type":"integer","minimum":0},"skipReasons":{"type":"object","additionalProperties":{"type":"integer","minimum":0}},"appliedPairs":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["documentId","transactionId"],"properties":{"documentId":{"type":"string","format":"uuid"},"transactionId":{"type":"string","format":"uuid"}}}}}}}},"DocumentMatchConfirmResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":false,"required":["scanned","confirmed","skipped","results"],"properties":{"scanned":{"type":"integer","minimum":0},"confirmed":{"type":"integer","minimum":0},"skipped":{"type":"integer","minimum":0},"results":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["documentId","transactionId","outcome"],"properties":{"documentId":{"type":"string","format":"uuid"},"transactionId":{"type":"string","format":"uuid"},"outcome":{"type":"string","enum":["confirmed","would_confirm","skipped"]},"reason":{"type":"string"}}}}}}}},"DataEntry":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"source":{"type":["string","null"]},"entryType":{"type":["string","null"]},"entryDate":{"type":"string","format":"date"},"amountCents":{"type":["integer","null"]},"currency":{"type":"string"},"description":{"type":["string","null"]},"details":{"type":"object","additionalProperties":true},"status":{"type":"string","enum":["active","archived"]},"createdBy":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateDataEntryInput":{"type":"object","required":["entryDate"],"properties":{"entryDate":{"type":"string","format":"date","example":"2026-01-15"},"source":{"type":"string"},"entryType":{"type":"string"},"amountCents":{"type":"integer"},"currency":{"type":"string","default":"USD"},"description":{"type":"string"},"details":{"type":"object","additionalProperties":true,"default":{}}}},"UpdateDataEntryInput":{"type":"object","properties":{"entryDate":{"type":"string","format":"date"},"source":{"type":["string","null"]},"entryType":{"type":["string","null"]},"amountCents":{"type":["integer","null"]},"currency":{"type":"string"},"description":{"type":["string","null"]},"details":{"type":"object","additionalProperties":true},"status":{"type":"string","enum":["active","archived"]}}},"DataEntryResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/DataEntry"}}},"DataEntriesListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/DataEntry"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"Company":{"type":"object","properties":{"fiscalYearEnd":{"type":["string","null"],"description":"Fiscal year end as MM-DD (companies.fiscal_year_end). Null means not confirmed; it is never defaulted to 12-31. Writes must be a real MM-DD date (422 otherwise). A value other than 12-31 flags month-end close and statements for review, because non-calendar fiscal years are not supported yet (#2019)."},"clientStatus":{"type":"string","enum":["test","active","inactive"],"description":"Lifecycle marker (migration 089). Used by the accountant app to hide internal test tenants in production and filter customer lists by lifecycle stage. 'active' is the default on creation; 'test' is for internal QA / demo companies; 'inactive' is for customers no longer serviced."}}},"CompanyResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Company"}}},"UpdateCompanyInput":{"type":"object","description":"Partial company profile edit. Every key is optional; an empty string is treated as \"not sent\". Text fields must not contain HTML markup.","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"description":"Company name. Trimmed; cannot be empty and cannot contain control characters."},"entityType":{"type":"string","maxLength":50},"industry":{"type":"string","maxLength":100},"ein":{"type":"string","maxLength":20},"yearFounded":{"type":"integer","minimum":1800,"maximum":2100},"monthFounded":{"type":"integer","minimum":1,"maximum":12},"state":{"type":"string","maxLength":50},"website":{"type":"string","maxLength":500,"description":"An http(s) URL or a bare domain."},"description":{"type":"string","maxLength":2000},"annualRevenue":{"type":"string","maxLength":50},"monthlyExpenses":{"type":"string","maxLength":50},"accountingMethod":{"type":"string","maxLength":50},"fiscalYearEnd":{"type":["string","null"],"pattern":"^\\d{2}-\\d{2}$","description":"Fiscal year end as MM-DD; must be a real date (422 otherwise). An explicit null clears a stored value back to \"not confirmed\" (#2736); it is never defaulted to 12-31."},"currentAccountingSoftware":{"type":"string","maxLength":100},"revenueStreams":{"type":"array","items":{"type":"string","maxLength":255}},"paymentProcessors":{"type":"array","items":{"type":"string","maxLength":255}},"bankAccountCount":{"type":"string","maxLength":10},"creditCardCount":{"type":"string","maxLength":10},"hasCorporateCards":{"type":"boolean"},"hasMercury":{"type":"boolean"},"hasBrex":{"type":"boolean"},"hasRamp":{"type":"boolean"},"hasRho":{"type":"boolean"},"payrollProvider":{"type":"string","maxLength":100},"painPoint":{"type":"string","maxLength":2000},"chartOfAccountsNotes":{"type":"string","maxLength":5000},"migrationSource":{"type":"string","maxLength":50},"migrationComplete":{"type":"boolean"},"chartOfAccountsReviewed":{"type":"boolean"}}},"CompanyMember":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["owner","admin","cfo","member","viewer"]},"inviteStatus":{"type":"string"},"invitedAt":{"type":["string","null"],"format":"date-time"},"joinedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"UpdateCompanyMemberInput":{"type":"object","required":["role"],"properties":{"role":{"type":"string","enum":["owner","admin","cfo","member","viewer"]}}},"CompanyMemberResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/CompanyMember"}}},"CompanyMembersListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/CompanyMember"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"Accountant":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":["string","null"],"format":"uuid"},"displayName":{"type":"string"},"title":{"type":["string","null"]},"bio":{"type":["string","null"]},"avatarUrl":{"type":["string","null"]},"credentials":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"AccountantAssignment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"accountantId":{"type":"string","format":"uuid"},"assignedAt":{"type":"string","format":"date-time"},"isPrimary":{"type":"boolean"},"accountant":{"$ref":"#/components/schemas/Accountant"}}},"CreateAccountantAssignmentInput":{"type":"object","required":["accountantId"],"properties":{"accountantId":{"type":"string","format":"uuid"},"isPrimary":{"type":"boolean","default":true}}},"AccountantAssignmentResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/AccountantAssignment"}}},"AccountantAssignmentsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/AccountantAssignment"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"CreateAccountantInput":{"type":"object","required":["email","firstName","lastName","password"],"properties":{"email":{"type":"string","format":"email"},"firstName":{"type":"string","minLength":1,"maxLength":100},"lastName":{"type":"string","minLength":1,"maxLength":100},"password":{"type":"string","minLength":12,"maxLength":128},"displayName":{"type":"string","maxLength":200},"title":{"type":"string","maxLength":200},"credentials":{"type":"array","maxItems":10,"items":{"type":"string"}},"assignAll":{"type":"boolean","default":false,"description":"If true, assign the new accountant to every existing company."}}},"CreateAccountantResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"accountant":{"$ref":"#/components/schemas/Accountant"},"userId":{"type":"string","format":"uuid"},"email":{"type":"string"},"assignedCompanyCount":{"type":"integer"}}}}},"UserInvite":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"companyName":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["Admin","CFO","Member"]},"invitedByUserId":{"type":["string","null"],"format":"uuid"},"expiresAt":{"type":"string","format":"date-time"},"acceptedAt":{"type":["string","null"],"format":"date-time"},"acceptedByUserId":{"type":["string","null"],"format":"uuid"},"revokedAt":{"type":["string","null"],"format":"date-time"},"revokedByUserId":{"type":["string","null"],"format":"uuid"},"lastSentAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateUserInviteInput":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["Admin","CFO","Member"],"default":"Member"}}},"UserInviteResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/UserInvite"}}},"UserInvitesListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/UserInvite"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"TaxSettings":{"type":"object","properties":{"id":{"type":"string"},"companyId":{"type":"string","format":"uuid"},"federalTaxId":{"type":["string","null"]},"stateTaxId":{"type":["string","null"]},"filingFrequency":{"type":["string","null"],"enum":["monthly","quarterly","annual",null]},"fiscalYearEnd":{"type":["integer","null"],"minimum":1,"maximum":12},"entityType":{"type":["string","null"]},"accountingMethod":{"type":["string","null"],"enum":["cash","accrual","tbd",null],"description":"Override for the onboarding accounting-method answer. 'tbd' is rendered as \"TBD\" in the UI and maps from the onboarding 'unsure' choice; null means \"fall back to companies.accounting_method\"."},"stateOfIncorporation":{"type":["string","null"],"description":"Override for the onboarding state-of-incorporation answer. null means \"fall back to companies.state\"."},"notes":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"TaxSettingsHistoryEntry":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"ein":{"type":["string","null"]},"accountingMethod":{"type":["string","null"],"enum":["cash","accrual","tbd",null]},"stateOfIncorporation":{"type":["string","null"]},"taxYearEndMonth":{"type":["integer","null"],"minimum":1,"maximum":12},"stateTaxId":{"type":["string","null"]},"filingFrequency":{"type":["string","null"],"enum":["monthly","quarterly","annual",null]},"entityType":{"type":["string","null"]},"notes":{"type":["string","null"]},"changedByUserId":{"type":["string","null"],"format":"uuid"},"changeSource":{"type":"string","enum":["onboarding","settings_update","accountant_edit","migration"]},"changeReason":{"type":["string","null"]},"changedAt":{"type":"string","format":"date-time"}}},"TaxInformationFieldSource":{"type":"string","enum":["onboarding","settings","default"],"description":"Where the displayed value came from. 'onboarding' = what the customer entered during onboarding (companies table). 'settings' = an override in tax_settings. 'default' = neither source had a value and the field falls back to an app default (UI renders \"TBD\")."},"TaxInformation":{"type":"object","properties":{"companyId":{"type":"string","format":"uuid"},"ein":{"type":["string","null"]},"accountingMethod":{"type":["string","null"],"enum":["cash","accrual","tbd",null]},"state":{"type":["string","null"]},"taxYearEndMonth":{"type":["integer","null"],"minimum":1,"maximum":12},"sources":{"type":"object","properties":{"ein":{"$ref":"#/components/schemas/TaxInformationFieldSource"},"accountingMethod":{"$ref":"#/components/schemas/TaxInformationFieldSource"},"state":{"$ref":"#/components/schemas/TaxInformationFieldSource"},"taxYearEndMonth":{"$ref":"#/components/schemas/TaxInformationFieldSource"}}},"settings":{"$ref":"#/components/schemas/TaxSettings"},"history":{"type":"array","description":"Most recent change-history entries, newest first.","items":{"$ref":"#/components/schemas/TaxSettingsHistoryEntry"}}}},"UpdateTaxSettingsInput":{"type":"object","properties":{"federalTaxId":{"type":["string","null"],"maxLength":20},"stateTaxId":{"type":["string","null"],"maxLength":50},"filingFrequency":{"type":["string","null"],"enum":["monthly","quarterly","annual",null]},"fiscalYearEnd":{"type":["integer","null"],"minimum":1,"maximum":12},"entityType":{"type":["string","null"],"maxLength":50},"accountingMethod":{"type":["string","null"],"enum":["cash","accrual","tbd",null]},"stateOfIncorporation":{"type":["string","null"],"maxLength":100},"notes":{"type":["string","null"],"maxLength":2000},"changeReason":{"type":["string","null"],"maxLength":500,"description":"Optional free-text explanation stored alongside the history entry that captures the pre-update effective state."}}},"TaxSettingsResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TaxInformation"}}},"UpdateTaxSettingsResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TaxSettings"}}},"TaxDeadline":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"label":{"type":"string"},"dueDate":{"type":"string","format":"date"},"status":{"type":"string","enum":["completed","upcoming","pending"]}}},"CreateTaxDeadlineInput":{"type":"object","required":["label","dueDate"],"properties":{"label":{"type":"string","minLength":1,"maxLength":500},"dueDate":{"type":"string","format":"date","example":"2026-04-15"},"status":{"type":"string","enum":["completed","upcoming","pending"],"default":"upcoming"}}},"UpdateTaxDeadlineInput":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":500},"dueDate":{"type":"string","format":"date"},"status":{"type":"string","enum":["completed","upcoming","pending"]}}},"TaxDeadlineResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/TaxDeadline"}}},"TaxDeadlinesListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/TaxDeadline"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"IntegrationConnection":{"type":"object","required":["id","companyId","provider","category","status","entityId","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"provider":{"type":"string"},"category":{"type":"string"},"status":{"type":"string","enum":["connected","disconnected"]},"needsReauth":{"type":"boolean","description":"True when the provider requires the user to re-authorize before syncing can resume."},"awaitingOnboardingClassification":{"type":"boolean","enum":[true],"description":"Present (true) only on an onboarding Plaid link held until the owner reviews its accounts; it reads `disconnected` and nothing syncs until that commit. Absent otherwise."},"lastSyncAt":{"type":["string","null"],"format":"date-time"},"lastSyncAttemptAt":{"type":["string","null"],"format":"date-time","description":"Stamped at the start of every sync attempt, successful or not."},"lastWebhookReceivedAt":{"type":["string","null"],"format":"date-time","description":"Stamped when a matching provider webhook arrives."},"externalId":{"type":["string","null"],"description":"Provider's public account identifier (e.g. Stripe `acct_…`, Google Workspace account email). Not a credential — safe to expose to UI."},"entityId":{"type":"string","format":"uuid","description":"Immutable concrete legal-entity owner (#1170). Consolidated/group ownership is forbidden."},"entityName":{"type":["string","null"],"description":"Convenience display name resolved from the persisted entityId."},"entityRole":{"type":["string","null"],"description":"Convenience display role resolved from the persisted entityId."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateIntegrationConnectionInput":{"type":"object","required":["provider","category"],"properties":{"provider":{"type":"string","minLength":1,"maxLength":100},"category":{"type":"string","minLength":1,"maxLength":50},"status":{"type":"string","enum":["connected","disconnected"],"default":"connected"},"entityId":{"type":"string","format":"uuid","description":"Attach the connection to an authorized concrete legal entity (#1170). Omission is accepted only when the actor has exactly one authorized legal entity; ambiguous ownership fails validation."}}},"UpdateIntegrationConnectionInput":{"type":"object","properties":{"provider":{"type":"string","minLength":1,"maxLength":100},"category":{"type":"string","minLength":1,"maxLength":50},"status":{"type":"string","enum":["connected","disconnected"]},"lastSyncAt":{"type":["string","null"],"format":"date-time"}}},"IntegrationConnectionResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/IntegrationConnection"}}},"IntegrationConnectionsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/IntegrationConnection"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"IntegrationAccount":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid","description":"Immutable legal-entity owner inherited from the parent integration connection."},"integrationId":{"type":"string","format":"uuid"},"provider":{"type":"string"},"externalId":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"currency":{"type":"string"},"glAccountId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"}}},"CreateIntegrationAccountInput":{"type":"object","required":["provider","externalId","name","type"],"properties":{"provider":{"type":"string","minLength":1,"maxLength":100},"externalId":{"type":"string","minLength":1,"maxLength":255},"name":{"type":"string","minLength":1,"maxLength":255},"type":{"type":"string","minLength":1,"maxLength":50},"currency":{"type":"string","minLength":3,"maxLength":3,"default":"USD"},"glAccountId":{"type":"string","format":"uuid"}}},"UpdateIntegrationAccountInput":{"type":"object","properties":{"glAccountId":{"type":["string","null"],"format":"uuid"}}},"IntegrationAccountResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/IntegrationAccount"}}},"IntegrationAccountsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/IntegrationAccount"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"ExternalTransaction":{"type":"object","required":["id","companyId","entityId","integrationId","provider","externalId","occurredAt","payload","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid","description":"Immutable concrete legal-entity owner."},"integrationId":{"type":["string","null"],"format":"uuid","description":"Exact source connection, or null for a source-unlinked manual event."},"provider":{"type":"string"},"externalId":{"type":"string"},"occurredAt":{"type":"string","format":"date-time"},"payload":{"type":"object","additionalProperties":true},"createdAt":{"type":"string","format":"date-time"}}},"CreateExternalTransactionInput":{"type":"object","required":["entityId","provider","externalId","occurredAt","payload"],"properties":{"entityId":{"type":"string","format":"uuid"},"integrationId":{"type":["string","null"],"format":"uuid","description":"Required for Plaid and Stripe provider events."},"provider":{"type":"string","minLength":1,"maxLength":100},"externalId":{"type":"string","minLength":1,"maxLength":255},"occurredAt":{"type":"string","format":"date-time"},"payload":{"type":"object","additionalProperties":true}}},"ExternalTransactionResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ExternalTransaction"}}},"ExternalTransactionsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ExternalTransaction"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"Recommendation":{"type":"object","required":["currency","minorUnitExponent"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"priority":{"type":"string","enum":["HIGH","MEDIUM"]},"category":{"type":"string"},"title":{"type":"string"},"summary":{"type":"string"},"details":{"type":["object","null"],"additionalProperties":true},"action":{"type":["string","null"]},"investmentCents":{"type":["integer","null"]},"expectedAnnualReturnCents":{"type":["integer","null"]},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer","const":2},"timeframe":{"type":["string","null"]},"confidencePct":{"type":["number","null"]},"dataSource":{"type":["string","null"]},"status":{"type":"string","enum":["pending","active","completed","dismissed"]},"dismissedReason":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"completedAt":{"type":["string","null"],"format":"date-time"}}},"CreateRecommendationInput":{"type":"object","required":["priority","category","title","summary","currency"],"properties":{"priority":{"type":"string","enum":["HIGH","MEDIUM"]},"category":{"type":"string","minLength":1,"maxLength":100},"title":{"type":"string","minLength":1,"maxLength":500},"summary":{"type":"string","minLength":1,"maxLength":5000},"details":{"type":"object","additionalProperties":true},"action":{"type":"string","maxLength":1000},"investmentCents":{"type":"integer","minimum":0},"expectedAnnualReturnCents":{"type":"integer"},"currency":{"type":"string","minLength":3,"maxLength":3,"pattern":"^[A-Za-z]{3}$","description":"Accepted case-insensitively and normalized to uppercase by the server."},"timeframe":{"type":"string","maxLength":200},"confidencePct":{"type":"number","minimum":0,"maximum":100},"dataSource":{"type":"string","maxLength":200}}},"UpdateRecommendationInput":{"type":"object","properties":{"priority":{"type":"string","enum":["HIGH","MEDIUM"]},"category":{"type":"string"},"title":{"type":"string"},"summary":{"type":"string"},"details":{"type":["object","null"],"additionalProperties":true},"action":{"type":["string","null"]},"investmentCents":{"type":["integer","null"]},"expectedAnnualReturnCents":{"type":["integer","null"]},"currency":{"type":"string","minLength":3,"maxLength":3,"pattern":"^[A-Za-z]{3}$","description":"Accepted case-insensitively and normalized to uppercase by the server."},"timeframe":{"type":["string","null"]},"confidencePct":{"type":["number","null"]},"dataSource":{"type":["string","null"]},"status":{"type":"string","enum":["pending","active","completed","dismissed"]},"dismissedReason":{"type":["string","null"]}}},"RecommendationResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Recommendation"}}},"RecommendationsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Recommendation"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"ScheduleProposalStatus":{"type":"string","enum":["proposed","pending_review","approved","rejected","blocked","posted","superseded","expired"]},"ScheduleProposalAccountRef":{"type":"object","description":"Account reference (role preferred) with a resolved snapshot.","properties":{"role":{"type":["string","null"]},"code":{"type":["string","null"]},"name":{"type":["string","null"]},"glAccountId":{"type":["string","null"]}}},"ScheduleProposalLeg":{"type":"object","required":["account","side"],"properties":{"account":{"$ref":"#/components/schemas/ScheduleProposalAccountRef"},"side":{"type":"string","enum":["debit","credit"]}}},"ScheduleProposal":{"type":"object","description":"One AI-detected deferral/accrual candidate with its derived schedule inputs and confidence. Never a book write on its own; materialization (#1266 Phase B) turns approved proposals into schedule definitions.","properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":["string","null"],"format":"uuid"},"currency":{"type":["string","null"]},"proposalType":{"type":"string","enum":["deferral","accrual"]},"kind":{"type":"string","enum":["prepaid_amortization","deferred_revenue_recognition","accrual"]},"derivedInputs":{"type":"object","description":"Zod-validated derived inputs (per-type schema; legs are ScheduleProposalLeg items).","additionalProperties":true},"totalAmountCents":{"type":"integer"},"startDate":{"type":"string","format":"date"},"endDate":{"type":["string","null"],"format":"date"},"confidencePct":{"type":"number"},"confidenceBand":{"type":"string","enum":["high","medium","low"]},"confidenceComponents":{"type":"object","additionalProperties":true},"detectionSignals":{"type":"object","additionalProperties":true},"reasoning":{"type":["string","null"]},"sourceKind":{"type":"string"},"sourceId":{"type":["string","null"]},"dedupKey":{"type":"string"},"inputHash":{"type":"string"},"matchKey":{"type":["string","null"]},"status":{"$ref":"#/components/schemas/ScheduleProposalStatus"},"blockedReason":{"type":["string","null"]},"escalatedAt":{"type":["string","null"],"format":"date-time"},"escalationReason":{"type":["string","null"]},"metadata":{"type":"object","properties":{"clarification":{"$ref":"#/components/schemas/ScheduleProposalClarification"}},"additionalProperties":true},"reviewedBy":{"type":["string","null"],"format":"uuid"},"reviewedAt":{"type":["string","null"],"format":"date-time"},"reviewNotes":{"type":["string","null"]},"editedInputs":{"type":["object","null"],"additionalProperties":true},"scheduleDefinitionIds":{"type":["array","null"],"items":{"type":"string","format":"uuid"}},"postedJeId":{"type":["string","null"],"format":"uuid"},"createdBy":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ScheduleProposalTimelineEntry":{"type":"object","properties":{"id":{"type":"string"},"actorUserId":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"changes":{"type":"object","description":"The decision payload (eventType, actorType, subAgent, confidence, before/after snapshots).","additionalProperties":true}}},"ScheduleProposalListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleProposal"}},"nextCursor":{"type":["string","null"]},"hasMore":{"type":"boolean"}}}}},"ScheduleProposalDetailResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"allOf":[{"$ref":"#/components/schemas/ScheduleProposal"},{"type":"object","properties":{"timeline":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleProposalTimelineEntry"}}}}]}}},"ScheduleProposalResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ScheduleProposal"}}},"ScheduleProposalQaIssue":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"role":{"type":"string"}}},"ScheduleProposalRecheckResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["outcome","proposal","issues"],"properties":{"outcome":{"type":"string","enum":["still_blocked","pending_review"]},"proposal":{"$ref":"#/components/schemas/ScheduleProposal"},"issues":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleProposalQaIssue"}}}}}},"ScheduleProposalRecoveryArtifacts":{"type":"object","additionalProperties":false,"required":["definitionIds","runIds","openingJournalEntryIds","postedRunJournalEntryIds"],"properties":{"definitionIds":{"type":"array","maxItems":16,"items":{"type":"string","format":"uuid"}},"runIds":{"type":"array","maxItems":512,"items":{"type":"string","format":"uuid"}},"openingJournalEntryIds":{"type":"array","maxItems":512,"items":{"type":"string","format":"uuid"}},"postedRunJournalEntryIds":{"type":"array","maxItems":512,"items":{"type":"string","format":"uuid"}}}},"ScheduleProposalRecovery":{"type":"object","additionalProperties":false,"required":["proposalId","status","revision","incidentReason","recoveryTaskId","artifacts","requirements","resolution","resolvedAt","resolvedBy"],"properties":{"proposalId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","resolved"]},"revision":{"type":"string","pattern":"^[a-f0-9]{64}$"},"incidentReason":{"type":"string"},"recoveryTaskId":{"type":["string","null"],"format":"uuid"},"artifacts":{"$ref":"#/components/schemas/ScheduleProposalRecoveryArtifacts"},"requirements":{"type":"object","additionalProperties":false,"required":["correctionJournalEntryRequired","originalsMustBeVoided","definitionsMustBeInactive"],"properties":{"correctionJournalEntryRequired":{"type":"boolean"},"originalsMustBeVoided":{"type":"boolean"},"definitionsMustBeInactive":{"type":"boolean","const":true}}},"resolution":{"type":["object","null"],"additionalProperties":false,"required":["mode","correctionJournalEntryId"],"properties":{"mode":{"type":"string","enum":["originals_voided","net_negating_correction"]},"correctionJournalEntryId":{"type":["string","null"],"format":"uuid"}}},"resolvedAt":{"type":["string","null"],"format":"date-time"},"resolvedBy":{"type":["string","null"],"format":"uuid"}}},"ScheduleProposalRecoveryResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ScheduleProposalRecovery"}}},"ResolveScheduleProposalRecoveryInput":{"type":"object","additionalProperties":false,"required":["expectedRevision"],"properties":{"expectedRevision":{"type":"string","pattern":"^[a-f0-9]{64}$"},"correctionJournalEntryId":{"type":"string","format":"uuid"},"note":{"type":"string","minLength":1,"maxLength":2000}}},"ScheduleProposalRecoveryTask":{"type":"object","required":["id","companyId","accountantId","type","sourceKey","priority","status"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"accountantId":{"type":"string","format":"uuid"},"title":{"type":"string"},"description":{"type":["string","null"]},"type":{"type":"string","const":"schedule_proposal_recovery"},"sourceKey":{"type":"string"},"priority":{"type":"string","const":"high"},"status":{"type":"string","enum":["pending","in_progress","completed","cancelled"]},"dueDate":{"type":["string","null"],"format":"date-time"},"completedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ScheduleProposalRecoveryResolutionResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":false,"required":["recovery","proposal","task"],"properties":{"recovery":{"$ref":"#/components/schemas/ScheduleProposalRecovery"},"proposal":{"$ref":"#/components/schemas/ScheduleProposal"},"task":{"oneOf":[{"$ref":"#/components/schemas/ScheduleProposalRecoveryTask"},{"type":"null"}]}}}}},"ScheduleProposalMaterialization":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["posted","already_posted","approved_not_materialized","blocked"]},"reason":{"type":"string","description":"Present when a gate or deterministic QA check prevents a write."},"scheduleDefinitionIds":{"type":"array","items":{"type":"string","format":"uuid"}},"postedJeId":{"type":["string","null"],"format":"uuid"}}},"ScheduleProposalApprovalResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"allOf":[{"$ref":"#/components/schemas/ScheduleProposal"},{"type":"object","properties":{"materialization":{"$ref":"#/components/schemas/ScheduleProposalMaterialization"}}}]}}},"SchedulePreviewInput":{"type":"object","required":["startDate","totalAmountCents"],"properties":{"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"totalPeriods":{"type":"integer","minimum":1,"description":"Optional when endDate is given (derived from the calendar span)."},"totalAmountCents":{"type":"integer","minimum":0},"frequency":{"type":"string","enum":["monthly","quarterly","annual","weekly"],"default":"monthly"},"allocationMethod":{"type":"string","enum":["equal","daily_prorated"],"default":"equal"}}},"SchedulePreviewRun":{"type":"object","properties":{"sequenceNum":{"type":"integer"},"scheduledDate":{"type":"string","format":"date"},"amountCents":{"type":"integer"},"runParams":{"type":"object","additionalProperties":true}}},"SchedulePreviewResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"runs":{"type":"array","items":{"$ref":"#/components/schemas/SchedulePreviewRun"}}}}}},"ScheduleProposalSweepInput":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["deferral","accrual"]},"periodEndDate":{"type":"string","format":"date"}}},"ScheduleProposalSweepResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"status":{"type":"string","enum":["not_available","ran"]},"type":{"type":"string","enum":["deferral","accrual"]},"result":{"type":["object","null"],"additionalProperties":true}}}}},"MonthEndRunDetectionInput":{"type":"object","additionalProperties":false,"required":["periodId"],"properties":{"periodId":{"type":"string","format":"uuid","description":"The GL period to detect accruals and deferrals for."}}},"MonthEndRunDetectionResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["status","periodId","periodEndDate","proposalsCreated","blocked","superseded","approvedBlocked","candidatesEvaluated","skipped"],"properties":{"status":{"type":"string","enum":["completed","partial","detection_off","timed_out","not_available"],"description":"`completed`: every candidate was judged. `partial`: some candidates could not be judged (see `skipped`). `detection_off`: the company's detection flag is off. `timed_out`: the 20-second budget ran out. `not_available`: the detector stack is not wired here. All counts are 0 unless the status is `completed` or `partial`."},"periodId":{"type":"string","format":"uuid"},"periodEndDate":{"type":"string","format":"date"},"proposalsCreated":{"type":"integer","description":"New proposals awaiting review."},"blocked":{"type":"integer","description":"New proposals the QA gate created as `blocked` (for example a missing account)."},"superseded":{"type":"integer","description":"Older live proposals superseded because their real charge has posted."},"approvedBlocked":{"type":"integer","description":"Approved-but-unposted proposals moved to `blocked` because their real charge has posted."},"candidatesEvaluated":{"type":"integer"},"skipped":{"type":"object","description":"Candidates the detector could not judge. Any non-zero entry makes the run `partial`.","required":["modelUnavailable","qaInvalid","unsupportedCurrency","unresolvedCounterparty","scopeBlocked"],"properties":{"modelUnavailable":{"type":"integer","description":"The model call failed, timed out, was over the company's budget, or is not configured."},"qaInvalid":{"type":"integer"},"unsupportedCurrency":{"type":"integer"},"unresolvedCounterparty":{"type":"integer"},"scopeBlocked":{"type":["string","null"],"description":"Set when the whole sweep was refused because the company's records are not tied to a single legal entity."}}}}}}},"ApproveScheduleProposalInput":{"type":"object","properties":{"editedInputs":{"type":"object","additionalProperties":true,"description":"Optional replacement derived inputs (validated per proposal type; 422 on schema violations)."},"reviewNotes":{"type":"string"}}},"RejectScheduleProposalInput":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","minLength":1}}},"SubscriptionInterval":{"type":"string","enum":["daily","weekly","monthly","quarterly","annual"],"description":"Detected (or manually set) billing cadence. The detector only writes one of these five values when confidence >= 80%; otherwise the row is not persisted as a subscription."},"Subscription":{"type":"object","required":["id","companyId","name","vendor","category","amountCents","currency","minorUnitExponent","billingFrequency","status","transactionCount","totalSpentCents","detectionSource"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"name":{"type":"string"},"vendor":{"type":"string"},"category":{"type":"string"},"amountCents":{"type":"integer","minimum":0,"maximum":9007199254740991},"currency":{"type":"string","minLength":3,"maxLength":3,"description":"Explicit supported scale-two ISO 4217 currency authority."},"minorUnitExponent":{"type":"integer","const":2},"billingFrequency":{"type":"string","enum":["monthly","annual"],"description":"Coarse cadence used by the legacy manual-CRUD path. For the detector-populated cadence, prefer `interval`."},"nextChargeOn":{"type":["string","null"],"format":"date"},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"merchantName":{"type":["string","null"]},"interval":{"oneOf":[{"$ref":"#/components/schemas/SubscriptionInterval"},{"type":"null"}]},"firstSeenAt":{"type":["string","null"],"format":"date-time"},"lastSeenAt":{"type":["string","null"],"format":"date-time"},"nextExpectedAt":{"type":["string","null"],"format":"date-time"},"transactionCount":{"type":"integer"},"totalSpentCents":{"type":"integer","minimum":0,"maximum":9007199254740991},"detectionSource":{"type":"string","enum":["auto","manual"]},"updatedAt":{"type":"string","format":"date-time"}}},"CreateSubscriptionInput":{"type":"object","required":["name","vendor","category","amountCents","currency","billingFrequency"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"vendor":{"type":"string","minLength":1,"maxLength":255},"category":{"type":"string","minLength":1,"maxLength":100},"amountCents":{"type":"integer","minimum":0,"maximum":9007199254740991},"currency":{"type":"string","minLength":3,"maxLength":3,"description":"Explicit supported scale-two ISO 4217 currency authority."},"billingFrequency":{"type":"string","enum":["monthly","annual"]},"nextChargeOn":{"type":"string","format":"date"},"status":{"type":"string","maxLength":50,"default":"active"}}},"UpdateSubscriptionInput":{"type":"object","properties":{"name":{"type":"string"},"vendor":{"type":"string"},"category":{"type":"string"},"amountCents":{"type":"integer","minimum":0,"maximum":9007199254740991},"currency":{"type":"string","minLength":3,"maxLength":3},"billingFrequency":{"type":"string","enum":["monthly","annual"]},"nextChargeOn":{"type":["string","null"],"format":"date"},"status":{"type":"string"}}},"SubscriptionResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Subscription"}}},"CheckoutSubscriptionPlan":{"type":"object","required":["id","name","priceCents","interval","features"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"priceCents":{"type":"integer","minimum":0},"interval":{"type":"string","enum":["month","year"]},"features":{"type":"array","items":{"type":"string"}}}},"CheckoutSubscriptionBilling":{"type":"object","description":"What Stripe actually charges the subscription each period. Differs from\nthe plan's list price whenever a coupon applies — a comped company has\nan effectiveAmountCents of 0 against a non-zero listAmountCents.\n","required":["listAmountCents","effectiveAmountCents","interval","discountLabel","trialEndsAt","discountEndsAt"],"properties":{"listAmountCents":{"type":"integer","minimum":0},"effectiveAmountCents":{"description":"The recurring charge each period once billing starts. While\ntrialEndsAt is set this amount is not yet being charged.\n","type":"integer","minimum":0},"interval":{"type":"string","enum":["month","year"]},"discountLabel":{"type":["string","null"]},"trialEndsAt":{"description":"Date the trial ends and effectiveAmountCents starts being charged.\nNon-null means nothing is due until then, and clients must show both\nthe zero due now and the recurring amount with this date.\n","type":["string","null"],"format":"date-time"},"discountEndsAt":{"description":"Date the coupon expires and listAmountCents resumes. Null when the\ncoupon runs for the life of the subscription.\n","type":["string","null"],"format":"date-time"}}},"CheckoutSubscriptionPaymentMethod":{"type":"object","required":["brand","last4","expMonth","expYear"],"properties":{"brand":{"type":"string"},"last4":{"type":"string"},"expMonth":{"type":["integer","null"],"minimum":1,"maximum":12},"expYear":{"type":["integer","null"]}}},"CheckoutSubscriptionResponse":{"type":"object","required":["id","companyId","status","stripeSubscriptionStatus","platformItemState","platformItemId","providerObservedAt","platformTermsVerifiedAt","stripeSubscriptionId","stripePriceId","currentPeriodStart","currentPeriodEnd","cancelledAt","planTier","plan","billing","paymentMethod","paymentMethodStatus","paymentMethodSummary","source"],"properties":{"id":{"type":["string","null"],"format":"uuid"},"companyId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["active","past_due","cancelled","trialing","incomplete","needs_attention"],"description":"Missing or ambiguous platform items project needs_attention; cancellation takes precedence."},"stripeSubscriptionStatus":{"type":["string","null"],"description":"Exact provider status from the last observation."},"platformItemState":{"type":"string","enum":["unverified","present","missing","ambiguous"]},"platformItemId":{"type":["string","null"]},"providerObservedAt":{"type":["string","null"],"format":"date-time"},"platformTermsVerifiedAt":{"type":["string","null"],"format":"date-time"},"stripeSubscriptionId":{"type":["string","null"]},"stripePriceId":{"type":["string","null"]},"currentPeriodStart":{"type":["string","null"],"format":"date-time"},"currentPeriodEnd":{"type":["string","null"],"format":"date-time"},"cancelledAt":{"type":["string","null"],"format":"date-time"},"planTier":{"type":["string","null"]},"plan":{"oneOf":[{"$ref":"#/components/schemas/CheckoutSubscriptionPlan"},{"type":"null"}]},"billing":{"description":"Null when the billed amount cannot be read from Stripe (no\nsubscription, or Stripe unavailable). Clients must not present the\nplan's list price as the billed amount in that case.\n","oneOf":[{"$ref":"#/components/schemas/CheckoutSubscriptionBilling"},{"type":"null"}]},"paymentMethod":{"oneOf":[{"$ref":"#/components/schemas/CheckoutSubscriptionPaymentMethod"},{"type":"null"}]},"paymentMethodStatus":{"type":"string","enum":["available","none","unavailable","not_configured"],"description":"Whether Stripe returned a payment method, confirmed that none is\nconfigured, or could not establish the answer. The not_configured\nstate means the company has no Stripe customer id; show \"No Stripe\nbilling on file\" without a Stripe portal action. An unavailable\nresult must not be presented as \"No payment method\". Neither state\npermits displaying the stored payment-method summary as current.\n"},"paymentMethodSummary":{"type":["string","null"]},"source":{"type":"string","enum":["median_subscription","stripe_resync","billing_plan_fallback"]}}},"SubscriptionsListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Subscription"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"BillingPlan":{"type":"object","properties":{"companyId":{"type":"string","format":"uuid"},"planName":{"type":"string"},"status":{"type":"string"},"paymentMethodSummary":{"type":["string","null"]},"updatedAt":{"type":"string","format":"date-time"}}},"UpdateBillingPlanInput":{"type":"object","properties":{"planName":{"type":"string","minLength":1,"maxLength":100},"status":{"type":"string","minLength":1,"maxLength":50},"paymentMethodSummary":{"type":["string","null"],"maxLength":500}}},"BillingPlanResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/BillingPlan"}}},"PaginationMeta":{"type":"object","properties":{"nextCursor":{"type":["string","null"]},"hasMore":{"type":"boolean"}}},"ProblemDetail":{"type":"object","properties":{"type":{"type":"string"},"title":{"type":"string","description":"For application errors, a stable UPPER_SNAKE machine code (for example `NOT_FOUND`, `FORECAST_NOT_FOUND`, `VALIDATION_ERROR`). Clients branch on this, never on `detail` wording. A few transport level responses use a short human title instead.\n"},"status":{"type":"integer"},"detail":{"type":"string","description":"Human-readable explanation; correlate a failure with `traceId`. A NOT_FOUND-family 404 names the resource type (for example \"Company not found\"), not its id. Some legacy messages still include an id (tracked in #2666).\n"},"instance":{"type":"string"},"traceId":{"type":"string"},"retryAfter":{"type":"integer","minimum":0,"description":"Whole seconds until retry is allowed for a 429 response"},"errors":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}}}},"extensions":{"type":"object","additionalProperties":true}}},"ApiErrorResponse":{"type":"object","required":["success","error"],"properties":{"success":{"type":"boolean","enum":[false]},"error":{"$ref":"#/components/schemas/ProblemDetail"}}},"CreateBusinessEventRequest":{"type":"object","description":"Business rules (supported event type, resolvable accounts, postable period/account) are enforced by the controller and the resolve-time posting guard, not this schema. Unknown extra keys are allowed.\n","properties":{"idempotencyKey":{"type":"string","minLength":1,"maxLength":128,"description":"Optional trimmed client operation key, unique per company. Retain it across retries; use a new key for a new intentional operation. Keyless legacy creates remain separate. Customer creates compare canonical request values (object key order ignored) and bind the authorized primary entity; unfinished creates require review and cannot be retried as new postings."},"eventType":{"type":"string","minLength":1,"maxLength":100,"description":"Generator key, e.g. adjusting_entry. Defaults to \"custom\" when absent."},"title":{"type":"string","maxLength":300},"description":{"type":["string","null"],"maxLength":5000},"amountCents":{"type":"integer"},"eventDate":{"type":"string","description":"ISO date (YYYY-MM-DD). Derived from parameters or today when absent."},"parameters":{"type":"object","additionalProperties":true,"description":"Generator parameters (e.g. debitAccount, creditAccount, amount)."},"allowWithoutJournalEntry":{"type":"boolean","description":"Opt into the save-now/fix-later flow — the event saves with metadata.jeGenerationSkipped naming the blocker instead of the request failing with 422.\n"},"entityId":{"type":"string","format":"uuid"}}},"UpdateBusinessEventRequest":{"type":"object","description":"Only unposted events (no journal entry, no schedule) can be edited.","properties":{"eventType":{"type":"string","minLength":1,"maxLength":100},"title":{"type":"string","maxLength":300},"description":{"type":["string","null"],"maxLength":5000},"eventDate":{"type":"string"},"parameters":{"type":"object","additionalProperties":true}}},"BusinessEventListMeta":{"type":"object","description":"Cursor pagination envelope meta on business-event lists.","required":["nextCursor","hasMore"],"properties":{"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` to fetch the next page; null on the last page."},"hasMore":{"type":"boolean"}}},"BusinessEventWire":{"type":"object","description":"A business event with its generated preview lines and any posted journal entries. jeGenerationSkipped/jeGenerationError explain a null journalEntryId — skipped means a known, named blocker (or metadata-only event); error means an unexpected posting failure.\n","properties":{"idempotentReplay":{"type":"boolean","description":"True when a completed create operation was returned without creating or posting again. Posting failures/skips retain their own fields."},"id":{"type":"string","format":"uuid"},"customerId":{"type":"string","format":"uuid","description":"The company id (wire name kept for accountant-app compatibility)."},"eventType":{"type":"string"},"status":{"type":"string"},"parameters":{"type":"object","additionalProperties":true},"journalEntryId":{"type":["string","null"],"format":"uuid"},"generatedEntries":{"type":"array","items":{"type":"object","properties":{"account":{"type":"string"},"accountNumber":{"type":["string","null"]},"debit":{"type":"number"},"credit":{"type":"number"},"memo":{"type":"string"}}}},"generatedJEs":{"type":"array","items":{"type":"object","additionalProperties":true}},"journalEntryState":{"type":"string","enum":["posted","not_posted","void","deleted","missing","mixed"],"description":"Consolidated state of every journal entry owned by this event."},"journalEntryStateCounts":{"type":"object","required":["posted","void","deleted","missing"],"properties":{"posted":{"type":"integer","minimum":0},"void":{"type":"integer","minimum":0},"deleted":{"type":"integer","minimum":0},"missing":{"type":"integer","minimum":0}}},"jeGenerationSkipped":{"type":"string","description":"Why journal-entry generation was skipped (named blocker, unresolved accounts, or metadata-only event)."},"jeGenerationError":{"type":"string","description":"Unexpected posting failure recorded by the residual safety net (also captured to Sentry)."},"payablesApItemId":{"type":"string","format":"uuid","description":"#2529: the Payables (AP) item a posted vendor bill created or linked; its initial journal entry is this event's journal entry."},"unresolvedAccounts":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":["string","null"]}}},"DataRepairRequest":{"type":"object","additionalProperties":false,"properties":{"companyId":{"type":"string","format":"uuid","description":"Scope. Omitted = fleet-wide, which is allowed for dry-run only."},"apply":{"type":"boolean","default":false,"description":"false = dry-run; report proposals, touch nothing."},"confirm":{"type":"string","maxLength":200,"description":"Must be exactly `REPAIR <companyId>` when apply is true."},"maxActions":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"Cap on void operations per request. Selection excludes already-voided rows — repeat until the ledger reports zero remaining.\n"}}},"DataRepairLedgerResponse":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","description":"JSON change ledger. Shared fields listed here; each repair adds its own counters (pairsFound/voidable/remainingVoidable for the Ramp repair; duplicateGroups/surplusEntries/remainingSurplus for the bill-accrual repair) plus its full proposal list.\n","required":["repairRun","mode","attempted","voided","failures","proposals"],"additionalProperties":true,"properties":{"repairRun":{"type":"string","description":"Stable identifier stamped on every void's audit trail."},"mode":{"type":"string","enum":["dry-run","apply"]},"companiesScanned":{"description":"The requested scope, or \"all\" for a fleet-wide dry-run.","oneOf":[{"type":"array","items":{"type":"string","format":"uuid"}},{"type":"string","enum":["all"]}]},"attempted":{"type":"integer","description":"Void operations attempted this run (bounded by maxActions)."},"voided":{"type":"integer"},"failures":{"type":"array","items":{"type":"object","additionalProperties":true}},"proposals":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}},"CreateServiceApiKeyInput":{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":100},"expiresInDays":{"type":"integer","minimum":1,"maximum":7,"description":"Requested lifetime in days, at most 7 (#1147). The server also caps it at its configured service-key default.\n"}}},"ServiceApiKey":{"type":"object","required":["id","companyId","name","prefix","scopes","createdByUserId","lastUsedAt","expiresAt","revokedAt","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid","description":"Configured service-key home company; not caller-selectable."},"name":{"type":"string"},"prefix":{"type":"string","description":"Non-secret lookup prefix; never the complete credential."},"scopes":{"type":"array","items":{"type":"string"},"description":"Newly issued service keys receive exactly accountant:*."},"createdByUserId":{"type":"string","format":"uuid","description":"Configured non-human service-principal user id."},"issuedByUserId":{"type":["string","null"],"format":"uuid","description":"Human allowlisted super-admin who issued the key."},"lastUsedAt":{"type":["string","null"],"format":"date-time"},"expiresAt":{"type":["string","null"],"format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"},"revokedByUserId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"usageCountLast24h":{"type":"integer","minimum":0},"usageCountLast7d":{"type":"integer","minimum":0}}},"CreatedServiceApiKey":{"allOf":[{"$ref":"#/components/schemas/ServiceApiKey"},{"type":"object","required":["plainTextKey"],"properties":{"plainTextKey":{"type":"string","pattern":"^mdn_svc_v1_[A-Za-z0-9_-]{43}_[0-9a-f]{8}$","description":"Returned once. Store in a secrets manager before discarding the response. Format (#1147): `mdn_svc_v1_` + base64url of 32 random bytes + `_` + 8 lowercase hex CRC-32 of everything before the final underscore. Service keys minted before this format (`mdn_live_`) keep verifying until they expire or are revoked.\n"}}}]},"ServiceApiKeyResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/ServiceApiKey"}}},"CreatedServiceApiKeyResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/CreatedServiceApiKey"}}},"ServiceApiKeyListResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","additionalProperties":false,"required":["items","nextCursor","hasMore"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ServiceApiKey"}},"nextCursor":{"type":["string","null"]},"hasMore":{"type":"boolean"}}}}},"CreateCreditNoteInput":{"type":"object","additionalProperties":false,"required":["type","date","counterpartyName","description","amountCents"],"properties":{"type":{"type":"string","enum":["received","issued"]},"number":{"type":"string","minLength":1},"date":{"type":"string","format":"date"},"counterpartyName":{"type":"string","minLength":1},"description":{"type":"string","minLength":1},"amountCents":{"type":"integer","minimum":1},"currency":{"type":"string","minLength":3,"maxLength":3},"appliedToInvoiceId":{"type":"string","format":"uuid"}}},"UpdateCreditNoteInput":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"counterpartyName":{"type":"string","minLength":1},"description":{"type":"string","minLength":1},"amountCents":{"type":"integer","minimum":1},"date":{"type":"string","format":"date"}}},"IssueCreditNoteInput":{"type":"object","additionalProperties":false,"required":["apAccountId","arAccountId","expenseAccountId","revenueAccountId"],"properties":{"apAccountId":{"type":"string","format":"uuid"},"arAccountId":{"type":"string","format":"uuid"},"expenseAccountId":{"type":"string","format":"uuid"},"revenueAccountId":{"type":"string","format":"uuid"}}},"RecognitionMarker":{"type":"object","description":"How a document (invoice revenue or bill expense) is recognized. `immediate` = single-period recognition; `amortize` = spread across `months` calendar periods via an entity-keyed schedule; `unavailable` means the legacy schedule source cannot authorize the selected entity.\n","required":["type"],"properties":{"type":{"type":"string","enum":["immediate","amortize","unavailable"]},"months":{"type":"integer","description":"Only present when type = amortize. Total periods in the schedule."},"monthsPosted":{"type":"integer","description":"Only present when type = amortize. Posted schedule runs."},"reason":{"type":"string","enum":["schedule_authority_not_entity_scoped"],"description":"Only present when type = unavailable."}}},"SubLedgerInvoiceRow":{"type":"object","required":["id","amountCents","recognition"],"properties":{"id":{"type":"string","format":"uuid"},"number":{"type":["string","null"]},"docDate":{"type":["string","null"],"format":"date"},"amountCents":{"type":"integer"},"customerName":{"type":["string","null"]},"recognition":{"$ref":"#/components/schemas/RecognitionMarker"}}},"SubLedgerBillRow":{"type":"object","required":["id","amountCents","recognition"],"properties":{"id":{"type":"string","format":"uuid"},"number":{"type":["string","null"]},"docDate":{"type":["string","null"],"format":"date"},"amountCents":{"type":"integer"},"vendorName":{"type":["string","null"]},"categoryGlAccountId":{"type":["string","null"],"format":"uuid"},"categoryGlAccountName":{"type":["string","null"]},"recognition":{"$ref":"#/components/schemas/RecognitionMarker"}}},"SubLedgerDirectRow":{"type":"object","required":["id","occurredOn","amountCents","description"],"properties":{"id":{"type":"string","format":"uuid"},"occurredOn":{"type":"string","format":"date"},"amountCents":{"type":"integer"},"description":{"type":"string"},"categoryGlAccountId":{"type":["string","null"],"format":"uuid"}}},"SubLedgerChartPoint":{"type":"object","required":["label","recognizedCents","bookedCents"],"properties":{"label":{"type":"string","description":"Month label in YYYY-MM format"},"recognizedCents":{"type":"integer"},"bookedCents":{"type":"integer"}}},"SubLedgerRevenueGroup":{"type":"object","required":["name","recognizedCents","deferredCents","bookedCents","invoices","direct"],"properties":{"name":{"type":"string","description":"Customer name (invoice customer, or the Stripe/QBO customer on a direct receipt); receipts with no customer are grouped per account as \"Receipts without a customer · {account}\". \"(Unknown)\" for an invoice with no customer."},"recognizedCents":{"type":["integer","null"],"description":"null when invoice-level recognition timing lacks entity authority."},"deferredCents":{"type":["integer","null"],"description":"null when invoice-level recognition timing lacks entity authority."},"bookedCents":{"type":"integer"},"invoices":{"type":"array","items":{"$ref":"#/components/schemas/SubLedgerInvoiceRow"}},"direct":{"type":"array","items":{"$ref":"#/components/schemas/SubLedgerDirectRow"}}}},"SubLedgerExpenseGroup":{"type":"object","required":["name","bookedCents","bills","direct"],"properties":{"categoryGlAccountId":{"type":["string","null"],"format":"uuid"},"name":{"type":"string","description":"GL account name, or \"(Uncategorized)\""},"bookedCents":{"type":"integer"},"bills":{"type":"array","items":{"$ref":"#/components/schemas/SubLedgerBillRow"}},"direct":{"type":"array","items":{"$ref":"#/components/schemas/SubLedgerDirectRow"}}}},"SubLedgerRange":{"type":"object","required":["startDate","endDate","monthsInRange"],"properties":{"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"monthsInRange":{"type":"integer"}}},"SubLedgerRevenueTiles":{"type":"object","required":["recognizedCents","bookedCents","deferredCarryingCents"],"properties":{"recognizedCents":{"type":"integer","description":"Operating revenue recognized in the range: /reports/pl totalRevenue (which excludes other income since #2745) minus 4999 Uncategorized Income (answered 2026-09-24), so the page ties to the Books hub.\n"},"bookedCents":{"type":"integer","description":"Sum of processed/reviewed invoices (by docDate) plus direct operating-revenue transactions in range. A receipt whose journal entries were all voided is not booked.\n"},"deferredCarryingCents":{"type":"integer","description":"Cumulative GL balance of deferred-revenue liability accounts (detail type or name) at range.end (point-in-time carrying).\n"},"uncategorizedIncomeCents":{"type":"integer","description":"4999 Uncategorized Income recognized in the range, shown apart from revenue (\"Excluded from Revenue until categorized\").\n"}}},"SubLedgerExpensesTiles":{"type":"object","required":["recognizedCents","bookedCents","prepaidCarryingCents","accruedCarryingCents"],"properties":{"recognizedCents":{"type":"integer","description":"Sum of posted JE debits on Expense GL accounts within the range. Equals /reports/pl totalExpenses × 100 within 1 cent.\n"},"bookedCents":{"type":"integer","description":"Sum of processed/reviewed bills (by docDate) plus direct expense-categorized transactions in range.\n"},"prepaidCarryingCents":{"type":"integer","description":"Cumulative GL balance of Prepaid Expense asset accounts at range.end.\n"},"accruedCarryingCents":{"type":"integer","description":"Cumulative GL balance of Accrued Liability accounts at range.end.\n"}}},"SubLedgerRevenueView":{"type":"object","required":["companyId","entityId","range","tiles","chart","drill"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"range":{"$ref":"#/components/schemas/SubLedgerRange"},"tiles":{"$ref":"#/components/schemas/SubLedgerRevenueTiles"},"chart":{"type":"object","required":["data"],"properties":{"data":{"type":"array","minItems":6,"description":"Monthly series; at least 6 points (6-month floor)","items":{"$ref":"#/components/schemas/SubLedgerChartPoint"}}}},"drill":{"type":"object","required":["groups"],"properties":{"groups":{"type":"array","description":"All customer groups sorted by bookedCents desc","items":{"$ref":"#/components/schemas/SubLedgerRevenueGroup"}}}}}},"SubLedgerExpensesView":{"type":"object","required":["companyId","entityId","range","tiles","chart","drill"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"range":{"$ref":"#/components/schemas/SubLedgerRange"},"tiles":{"$ref":"#/components/schemas/SubLedgerExpensesTiles"},"chart":{"type":"object","required":["data"],"properties":{"data":{"type":"array","minItems":6,"description":"Monthly series; at least 6 points (6-month floor)","items":{"$ref":"#/components/schemas/SubLedgerChartPoint"}}}},"drill":{"type":"object","required":["groups"],"properties":{"groups":{"type":"array","description":"All expense category groups sorted by bookedCents desc","items":{"$ref":"#/components/schemas/SubLedgerExpenseGroup"}}}}}},"SubLedgerCurrentAssetRow":{"type":"object","required":["glAccountId","name","balanceCents"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"name":{"type":"string"},"code":{"type":["string","null"]},"balanceCents":{"type":"integer"}}},"FixedAssetDepreciationEntry":{"type":"object","required":["assetId","month","depreciationCents","accumulatedCents","netBookValueCents"],"properties":{"assetId":{"type":"string"},"month":{"type":"string","format":"date"},"depreciationCents":{"type":"integer"},"accumulatedCents":{"type":"integer"},"netBookValueCents":{"type":"integer"}}},"FixedAssetRegisterEntry":{"type":"object","required":["assetId","name","originalCostCents","inServiceDate","usefulLifeMonths","status"],"properties":{"assetId":{"type":"string"},"name":{"type":"string"},"originalCostCents":{"type":"integer"},"inServiceDate":{"type":"string","format":"date"},"usefulLifeMonths":{"type":"integer"},"status":{"type":"string","enum":["active","retired"]},"glAssetAccountId":{"type":["string","null"],"format":"uuid"},"latestScheduleEntry":{"oneOf":[{"$ref":"#/components/schemas/FixedAssetDepreciationEntry"},{"type":"null"}]}}},"PrepaidAmortScheduleEntry":{"type":"object","required":["sequenceNum","scheduledDate","amountCents","status"],"properties":{"sequenceNum":{"type":"integer"},"scheduledDate":{"type":"string","format":"date"},"amountCents":{"type":"integer"},"status":{"type":"string"}}},"ScheduleSourceLink":{"type":"object","required":["kind","id"],"additionalProperties":false,"properties":{"kind":{"type":"string","enum":["transaction","document","ar_item","ap_item"]},"id":{"type":"string"}}},"ScheduleRunOffUnavailableReason":{"type":["string","null"],"enum":["no_active_schedules","not_available_for_books","schedule_authority_not_entity_scoped",null],"description":"null when persisted run-off schedules are available. no_active_schedules means the Books cutoff has no active persisted schedule. not_available_for_books means the required durable schedule read model is not active for these books. schedule_authority_not_entity_scoped means only a company-wide legacy source exists.\n"},"ScheduleRunOffSchedule":{"type":"object","required":["scheduleId","kind","totalAmountCents","remainingPeriods","startDate","endDate","currency","sourceLabel","sourceLink","entries"],"properties":{"scheduleId":{"type":"string"},"kind":{"type":"string","enum":["prepaid_amortization","deferred_revenue_recognition","accrual_reversal"]},"totalAmountCents":{"type":"integer"},"remainingPeriods":{"type":"integer","minimum":0},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"currency":{"type":["string","null"],"pattern":"^[A-Z]{3}$"},"sourceLabel":{"type":["string","null"],"description":"Customer-safe lineage label. Never contains confidence or routing metadata."},"sourceLink":{"oneOf":[{"$ref":"#/components/schemas/ScheduleSourceLink"},{"type":"null"}]},"entries":{"type":"array","items":{"$ref":"#/components/schemas/PrepaidAmortScheduleEntry"}}}},"PrepaidAmortSchedule":{"type":"object","required":["scheduleId","sourceEventId","kind","totalAmountCents","remainingPeriods","startDate","endDate","currency","sourceLabel","sourceLink","entries"],"properties":{"scheduleId":{"type":"string"},"sourceEventId":{"type":"string"},"kind":{"type":"string","enum":["prepaid_amortization"]},"totalAmountCents":{"type":"integer"},"remainingPeriods":{"type":"integer"},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"currency":{"type":["string","null"],"pattern":"^[A-Z]{3}$"},"sourceLabel":{"type":["string","null"],"description":"Customer-safe lineage label. Never contains confidence or routing metadata."},"sourceLink":{"oneOf":[{"$ref":"#/components/schemas/ScheduleSourceLink"},{"type":"null"}]},"entries":{"type":"array","items":{"$ref":"#/components/schemas/PrepaidAmortScheduleEntry"}}}},"SubLedgerAssetsView":{"type":"object","required":["companyId","entityId","asOf","current","fixed","prepaid","inventory"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"asOf":{"type":["string","null"],"format":"date","description":"Cutoff for every balance-sheet figure. The customer route returns today (UTC); the accountant mirror returns the last closed GL period's end date, or null when none is closed."},"current":{"type":"object","required":["totalCents","byAccount"],"properties":{"totalCents":{"type":"integer","description":"Sum of signed GL balances for current (non-fixed) Asset accounts. Ties to /reports/balance-sheet current assets total within 1 cent.\n"},"byAccount":{"type":"array","items":{"$ref":"#/components/schemas/SubLedgerCurrentAssetRow"}}}},"fixed":{"type":"object","required":["netBookValueCents","originalCostCents","accumDepreciationCents","activeCount","register","registerUnavailableReason"],"properties":{"netBookValueCents":{"type":"integer","description":"Sum of signed GL balances on fixed-asset accounts (cost accounts positive, contra-asset accum-dep accounts negative). Ties to /reports/balance-sheet fixed-asset total within 1 cent.\n"},"originalCostCents":{"type":["integer","null"],"description":"null while the fixed-asset register lacks legal-entity authority."},"accumDepreciationCents":{"type":["integer","null"],"description":"null while the fixed-asset register lacks legal-entity authority."},"activeCount":{"type":["integer","null"],"description":"null while the fixed-asset register lacks legal-entity authority."},"register":{"type":["array","null"],"items":{"$ref":"#/components/schemas/FixedAssetRegisterEntry"}},"registerUnavailableReason":{"type":"string","enum":["fixed_asset_register_not_entity_scoped"]},"byAccount":{"type":"array","description":"Posted fixed-asset and accumulated-depreciation accounts; they net to netBookValueCents.","items":{"$ref":"#/components/schemas/SubLedgerAccountRow"}}}},"prepaid":{"type":"object","required":["totalCents","schedules","runOffUnavailableReason"],"properties":{"totalCents":{"type":["integer","null"],"description":"null when no entity-keyed schedule authority is available."},"schedules":{"type":"array","items":{"$ref":"#/components/schemas/PrepaidAmortSchedule"}},"runOffUnavailableReason":{"$ref":"#/components/schemas/ScheduleRunOffUnavailableReason"},"postedBalanceCents":{"type":"integer","description":"Posted balance of prepaid accounts (detail type or name), available whether or not schedules are."},"byAccount":{"type":"array","items":{"$ref":"#/components/schemas/SubLedgerAccountRow"}}}},"inventory":{"type":"null","description":"Always null. Inventory data model (inventory_items table) is deferred to a future increment.\n"}}},"CreditCardDebtEntry":{"type":"object","required":["glAccountId","name","balanceCents","monthlyInterestCents","aprUsed","interestUnavailableReason"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"name":{"type":"string"},"balanceCents":{"type":"integer"},"monthlyInterestCents":{"type":"null","description":"Unavailable until an authoritative APR or charge feed exists."},"aprUsed":{"type":"null","description":"No APR is inferred from GL account metadata or defaults."},"interestUnavailableReason":{"type":"string","enum":["credit_card_apr_not_available"]}}},"LeaseEntry":{"type":"object","required":["scheduleId","sourceEventId","leaseType","totalAmountCents","remainingPeriods","startDate","endDate","monthlyPaymentCents"],"properties":{"scheduleId":{"type":"string"},"sourceEventId":{"type":"string"},"leaseType":{"type":"string","enum":["operating","finance"]},"totalAmountCents":{"type":"integer"},"remainingPeriods":{"type":"integer"},"startDate":{"type":"string","format":"date"},"endDate":{"type":"string","format":"date"},"monthlyPaymentCents":{"type":"integer"}}},"DeferredRevenueMonthRow":{"type":"object","required":["month","additionsCents","recognizedCents","closingCents"],"properties":{"month":{"type":"string","description":"Month label in YYYY-MM format"},"additionsCents":{"type":"integer","description":"New deferred revenue booked in this month across all schedules."},"recognizedCents":{"type":"integer","description":"Revenue recognized (posted) in this month."},"closingCents":{"type":"integer","description":"Running balance of additions minus recognized through this month."}}},"SalesTaxEntry":{"type":"object","required":["payableGlAccountId","payableAccountName","payableBalanceCents","heldAssetGlAccountId","heldAssetBalanceCents","heldAssetUnavailableReason"],"properties":{"payableGlAccountId":{"type":"string","format":"uuid","description":"The sales-tax payable GL account, resolved by account name/subtype rather than by code. Code 2200 is the seeded credit-card code, so it is never sufficient on its own (#2000).\n"},"payableAccountName":{"type":"string","description":"Name of the resolved account, so the caption can be audited against the source."},"payableBalanceCents":{"type":"integer"},"heldAssetGlAccountId":{"type":["string","null"],"format":"uuid","description":"GL account 1210 if it exists; null when no posted held-asset account exists."},"heldAssetBalanceCents":{"type":["integer","null"],"description":"Posted balance of the held-asset account; never inferred from the payable."},"heldAssetUnavailableReason":{"type":["string","null"],"enum":["held_asset_account_not_available",null],"description":"Explicit reason the held-asset balance is unavailable. Null when a real 1210 account and its posted balance are present.\n"}}},"SubLedgerAccountRow":{"type":"object","description":"One posted GL account balance, signed by the balance sheet's rule. Balance-sheet synthetic rows (unclosed earnings) carry `glAccountId` = `synthetic:<kind>` and `code` null.","required":["glAccountId","name","code","balanceCents"],"properties":{"glAccountId":{"type":"string"},"name":{"type":"string"},"code":{"type":["string","null"]},"balanceCents":{"type":"integer"}}},"SubLedgerLiabilitiesView":{"type":"object","required":["companyId","entityId","asOf","totals","debt","leases","deferred","accrued","equity"],"properties":{"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"asOf":{"type":["string","null"],"format":"date","description":"Cutoff for every balance-sheet figure. The customer route returns today (UTC); the accountant mirror returns the last closed GL period's end date, or null when none is closed."},"totals":{"type":"object","required":["totalLiabilitiesCents","totalEquityCents"],"properties":{"totalLiabilitiesCents":{"type":"integer","description":"Sum of signed GL balances for all Liability accounts. Ties to /reports/balance-sheet totalLiabilities within 1 cent.\n"},"totalEquityCents":{"type":"integer","description":"Sum of signed GL balances for all Equity accounts. Omits earnings not yet closed to retained earnings; see balanceSheetEquityCents."},"balanceSheetEquityCents":{"type":["integer","null"],"description":"Total equity from the balance sheet at the same cutoff, including prior- and current-year earnings not yet closed (#1994). Null when the balance sheet could not be read."},"balanceSheetLiabilitiesCents":{"type":["integer","null"],"description":"Total liabilities from the same balance-sheet read, so a caption built from it and balanceSheetEquityCents sums to total assets."}}},"balanceSheetLiabilities":{"type":["array","null"],"description":"Every non-zero liability line on the balance sheet at the same cutoff, largest first (including lines no tab details, e.g. a SAFE).","items":{"$ref":"#/components/schemas/SubLedgerAccountRow"}},"debt":{"type":"object","required":["totalCents","loans","loansUnavailableReason","creditCards"],"properties":{"totalCents":{"type":"null"},"loans":{"type":"null"},"loansUnavailableReason":{"type":"string","enum":["loan_register_not_entity_scoped"]},"creditCards":{"type":"array","items":{"$ref":"#/components/schemas/CreditCardDebtEntry"}},"loanAccounts":{"type":"array","description":"Posted loan, note and line-of-credit accounts (no cards, no SAFEs).","items":{"$ref":"#/components/schemas/SubLedgerAccountRow"}},"postedBalanceCents":{"type":"integer","description":"Credit cards plus loan accounts, from the ledger."}}},"leases":{"type":"object","required":["totalCents","entries","runOffUnavailableReason"],"properties":{"totalCents":{"type":["integer","null"]},"entries":{"type":"array","items":{"$ref":"#/components/schemas/LeaseEntry"}},"runOffUnavailableReason":{"$ref":"#/components/schemas/ScheduleRunOffUnavailableReason"},"postedBalanceCents":{"type":"integer","description":"Posted balance of lease-liability accounts."}}},"deferred":{"type":"object","required":["totalCents","monthlyRollup","schedules","runOffUnavailableReason"],"properties":{"totalCents":{"type":["integer","null"],"description":"Closing balance of the deferred revenue roll-up (last row's closingCents)."},"monthlyRollup":{"type":"array","maxItems":12,"description":"Up to 12 months ending in the asOf month from entity-keyed schedules; empty when schedule authority is not entity-scoped.\n","items":{"$ref":"#/components/schemas/DeferredRevenueMonthRow"}},"schedules":{"type":"array","description":"Active persisted deferred-revenue schedules, including posted and upcoming runs.","items":{"$ref":"#/components/schemas/ScheduleRunOffSchedule"}},"runOffUnavailableReason":{"$ref":"#/components/schemas/ScheduleRunOffUnavailableReason"},"postedBalanceCents":{"type":"integer","description":"Posted deferred-revenue balance (detail type or name), available whether or not schedules are."},"byAccount":{"type":"array","items":{"$ref":"#/components/schemas/SubLedgerAccountRow"}}}},"accrued":{"type":"object","required":["totalCents","byAccount","schedules","runOffUnavailableReason"],"properties":{"totalCents":{"type":"integer"},"byAccount":{"type":"array","items":{"type":"object","required":["glAccountId","name","balanceCents"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"name":{"type":"string"},"code":{"type":["string","null"]},"balanceCents":{"type":"integer"}}}},"schedules":{"type":"array","description":"Pending reversal schedules only after the paired accrual has posted by the Books cutoff. Never forecasts an unposted accrual.\n","items":{"$ref":"#/components/schemas/ScheduleRunOffSchedule"}},"runOffUnavailableReason":{"$ref":"#/components/schemas/ScheduleRunOffUnavailableReason"}}},"equity":{"type":"object","required":["totalCents","byAccount"],"properties":{"totalCents":{"type":"integer"},"byAccount":{"type":"array","items":{"type":"object","required":["glAccountId","name","balanceCents"],"properties":{"glAccountId":{"type":"string","format":"uuid"},"name":{"type":"string"},"code":{"type":["string","null"]},"balanceCents":{"type":"integer"}}}},"balanceSheetRows":{"type":["array","null"],"description":"Balance-sheet equity rows at the same cutoff, including the synthetic prior-year and current-year earnings rows.","items":{"$ref":"#/components/schemas/SubLedgerAccountRow"}}}},"tax":{"oneOf":[{"$ref":"#/components/schemas/SalesTaxEntry"},{"type":"null"}],"description":"Sales-tax pairing (payable ↔ 1210 held asset). null when no account in the COA is identifiable as sales-tax payable; see taxUnavailableReason.\n"},"taxUnavailableReason":{"type":["string","null"],"enum":["sales_tax_account_not_identifiable",null],"description":"Set when a code-2200 liability account exists but is not a sales-tax account (in practice a named credit card, #2000). Callers must render a named-unavailable state instead of captioning that balance as tax owed to authorities. Null when tax is populated, and also null when the COA simply has no 2200 account at all.\n"}}},"ForecastModel":{"type":"object","additionalProperties":false,"required":["id","companyId","entityId","label","businessType","startCashCents","horizonMonths","currency","minorUnitExponent","moneyAuthorityVersion","source","sourceMetadata","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"entityId":{"type":"string","format":"uuid"},"label":{"type":"string"},"businessType":{"type":"string","enum":["software","services","digital","usage","license","blended","custom"]},"startCashCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Starting cash in the model's authoritative minor units"},"horizonMonths":{"type":"integer","enum":[12,18,24]},"currency":{"type":"string","pattern":"^[A-Z]{3}$","description":"Server-owned legal-entity functional currency"},"minorUnitExponent":{"type":"integer","const":2,"description":"Server-owned scale for every monetary integer in this Forecast model"},"moneyAuthorityVersion":{"type":"integer","const":1},"source":{"type":"string","enum":["unknown","manual","books"],"description":"Provenance of the model's opening cash boundary"},"sourceMetadata":{"type":"object","additionalProperties":true,"description":"Non-secret authority metadata such as closed period, anchor, and functional currency"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateForecastModelInput":{"type":"object","required":["businessType","startCashCents"],"properties":{"label":{"type":"string","minLength":1,"maxLength":80,"default":"Forecast"},"businessType":{"type":"string","enum":["software","services","digital","usage","license","blended","custom"]},"startCashCents":{"type":"integer","minimum":0,"maximum":9007199254740991},"horizonMonths":{"type":"integer","enum":[12,18,24],"default":12}}},"ForecastStream":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"forecastId":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["subscription","usage","license","onetime","services_hours","services_retainer","ledger_run_rate"]},"label":{"type":"string"},"position":{"type":"integer"},"drivers":{"type":"object","additionalProperties":{"type":"number"}},"archived":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ForecastHeadcount":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"forecastId":{"type":"string","format":"uuid"},"role":{"type":"string"},"employmentType":{"type":"string","enum":["w2","contractor"]},"count":{"type":"integer","minimum":0},"monthlyCostCents":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Monthly cost per head in the model's authoritative minor units"},"startOffset":{"type":"integer","minimum":0},"rampMonths":{"type":"integer","minimum":0},"position":{"type":"integer"}}},"ForecastOpex":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"forecastId":{"type":"string","format":"uuid"},"name":{"type":"string"},"behavior":{"type":"string","enum":["fixed","pct_revenue","per_head"]},"amountCents":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991,"description":"Fixed or per-head amount in the model's authoritative minor units"},"pct":{"type":["number","null"],"description":"Percentage of revenue (for pct_revenue), in [0,1]"},"position":{"type":"integer"}}},"ForecastScenario":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"forecastId":{"type":"string","format":"uuid"},"name":{"type":"string"},"kind":{"type":"string","enum":["adhoc","budget"]},"isLocked":{"type":"boolean"},"baseModelId":{"type":["string","null"],"format":"uuid"},"overrides":{"type":"object"},"createdAt":{"type":"string","format":"date-time"}}},"ForecastFinancingEvent":{"type":"object","additionalProperties":false,"description":"Immutable, timed capital cash inflow; never revenue or opening cash","required":["id","forecastId","legalEntityId","amountCents","currency","effectiveMonth","source","promptHash","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"forecastId":{"type":"string","format":"uuid"},"legalEntityId":{"type":"string","format":"uuid"},"amountCents":{"type":"integer","minimum":1,"maximum":9007199254740991},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"effectiveMonth":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"},"expectedDate":{"type":["string","null"],"format":"date","description":"Explicit expected receipt day within effectiveMonth. Omitted or null means undated; a date alone is not evidence of posted cash."},"source":{"type":"string","enum":["manual","forecast_ai","forecast_mcp","deterministic_lever"]},"promptHash":{"type":["string","null"],"pattern":"^[0-9a-f]{64}$"},"createdAt":{"type":"string","format":"date-time"}}},"ForecastAggregate":{"type":"object","required":["model","streams","headcount","opex","financingEvents","scenarios"],"properties":{"model":{"$ref":"#/components/schemas/ForecastModel"},"streams":{"type":"array","items":{"$ref":"#/components/schemas/ForecastStream"}},"headcount":{"type":"array","items":{"$ref":"#/components/schemas/ForecastHeadcount"}},"opex":{"type":"array","items":{"$ref":"#/components/schemas/ForecastOpex"}},"financingEvents":{"type":"array","description":"Repository-authoritative financing assumptions; preview clients cannot submit this field","items":{"$ref":"#/components/schemas/ForecastFinancingEvent"}},"scenarios":{"type":"array","items":{"$ref":"#/components/schemas/ForecastScenario"}}}},"ForecastAggregateResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/ForecastAggregate"}}},"ApplyForecastBooksBaselineInput":{"type":"object","additionalProperties":false,"required":["fingerprint"],"properties":{"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$","description":"SHA-256 review token returned by the books-baseline review endpoint"}}},"ForecastBooksBaselinePeriod":{"type":"object","additionalProperties":false,"required":["period","revenueCents"],"properties":{"period":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"},"revenueCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}}},"ForecastBooksBaselineCurrent":{"type":"object","additionalProperties":false,"required":["streamId","monthlyRevenueCents","fingerprint"],"properties":{"streamId":{"type":"string","format":"uuid"},"monthlyRevenueCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"fingerprint":{"type":["string","null"],"pattern":"^[a-f0-9]{64}$"}}},"ForecastBooksBaselineCandidate":{"type":"object","additionalProperties":false,"required":["forecastId","authority","calculation","legalEntityId","functionalCurrency","minorUnitExponent","moneyAuthorityVersion","periods","totalRevenueCents","monthlyRevenueCents","fingerprint","current","isCurrent"],"properties":{"forecastId":{"type":"string","format":"uuid"},"authority":{"type":"string","enum":["posted_calendar_gl_v2"]},"calculation":{"type":"string","enum":["trailing_completed_month_average"]},"legalEntityId":{"type":"string","format":"uuid"},"functionalCurrency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer","const":2},"moneyAuthorityVersion":{"type":"integer","const":1},"periods":{"type":"array","minItems":1,"maxItems":3,"items":{"$ref":"#/components/schemas/ForecastBooksBaselinePeriod"}},"totalRevenueCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"monthlyRevenueCents":{"type":"integer","minimum":1,"maximum":9007199254740991},"fingerprint":{"type":"string","pattern":"^[a-f0-9]{64}$"},"current":{"oneOf":[{"$ref":"#/components/schemas/ForecastBooksBaselineCurrent"},{"type":"null"}]},"isCurrent":{"type":"boolean"}}},"ForecastSteerInput":{"type":"object","additionalProperties":false,"required":["prompt"],"properties":{"prompt":{"type":"string","minLength":1,"maxLength":2000},"scenarioId":{"type":"string","format":"uuid"}}},"ForecastSteerResponse":{"type":"object","required":["scenario","toolCalls","projection","narrative","confidencePct","requiresHumanReview","functionalCurrency","minorUnitExponent","moneyAuthorityVersion","anchorYyyyMm","cashAsOfYyyyMm","runwayDelta"],"properties":{"scenario":{"$ref":"#/components/schemas/ForecastScenario"},"toolCalls":{"type":"array","minItems":1,"maxItems":12,"items":{"type":"object","required":["name","arguments"],"properties":{"name":{"type":"string","enum":["apply_lever","apply_driver_change","add_stream","remove_stream","add_hire","set_opex","add_financing"]},"arguments":{"type":"object"}}}},"projection":{"$ref":"#/components/schemas/ProjectionResult"},"narrative":{"type":"string"},"confidencePct":{"type":"number","minimum":0,"maximum":100},"requiresHumanReview":{"type":"boolean"},"functionalCurrency":{"type":"string","pattern":"^[A-Z]{3}$","description":"Functional currency of the authoritative ledger cash boundary"},"minorUnitExponent":{"type":"integer","const":2},"moneyAuthorityVersion":{"type":"integer","const":1},"anchorYyyyMm":{"type":["string","null"],"pattern":"^\\d{4}-(0[1-9]|1[0-2])$","description":"First projected month; the current UTC calendar month"},"cashAsOfYyyyMm":{"type":["string","null"],"pattern":"^\\d{4}-(0[1-9]|1[0-2])$","description":"Calendar month whose posted books cash anchors the forecast"},"runwayDelta":{"type":"object","properties":{"before":{"$ref":"#/components/schemas/ForecastRunway"},"after":{"$ref":"#/components/schemas/ForecastRunway"}}}}},"ForecastActiveSandboxResponse":{"type":"object","required":["scenario","toolCalls","projection","narrative","confidencePct","requiresHumanReview","functionalCurrency","minorUnitExponent","moneyAuthorityVersion","anchorYyyyMm","cashAsOfYyyyMm","runwayDelta","unavailableReason"],"properties":{"scenario":{"$ref":"#/components/schemas/ForecastScenario"},"toolCalls":{"type":"array","maxItems":12,"items":{"type":"object","required":["name","arguments"],"properties":{"name":{"type":"string","enum":["apply_lever","apply_driver_change","add_stream","remove_stream","add_hire","set_opex","add_financing"]},"arguments":{"type":"object"}}}},"projection":{"oneOf":[{"$ref":"#/components/schemas/ProjectionResult"},{"type":"null"}]},"narrative":{"type":"string"},"confidencePct":{"type":"number","minimum":0,"maximum":100},"requiresHumanReview":{"type":"boolean"},"functionalCurrency":{"type":["string","null"],"pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":["integer","null"],"enum":[2,null]},"moneyAuthorityVersion":{"type":["integer","null"],"enum":[1,null]},"anchorYyyyMm":{"type":["string","null"],"pattern":"^\\d{4}-(0[1-9]|1[0-2])$"},"cashAsOfYyyyMm":{"type":["string","null"],"pattern":"^\\d{4}-(0[1-9]|1[0-2])$"},"runwayDelta":{"oneOf":[{"type":"object","required":["before","after"],"properties":{"before":{"$ref":"#/components/schemas/ForecastRunway"},"after":{"$ref":"#/components/schemas/ForecastRunway"}}},{"type":"null"}]},"unavailableReason":{"type":["string","null"]}}},"ForecastRunway":{"type":"object","properties":{"months":{"type":["integer","null"]},"profitable":{"type":"boolean"}}},"UpdateForecastModelInput":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":80},"businessType":{"type":"string","enum":["software","services","digital","usage","license","blended","custom"]},"startCashCents":{"type":"integer","minimum":0,"maximum":9007199254740991},"horizonMonths":{"type":"integer","enum":[12,18,24]}}},"CreateForecastStreamInput":{"type":"object","required":["type","label","drivers"],"properties":{"type":{"type":"string","enum":["subscription","usage","license","onetime","services_hours","services_retainer"]},"label":{"type":"string","minLength":1,"maxLength":80},"position":{"type":"integer","minimum":0},"drivers":{"type":"object","additionalProperties":{"type":"number"},"description":"Discriminated driver fields for the stream type; validated against DRIVER_BOUNDS"}}},"CreateForecastHeadcountInput":{"type":"object","required":["role","employmentType","count","monthlyCostCents"],"properties":{"role":{"type":"string","minLength":1,"maxLength":80},"employmentType":{"type":"string","enum":["w2","contractor"]},"count":{"type":"integer","minimum":0},"monthlyCostCents":{"type":"integer","minimum":0,"maximum":9007199254740991},"startOffset":{"type":"integer","minimum":0,"default":0},"rampMonths":{"type":"integer","minimum":0,"default":0},"position":{"type":"integer","minimum":0}}},"CreateForecastOpexInput":{"type":"object","required":["name","behavior"],"properties":{"name":{"type":"string","minLength":1,"maxLength":80},"behavior":{"type":"string","enum":["fixed","pct_revenue","per_head"]},"amountCents":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"pct":{"type":["number","null"],"minimum":0,"maximum":1},"position":{"type":"integer","minimum":0}}},"CreateForecastScenarioInput":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":80},"kind":{"type":"string","enum":["adhoc","budget"],"default":"adhoc"},"isLocked":{"type":"boolean","default":false},"baseModelId":{"type":["string","null"],"format":"uuid"},"overrides":{"type":"object"}}},"UpdateForecastScenarioInput":{"type":"object","minProperties":1,"properties":{"name":{"type":"string","minLength":1,"maxLength":80},"kind":{"type":"string","enum":["adhoc","budget"]},"isLocked":{"type":"boolean"},"overrides":{"type":"object"}}},"UpdateForecastStreamInput":{"type":"object","minProperties":1,"properties":{"label":{"type":"string","minLength":1,"maxLength":80},"position":{"type":"integer","minimum":0},"drivers":{"type":"object","additionalProperties":{"type":"number"}},"archived":{"type":"boolean"}}},"UpdateForecastHeadcountInput":{"type":"object","minProperties":1,"properties":{"role":{"type":"string","minLength":1,"maxLength":80},"employmentType":{"type":"string","enum":["w2","contractor"]},"count":{"type":"integer","minimum":0},"monthlyCostCents":{"type":"integer","minimum":0,"maximum":9007199254740991},"startOffset":{"type":"integer","minimum":0},"rampMonths":{"type":"integer","minimum":0},"position":{"type":"integer","minimum":0}}},"UpdateForecastOpexInput":{"type":"object","minProperties":1,"properties":{"name":{"type":"string","minLength":1,"maxLength":80},"behavior":{"type":"string","enum":["fixed","pct_revenue","per_head"]},"amountCents":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"pct":{"type":["number","null"],"minimum":0,"maximum":1},"position":{"type":"integer","minimum":0}}},"MonthlyPoint":{"type":"object","description":"A single month in a projection series","required":["offset","label","revenueCents","byStreamCents","peopleCents","opexCents","financingCents","netCents","endingCents","marginPct"],"properties":{"offset":{"type":"integer","description":"0-based month offset from model start"},"label":{"type":"string","description":"Human-readable month label (e.g. \"Jul 26\")"},"revenueCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Total revenue in the response's authoritative minor units"},"byStreamCents":{"type":"object","additionalProperties":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"Revenue by stream ID in the response's authoritative minor units"},"peopleCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Headcount cost in the response's authoritative minor units"},"opexCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Operating expense in the response's authoritative minor units"},"financingCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Timed non-revenue capital cash flow in the response's authoritative minor units"},"netCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Net income excluding financing, in the response's authoritative minor units"},"endingCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Ending cash balance in the response's authoritative minor units"},"cashMovementCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Projected rows only (#2652). Cash this row adds to the prior ending cash — operating net (for offset 0, prorated to the days of the current month after cashAsOfDate, half a minor unit rounding away from zero) plus financing — so prior ending + cashMovementCents = endingCents."},"marginPct":{"type":"number","description":"Net margin (0 when revenue is 0)"}}},"ForecastActualsResponse":{"type":"object","required":["actuals","boundary"],"properties":{"actuals":{"type":"array","description":"One point per calendar month from the first posted activity through the last completed UTC month (at most 36; MonthlyPoint shape)","items":{"$ref":"#/components/schemas/MonthlyPoint"}},"boundary":{"type":"object","description":"Calendar boundary (#2652); no closed accounting period is required","required":["actualsThroughPeriod","anchorPeriod","cashAsOfDate","cashAsOfAt","startCashCents","functionalCurrency","minorUnitExponent","moneyAuthorityVersion","legalEntityId"],"properties":{"actualsThroughPeriod":{"type":"string","description":"YYYY-MM of the last completed UTC calendar month"},"anchorPeriod":{"type":"string","description":"YYYY-MM of the first projected month (the current UTC calendar month)"},"cashAsOfDate":{"type":["string","null"],"format":"date","description":"Date startCashCents is stated at (today, UTC); null when the ledger holds no cash balance"},"cashAsOfAt":{"type":["string","null"],"format":"date-time","description":"Instant the books cash was read (ISO timestamp); null when the ledger holds no cash balance"},"startCashCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Posted GL cash-account balance from entries dated through today (UTC); entries dated later this month are excluded"},"functionalCurrency":{"type":["string","null"],"pattern":"^[A-Z]{3}$","description":"Reconciled legal-entity, P&L, and cash functional currency"},"minorUnitExponent":{"type":["integer","null"],"enum":[2,null]},"moneyAuthorityVersion":{"type":["integer","null"],"enum":[1,null]},"legalEntityId":{"type":["string","null"],"format":"uuid","description":"Sole legal entity whose posted books feed Forecast"}}}}},"VarianceCell":{"type":"object","required":["actualCents","planCents","varianceCents","favorable","material"],"properties":{"actualCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"planCents":{"type":["integer","null"],"minimum":-9007199254740991,"maximum":9007199254740991,"description":"From the locked budget scenario; null when no budget is locked"},"varianceCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"actual - plan (0 when plan is null)"},"favorable":{"type":"boolean","description":"Sign-aware (revenue/net over plan favorable; expense under plan favorable)"},"material":{"type":"boolean","description":"|variance| over the authoritative minor-unit floor OR |variance/plan| over the pct threshold"}}},"VariancePoint":{"type":"object","required":["offset","label","period","revenue","expense","net"],"properties":{"offset":{"type":"integer"},"label":{"type":"string"},"period":{"type":"string","description":"YYYY-MM"},"revenue":{"$ref":"#/components/schemas/VarianceCell"},"expense":{"$ref":"#/components/schemas/VarianceCell"},"net":{"$ref":"#/components/schemas/VarianceCell"}}},"ForecastVarianceResponse":{"type":"object","required":["scenarioId","materialityFloorCents","materialityPct","currency","minorUnitExponent","moneyAuthorityVersion","months"],"properties":{"scenarioId":{"type":["string","null"],"format":"uuid","description":"The locked budget scenario used as plan, if any"},"materialityFloorCents":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Absolute materiality floor in the supplied currency's minor units"},"materialityPct":{"type":"number","description":"Relative materiality threshold (default 0.1)"},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer","const":2},"moneyAuthorityVersion":{"type":"integer","const":1},"months":{"type":"array","items":{"$ref":"#/components/schemas/VariancePoint"}}}},"ProjectionResult":{"type":"object","description":"Full projection result with all three scenarios, runway, and KPIs","required":["scenarios","actuals","functionalCurrency","minorUnitExponent","moneyAuthorityVersion","anchorYyyyMm","cashAsOfYyyyMm","runway","recurringMixPct","kpis"],"properties":{"scenarios":{"type":"object","required":["worst","base","best"],"properties":{"worst":{"type":"array","items":{"$ref":"#/components/schemas/MonthlyPoint"}},"base":{"type":"array","items":{"$ref":"#/components/schemas/MonthlyPoint"}},"best":{"type":"array","items":{"$ref":"#/components/schemas/MonthlyPoint"}}}},"actuals":{"type":"array","description":"Historical actuals (empty until","items":{"$ref":"#/components/schemas/MonthlyPoint"}},"functionalCurrency":{"type":"string","pattern":"^[A-Z]{3}$","description":"Functional currency of the authoritative ledger cash boundary"},"minorUnitExponent":{"type":"integer","const":2},"moneyAuthorityVersion":{"type":"integer","const":1},"anchorYyyyMm":{"type":["string","null"],"pattern":"^\\d{4}-(0[1-9]|1[0-2])$","description":"First projected month; the current UTC calendar month (actuals run through the month before it)"},"cashAsOfYyyyMm":{"type":["string","null"],"pattern":"^\\d{4}-(0[1-9]|1[0-2])$","description":"Calendar month whose posted books cash anchors the forecast (null when the persisted model's cash is used)"},"cashAsOfDate":{"type":["string","null"],"format":"date","description":"Date the posted books start cash is stated at (#2652; today for live reads, the month end for close snapshots; null when the persisted model's cash is used)"},"cashAsOfAt":{"type":["string","null"],"format":"date-time","description":"Instant the live books cash was read (UTC ISO timestamp), so clients can state the as-of date in the viewer's time zone; null for close snapshots and persisted model cash. Proration uses cashAsOfDate, not this field."},"runway":{"type":"object","required":["profitable"],"properties":{"months":{"type":["integer","null"],"minimum":0,"description":"Months of runway remaining (null when no shortfall is projected)"},"profitable":{"type":"boolean","description":"True when cash never declines over the horizon"}}},"recurringMixPct":{"type":["number","null"],"minimum":0,"maximum":1,"description":"Fraction of current-month base revenue that is recurring; null when source data cannot prove recurrence"},"horizonSummaries":{"type":"object","description":"Summaries keyed by visible month count for 6, 12 and the full projection length when available. Select these with the corresponding scenario prefix; never extrapolate runway in the client. Legacy payloads may omit this object and support only their full horizon.","additionalProperties":{"$ref":"#/components/schemas/ProjectionHorizonSummary"}},"kpis":{"type":"object","required":["cashOnHandCents","nextMonthNetCents"],"properties":{"cashOnHandCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Current cash on hand in the supplied currency's minor units"},"nextMonthNetCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Projected net income for the calendar month after the current month (offset 1; offset 0 is the current, partly elapsed month) in the supplied currency's minor units"}}}}},"ProjectionHorizonSummary":{"type":"object","description":"Server summary for a prefix of the same scenario points. Runway uses that prefix; starting cash, next-month net and month-zero recurring mix retain their original meaning.","required":["runway","recurringMixPct","kpis"],"properties":{"runway":{"$ref":"#/components/schemas/ProjectionResult/properties/runway"},"recurringMixPct":{"$ref":"#/components/schemas/ProjectionResult/properties/recurringMixPct"},"kpis":{"$ref":"#/components/schemas/ProjectionResult/properties/kpis"}}},"ForecastRunwayImpact":{"type":"object","additionalProperties":false,"required":["before","after"],"properties":{"before":{"$ref":"#/components/schemas/ForecastRunway"},"after":{"$ref":"#/components/schemas/ForecastRunway"}}},"SensitivityItem":{"type":"object","description":"Impact of a single lever on 12-month ending cash","required":["leverId","label","deltaCents","active","runwayImpact","currency","minorUnitExponent","moneyAuthorityVersion"],"properties":{"leverId":{"type":"string","enum":["raise_prices","accelerate_new_business","make_a_key_hire","trim_opex","churn_up","raise_financing"]},"label":{"type":"string","description":"Human-readable lever label"},"deltaCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Change in ending cash in the supplied currency's minor units"},"active":{"type":"boolean"},"runwayImpact":{"$ref":"#/components/schemas/ForecastRunwayImpact"},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer","const":2},"moneyAuthorityVersion":{"type":"integer","const":1}}},"DecisionItem":{"type":"object","description":"A recommended decision with its cash impact and tone","required":["leverId","action","tone","deltaCents","active","runwayImpact","currency","minorUnitExponent","moneyAuthorityVersion"],"properties":{"leverId":{"type":"string","enum":["raise_prices","accelerate_new_business","make_a_key_hire","trim_opex","churn_up","raise_financing"]},"action":{"type":"string","description":"Human-readable action label"},"tone":{"type":"string","enum":["positive","caution"],"description":"Whether this decision is positive or requires caution"},"deltaCents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Change in ending cash in the supplied currency's minor units"},"active":{"type":"boolean"},"runwayImpact":{"$ref":"#/components/schemas/ForecastRunwayImpact"},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"minorUnitExponent":{"type":"integer","const":2},"moneyAuthorityVersion":{"type":"integer","const":1}}}}}}