{"openapi":"3.1.0","info":{"title":"ClearlyLedger API","description":"Bank statement PDF → Excel/CSV conversion service","version":"0.1.0"},"paths":{"/api/health":{"get":{"tags":["health"],"summary":"Health Check","description":"Liveness + readiness probe.\n\nChecks that the database accepts a trivial query.  Returns 503 if the DB\nis unreachable so Railway (and any upstream load balancer) can route away\nfrom this instance.","operationId":"health_check_api_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/health":{"get":{"tags":["health"],"summary":"Health Check","description":"Liveness + readiness probe.\n\nChecks that the database accepts a trivial query.  Returns 503 if the DB\nis unreachable so Railway (and any upstream load balancer) can route away\nfrom this instance.","operationId":"health_check_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/health/payments":{"get":{"tags":["health"],"summary":"Payments Health","description":"Payment configuration readiness diagnostic.\n\nReports whether Dodo Payments is correctly configured without exposing\nany secret values. Use to verify Railway env var setup after deploy.\n\nSafe to call in production — no secrets returned.","operationId":"payments_health_health_payments_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health/storage":{"get":{"tags":["health"],"summary":"Storage Health","description":"Storage readiness diagnostic.\n\nSafe for production: reports which R2 env var names are missing without\nexposing secret values. The app can still serve local /download/ fallback\nURLs when R2 is not configured, but that mode is not durable across\nrestarts or multiple instances.","operationId":"storage_health_health_storage_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health/ocr":{"get":{"tags":["health"],"summary":"Ocr Health","description":"Report whether this instance can process scanned PDFs, without secrets.","operationId":"ocr_health_health_ocr_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/posthog-test":{"get":{"tags":["health"],"summary":"Posthog Test","description":"Send a test event to PostHog to verify configuration.\nDev/staging only — returns 404 in production.\nCheck PostHog Live Events tab within 30 seconds of calling this.","operationId":"posthog_test_posthog_test_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/conversions/recent":{"get":{"tags":["admin"],"summary":"Recent Conversions","operationId":"recent_conversions_conversions_recent_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Recent Conversions Conversions Recent Get"}}}}}}},"/admin/conversion-quality":{"get":{"tags":["admin"],"summary":"Conversion Quality Dashboard","description":"Privacy-safe conversion quality dashboard for launch triage.\n\nUses only `bank_layout_observations`, which intentionally stores no user\nidentifiers, account numbers, transaction text, or amounts.","operationId":"conversion_quality_dashboard_admin_conversion_quality_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":30,"title":"Days"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Conversion Quality Dashboard Admin Conversion Quality Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/format-registry":{"get":{"tags":["admin"],"summary":"Format Registry","description":"Per-bank format registry: which formats, languages, and conventions\neach bank's statements actually use, learned from privacy-safe\n`bank_layout_observations` (short format codes only — no user IDs,\naccount numbers, transaction text, or amounts).\n\n`dayfirst_evidence_*` fields aggregate ONLY digit-evidenced observations;\nreview them before enabling FORMAT_PRIORS_ENABLED.","operationId":"format_registry_admin_format_registry_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":180,"title":"Days"}},{"name":"bank","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bank"}},{"name":"min_samples","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Min Samples"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Format Registry Admin Format Registry Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/profile-candidates":{"get":{"tags":["admin"],"summary":"List Profile Candidates","operationId":"list_profile_candidates_admin_profile_candidates_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","pattern":"^(candidate|promoted|rejected)$","default":"candidate","title":"Status"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response List Profile Candidates Admin Profile Candidates Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/profile-candidates/stats":{"get":{"tags":["admin"],"summary":"Profile Candidate Stats","operationId":"profile_candidate_stats_admin_profile_candidates_stats_get","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Profile Candidate Stats Admin Profile Candidates Stats Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/profile-candidates/{candidate_id}":{"get":{"tags":["admin"],"summary":"Get Profile Candidate","operationId":"get_profile_candidate_admin_profile_candidates__candidate_id__get","parameters":[{"name":"candidate_id","in":"path","required":true,"schema":{"type":"string","title":"Candidate Id"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Profile Candidate Admin Profile Candidates  Candidate Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/profile-candidates/{candidate_id}/promote":{"post":{"tags":["admin"],"summary":"Promote Profile Candidate","operationId":"promote_profile_candidate_admin_profile_candidates__candidate_id__promote_post","parameters":[{"name":"candidate_id","in":"path","required":true,"schema":{"type":"string","title":"Candidate Id"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Promote Profile Candidate Admin Profile Candidates  Candidate Id  Promote Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/profile-candidates/{candidate_id}/reject":{"post":{"tags":["admin"],"summary":"Reject Profile Candidate","operationId":"reject_profile_candidate_admin_profile_candidates__candidate_id__reject_post","parameters":[{"name":"candidate_id","in":"path","required":true,"schema":{"type":"string","title":"Candidate Id"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Reject Profile Candidate Admin Profile Candidates  Candidate Id  Reject Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/convert":{"post":{"tags":["conversion"],"summary":"Convert Pdf","description":"Convert a bank statement PDF to structured transaction data.\n\n- Free users: max 50 pages/month (returns 402 if exceeded)\n- Max upload: 20 MB\n- Returns ConversionResult with VERIFIED / DISCREPANCY / FAILED status","operationId":"convert_pdf_convert_post","parameters":[{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_convert_pdf_convert_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversionResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/convert/accounting":{"post":{"tags":["conversion"],"summary":"Convert To Accounting","description":"Convert a PDF bank statement into OFX/QBO/QIF/MT940 accounting exports.","operationId":"convert_to_accounting_convert_accounting_post","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_convert_to_accounting_convert_accounting_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Convert To Accounting Convert Accounting Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/convert/quickbooks":{"post":{"tags":["conversion"],"summary":"Convert To Quickbooks","description":"Convert a PDF bank statement into a QuickBooks Online-ready CSV.","operationId":"convert_to_quickbooks_convert_quickbooks_post","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_convert_to_quickbooks_convert_quickbooks_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Convert To Quickbooks Convert Quickbooks Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/convert/xero":{"post":{"tags":["conversion"],"summary":"Convert To Xero","description":"Convert a PDF bank statement into a Xero bank-statement CSV.","operationId":"convert_to_xero_convert_xero_post","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_convert_to_xero_convert_xero_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Convert To Xero Convert Xero Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/convert/gnucash":{"post":{"tags":["conversion"],"summary":"Convert To Gnucash","description":"Convert a PDF bank statement into a GnuCash-importable CSV/OFX/QIF file.","operationId":"convert_to_gnucash_convert_gnucash_post","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_convert_to_gnucash_convert_gnucash_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Convert To Gnucash Convert Gnucash Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/revenue-expense/pdf":{"post":{"tags":["reports"],"summary":"Create Revenue Expense Pdf","description":"Recalculate and render a report without consuming conversion pages.","operationId":"create_revenue_expense_pdf_reports_revenue_expense_pdf_post","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevenueExpenseReportRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/convert/batch":{"post":{"tags":["batch"],"summary":"Convert Batch","description":"Accept up to 50 PDF files for batch conversion.\n\n<=5 files  → processed synchronously, result returned immediately.\n6-50 files → processed asynchronously, job_id returned immediately.","operationId":"convert_batch_convert_batch_post","parameters":[{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_convert_batch_convert_batch_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchSubmitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/convert/batch/status/{job_id}":{"get":{"tags":["batch"],"summary":"Get Batch Status","description":"Poll the status of an async batch job.","operationId":"get_batch_status_convert_batch_status__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchJobStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/usage/stats":{"get":{"tags":["usage"],"summary":"Get Usage Stats","description":"Authoritative dashboard stats for the caller.","operationId":"get_usage_stats_usage_stats_get","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Usage Stats Usage Stats Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/usage/{user_id}":{"get":{"tags":["usage"],"summary":"Get User Usage","description":"Return current page usage for the caller's authoritative billing plan.","operationId":"get_user_usage_usage__user_id__get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/conversions/history":{"get":{"tags":["conversion-history"],"summary":"Conversion History","description":"Return the caller's own non-sensitive conversion history.","operationId":"conversion_history_conversions_history_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":50,"title":"Limit"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Conversion History Conversions History Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/banks":{"get":{"tags":["banks"],"summary":"List Banks","description":"Return list of supported banks (filesystem profiles only for now).","operationId":"list_banks_banks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BanksResponse"}}}}}}},"/webhooks/paddle":{"post":{"tags":["webhooks"],"summary":"Paddle Webhook","description":"Durable Paddle webhook ingestion endpoint.\n\nReturns 200 ONLY after the event is:\n  - Verified (valid HMAC + fresh timestamp)\n  - Durably stored in payment_webhook_events\n  OR identified as a known duplicate.\n\nProcessing happens asynchronously after the response is sent.","operationId":"paddle_webhook_webhooks_paddle_post","parameters":[{"name":"Paddle-Signature","in":"header","required":true,"schema":{"type":"string","title":"Paddle-Signature"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/portal":{"get":{"tags":["webhooks"],"summary":"Billing Portal","description":"Paddle customer portal redirect.\nTODO P1-04: Implement real Paddle customer portal session creation.","operationId":"billing_portal_billing_portal_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/webhooks/dodo":{"post":{"tags":["webhooks"],"summary":"Dodo Webhook","description":"Durable Dodo Payments webhook ingestion endpoint.\n\nReturns 200 ONLY after the event is:\n  - Signature-verified (Standard Webhooks HMAC-SHA256)\n  - Durably stored in payment_webhook_events with provider=\"dodo\"\n  OR identified as a known duplicate.\n\nProcessing happens asynchronously after the response is sent.","operationId":"dodo_webhook_webhooks_dodo_post","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string","title":"Webhook-Id"}},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"string","title":"Webhook-Timestamp"}},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string","title":"Webhook-Signature"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/webhook/distribb":{"post":{"tags":["webhooks"],"summary":"Distribb Webhook","operationId":"distribb_webhook_api_webhook_distribb_post","parameters":[{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/plan":{"get":{"tags":["billing"],"summary":"Authoritative Plan","description":"Return the caller's AUTHORITATIVE entitlement (the Dodo-billing source of\ntruth used by /convert enforcement). The frontend should treat this — not the\nSupabase get_user_plan RPC — as the plan after a Dodo payment, so UI gating\nmatches what the backend actually enforces. Expired/cancelled subscriptions\nresolve to \"free\" here via the billing state machine.","operationId":"authoritative_plan_billing_plan_get","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/dodo/checkout-session":{"post":{"tags":["billing"],"summary":"Dodo Checkout Session","description":"Create a Dodo Payments hosted-checkout session for the authenticated user.\n\nFlow:\n  1. Validate and normalise plan_name → internal plan_key\n  2. Look up Dodo product_id from server-side product map (env var or defaults)\n  3. Call Dodo API server-side with the API key (never client-side)\n  4. Embed user_id in session metadata so webhooks can provision correctly\n  5. Return { checkout_url, session_id } — client redirects to checkout_url\n\nFails closed if:\n  - plan_name is unknown\n  - DODO_PRODUCT_MAP does not contain the resolved plan_key\n  - Dodo API call fails","operationId":"dodo_checkout_session_billing_dodo_checkout_session_post","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/dodo/verify-checkout":{"post":{"tags":["billing"],"summary":"Dodo Verify Checkout","description":"Provision entitlement directly from Dodo when the webhook has not (yet).\n\nThe Standard-Webhooks path (`/webhooks/dodo`) is the primary sync channel,\nbut a paying customer must never be stuck on the free tier if a webhook is\ndelayed, mis-configured, or fails signature verification. The success page\ncalls this endpoint after checkout; it authoritatively re-reads the\nsubscription from Dodo, confirms it belongs to the authenticated user, and\ndrives it through the SAME billing state machine the webhook uses.\n\nSecurity:\n  - The subscription's `metadata.user_id` MUST equal the authenticated\n    user id. A caller can therefore only ever activate their own\n    subscription, even if they supply an arbitrary id.\n  - Unknown products still fail closed via the shared upsert path.\n\nIdempotent with the webhook: the upsert's event-ordering guard means wh\nichever channel observes the newer state wins; repeat calls are no-ops.","operationId":"dodo_verify_checkout_billing_dodo_verify_checkout_post","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyCheckoutRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/conversions/{conversion_id}/review":{"get":{"tags":["review"],"summary":"Get Review","operationId":"get_review_conversions__conversion_id__review_get","parameters":[{"name":"conversion_id","in":"path","required":true,"schema":{"type":"string","title":"Conversion Id"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Review Conversions  Conversion Id  Review Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/conversions/{conversion_id}/transactions/{transaction_id}":{"patch":{"tags":["review"],"summary":"Correct Transaction","operationId":"correct_transaction_conversions__conversion_id__transactions__transaction_id__patch","parameters":[{"name":"conversion_id","in":"path","required":true,"schema":{"type":"string","title":"Conversion Id"}},{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","title":"Transaction Id"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CorrectionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Correct Transaction Conversions  Conversion Id  Transactions  Transaction Id  Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/conversions/{conversion_id}/reverify":{"post":{"tags":["review"],"summary":"Reverify Conversion","operationId":"reverify_conversion_conversions__conversion_id__reverify_post","parameters":[{"name":"conversion_id","in":"path","required":true,"schema":{"type":"string","title":"Conversion Id"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Reverify Conversion Conversions  Conversion Id  Reverify Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/conversions/{conversion_id}/export":{"post":{"tags":["review"],"summary":"Export Accounting","description":"QuickBooks/Xero export from the re-verified review snapshot.","operationId":"export_accounting_conversions__conversion_id__export_post","parameters":[{"name":"conversion_id","in":"path","required":true,"schema":{"type":"string","title":"Conversion Id"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingExportRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Export Accounting Conversions  Conversion Id  Export Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/previews/{conversion_id}":{"get":{"tags":["preview"],"summary":"Preview Status","operationId":"preview_status_previews__conversion_id__get","parameters":[{"name":"conversion_id","in":"path","required":true,"schema":{"type":"string","title":"Conversion Id"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Preview Status Previews  Conversion Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/previews/{conversion_id}/claim":{"post":{"tags":["preview"],"summary":"Claim Conversion Preview","operationId":"claim_conversion_preview_previews__conversion_id__claim_post","parameters":[{"name":"conversion_id","in":"path","required":true,"schema":{"type":"string","title":"Conversion Id"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimPreviewRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Claim Conversion Preview Previews  Conversion Id  Claim Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/previews/{conversion_id}/release":{"post":{"tags":["preview"],"summary":"Release Conversion Preview","operationId":"release_conversion_preview_previews__conversion_id__release_post","parameters":[{"name":"conversion_id","in":"path","required":true,"schema":{"type":"string","title":"Conversion Id"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Release Conversion Preview Previews  Conversion Id  Release Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/portal-session":{"post":{"summary":"Billing Portal Session","description":"Create a Dodo Payments customer portal session for the authenticated user.\n\nLooks up the user's Dodo customer_id from the subscription that currently\ngrants access, then calls the Dodo API to generate a time-bound portal link.\nFalls back to a support message if no live Dodo subscription exists yet.\n\nThe customer portal lets users:\n  - View billing history and download invoices\n  - Cancel or view subscription details\n  - Update payment methods\n  - Retrieve license keys","operationId":"billing_portal_session_billing_portal_session_post","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string","title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/download/{filename}":{"get":{"summary":"Download File","description":"Serve generated Excel/CSV output files.\n\nAccepts either a verified JWT (registered/paid users) or the anonymous\ntier (no Authorization + X-User-Plan: anonymous → IP+UA identity). In both\ncases the DB ownership check (OutputFile.user_id == auth.user_id) + expiry\nscope the file to its owner: an anonymous visitor only matches files their\nown conversion stamped with the same anon id, within the 1-hour window.\nIf R2 is configured, redirects to a fresh presigned URL (5 min); otherwise\nserves the local file directly.","operationId":"download_file_download__filename__get","parameters":[{"name":"filename","in":"path","required":true,"schema":{"type":"string","title":"Filename"}},{"name":"Authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"X-User-Id","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-User-Id"}},{"name":"X-User-Plan","in":"header","required":false,"schema":{"type":"string","default":"free","title":"X-User-Plan"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AccountingExportRequest":{"properties":{"format":{"type":"string","title":"Format"},"columns":{"type":"string","title":"Columns","default":"3-column"},"date_format":{"type":"string","title":"Date Format","default":"MM/DD/YYYY"}},"type":"object","required":["format"],"title":"AccountingExportRequest"},"BankProfile":{"properties":{"bank_name":{"type":"string","title":"Bank Name"},"profile_source":{"type":"string","enum":["filesystem","database"],"title":"Profile Source"},"parser_type":{"type":"string","title":"Parser Type","default":"profile"},"account_statement_support":{"type":"string","title":"Account Statement Support","default":"supported"},"credit_statement_support":{"type":"string","title":"Credit Statement Support","default":"unknown"},"safety_check":{"type":"string","title":"Safety Check","default":"available"},"ocr_support":{"type":"string","title":"Ocr Support","default":"available"},"last_verified":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Verified"},"notes":{"items":{"type":"string"},"type":"array","title":"Notes"}},"type":"object","required":["bank_name","profile_source"],"title":"BankProfile"},"BanksResponse":{"properties":{"supported_banks":{"items":{"$ref":"#/components/schemas/BankProfile"},"type":"array","title":"Supported Banks"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["supported_banks","total"],"title":"BanksResponse"},"BatchFileResult":{"properties":{"conversion_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Conversion Id"},"filename":{"type":"string","title":"Filename"},"status":{"type":"string","enum":["complete","failed","processing","queued"],"title":"Status"},"bank_detected":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bank Detected"},"verification_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Verification Status"},"pdf_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pdf Type"},"ocr_preprocessing_used":{"type":"boolean","title":"Ocr Preprocessing Used","default":false},"quality_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Quality Score"},"review_required":{"type":"boolean","title":"Review Required","default":false},"transaction_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Transaction Count"},"page_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Count"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"download_urls":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":"object","title":"Download Urls"},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings"}},"type":"object","required":["filename","status"],"title":"BatchFileResult"},"BatchJobStatus":{"properties":{"job_id":{"type":"string","title":"Job Id"},"status":{"type":"string","enum":["pending","processing","complete","failed"],"title":"Status"},"progress":{"additionalProperties":{"type":"integer"},"type":"object","title":"Progress"},"current_file":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Current File"},"file_results":{"items":{"$ref":"#/components/schemas/BatchFileResult"},"type":"array","title":"File Results"},"total_transactions":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Transactions"},"total_pages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Pages"},"verified_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Verified Count"},"discrepancy_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Discrepancy Count"},"failed_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Failed Count"},"merged_download_urls":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":"object","title":"Merged Download Urls"},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["job_id","status"],"title":"BatchJobStatus","description":"Returned by GET /convert/batch/status/{job_id}."},"BatchSubmitResponse":{"properties":{"job_id":{"type":"string","title":"Job Id"},"status":{"type":"string","enum":["processing","complete","failed"],"title":"Status"},"file_count":{"type":"integer","title":"File Count"},"estimated_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Estimated Seconds"},"result":{"anyOf":[{"$ref":"#/components/schemas/BatchJobStatus"},{"type":"null"}]}},"type":"object","required":["job_id","status","file_count"],"title":"BatchSubmitResponse","description":"Returned immediately after POST /convert/batch."},"Body_convert_batch_convert_batch_post":{"properties":{"files":{"items":{"type":"string","contentMediaType":"application/octet-stream"},"type":"array","title":"Files"}},"type":"object","required":["files"],"title":"Body_convert_batch_convert_batch_post"},"Body_convert_pdf_convert_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"}},"type":"object","required":["file"],"title":"Body_convert_pdf_convert_post"},"Body_convert_to_accounting_convert_accounting_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"format":{"type":"string","title":"Format","default":"ofx"},"account_id":{"type":"string","title":"Account Id","default":"UNKNOWN"},"bank_id":{"type":"string","title":"Bank Id","default":"ClearlyLedger"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"},"date_format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date Format"}},"type":"object","required":["file"],"title":"Body_convert_to_accounting_convert_accounting_post"},"Body_convert_to_gnucash_convert_gnucash_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"format":{"type":"string","title":"Format","default":"csv"},"layout":{"type":"string","title":"Layout","default":"split"},"date_format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date Format"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"}},"type":"object","required":["file"],"title":"Body_convert_to_gnucash_convert_gnucash_post"},"Body_convert_to_quickbooks_convert_quickbooks_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"columns":{"type":"string","title":"Columns","default":"3-column"},"date_format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date Format"}},"type":"object","required":["file"],"title":"Body_convert_to_quickbooks_convert_quickbooks_post"},"Body_convert_to_xero_convert_xero_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"date_format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date Format"}},"type":"object","required":["file"],"title":"Body_convert_to_xero_convert_xero_post"},"CheckoutRequest":{"properties":{"plan_name":{"type":"string","title":"Plan Name"},"affonso_referral":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Affonso Referral"}},"type":"object","required":["plan_name"],"title":"CheckoutRequest"},"ClaimPreviewRequest":{"properties":{"claim_token":{"type":"string","title":"Claim Token","default":""}},"type":"object","title":"ClaimPreviewRequest"},"ConversionResult":{"properties":{"conversion_id":{"type":"string","title":"Conversion Id"},"bank_detected":{"type":"string","title":"Bank Detected"},"was_known_profile":{"type":"boolean","title":"Was Known Profile"},"statement_type":{"type":"string","enum":["bank_account","credit_card"],"title":"Statement Type","default":"bank_account"},"pdf_type":{"type":"string","enum":["text_based","scanned","camt_xml","structured"],"title":"Pdf Type"},"verification_status":{"type":"string","enum":["VERIFIED","DISCREPANCY","FAILED","UNVERIFIED"],"title":"Verification Status"},"opening_balance":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Opening Balance"},"closing_balance":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Closing Balance"},"computed_closing_balance":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Computed Closing Balance"},"balance_diff":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Balance Diff"},"transaction_count":{"type":"integer","title":"Transaction Count"},"page_count":{"type":"integer","title":"Page Count"},"low_confidence_rows":{"type":"integer","title":"Low Confidence Rows"},"llm_corrected_rows":{"type":"integer","title":"Llm Corrected Rows"},"llm_calls_made":{"type":"integer","title":"Llm Calls Made"},"llm_cost_usd":{"type":"number","title":"Llm Cost Usd"},"camelot_accuracy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Camelot Accuracy"},"flagged_row_count":{"type":"integer","title":"Flagged Row Count","default":0},"delta_verification_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delta Verification Status"},"ocr_preprocessing_used":{"type":"boolean","title":"Ocr Preprocessing Used","default":false},"ocr_mean_confidence":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Ocr Mean Confidence"},"category_summary":{"additionalProperties":{"type":"integer"},"type":"object","title":"Category Summary"},"revenue_expense_summary":{"anyOf":[{"$ref":"#/components/schemas/RevenueExpenseSummary"},{"type":"null"}]},"revenue_expense_report_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revenue Expense Report Token"},"quality_score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Quality Score","default":0.0},"review_required":{"type":"boolean","title":"Review Required","default":true},"extraction_profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Extraction Profile"},"unsupported_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unsupported Reason"},"profile_candidate_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile Candidate Id"},"full_page_llm_used":{"type":"boolean","title":"Full Page Llm Used","default":false},"page_coverage":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Page Coverage"},"credit_card_summary":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Credit Card Summary"},"statement_period":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Statement Period"},"statement_region":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Statement Region"},"detected_language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detected Language"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"},"account_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Number"},"source_integrity_validated":{"type":"boolean","title":"Source Integrity Validated","default":false},"transactions":{"items":{"$ref":"#/components/schemas/Transaction"},"type":"array","title":"Transactions"},"download_urls":{"additionalProperties":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":"object","title":"Download Urls"},"delivery":{"anyOf":[{"$ref":"#/components/schemas/PreviewDelivery"},{"type":"null"}]},"customer_outcome":{"$ref":"#/components/schemas/CustomerOutcome"},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings"},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"}},"type":"object","required":["conversion_id","bank_detected","was_known_profile","pdf_type","verification_status","transaction_count","page_count","low_confidence_rows","llm_corrected_rows","llm_calls_made","llm_cost_usd","transactions","download_urls","customer_outcome"],"title":"ConversionResult"},"CorrectionRequest":{"properties":{"revision":{"type":"integer","minimum":0.0,"title":"Revision"},"fields":{"additionalProperties":true,"type":"object","title":"Fields"}},"type":"object","required":["revision"],"title":"CorrectionRequest"},"CustomerOutcome":{"properties":{"code":{"type":"string","enum":["download_ready","review_required","password_required","different_source_recommended","plan_required","retry_available","download_expired","support_required"],"title":"Code"},"message":{"type":"string","title":"Message"},"next_action":{"type":"string","enum":["download","review_statement","enter_password","upload_alternative","choose_plan","retry","upload_replacement","contact_support"],"title":"Next Action"},"retryable":{"type":"boolean","title":"Retryable","default":false},"support_reference":{"type":"string","title":"Support Reference"},"action_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Action Path"},"required_plan":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Required Plan"}},"type":"object","required":["code","message","next_action","support_reference"],"title":"CustomerOutcome","description":"One stable, plain-language next action for a conversion state."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponse":{"properties":{"status":{"type":"string","title":"Status"},"version":{"type":"string","title":"Version"},"db":{"type":"string","title":"Db","default":"ok"}},"type":"object","required":["status","version"],"title":"HealthResponse"},"PreviewDelivery":{"properties":{"state":{"type":"string","enum":["released","preview_withheld","review_required","unavailable"],"title":"State"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"},"source_page_count":{"type":"integer","minimum":0.0,"title":"Source Page Count"},"converted_page_count":{"type":"integer","minimum":0.0,"title":"Converted Page Count"},"required_plan":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Required Plan"},"claim_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Claim Token"},"claim_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Claim Expires At"}},"type":"object","required":["state","source_page_count","converted_page_count"],"title":"PreviewDelivery","description":"Structured delivery decision; claim_token is returned once on create."},"RevenueExpenseCategoryRow":{"properties":{"category":{"type":"string","title":"Category"},"direction":{"type":"string","enum":["inflow","outflow"],"title":"Direction"},"classification":{"type":"string","enum":["candidate_income","candidate_expense","excluded","unclassified"],"title":"Classification"},"amount":{"type":"number","minimum":0.0,"title":"Amount"},"transaction_count":{"type":"integer","minimum":1.0,"title":"Transaction Count"}},"type":"object","required":["category","direction","classification","amount","transaction_count"],"title":"RevenueExpenseCategoryRow"},"RevenueExpenseMonthlyRow":{"properties":{"month":{"type":"string","pattern":"^\\d{4}-\\d{2}$","title":"Month"},"inflows":{"type":"number","minimum":0.0,"title":"Inflows"},"outflows":{"type":"number","minimum":0.0,"title":"Outflows"},"net_cash_movement":{"type":"number","title":"Net Cash Movement"}},"type":"object","required":["month","inflows","outflows","net_cash_movement"],"title":"RevenueExpenseMonthlyRow"},"RevenueExpenseReportRequest":{"properties":{"conversion_id":{"type":"string","maxLength":64,"minLength":1,"title":"Conversion Id"},"report_token":{"type":"string","maxLength":4096,"minLength":1,"title":"Report Token"},"transactions":{"items":{"$ref":"#/components/schemas/Transaction"},"type":"array","maxItems":20000,"minItems":1,"title":"Transactions"},"statement_type":{"type":"string","enum":["bank_account","credit_card"],"title":"Statement Type","default":"bank_account"},"default_currency":{"anyOf":[{"type":"string","pattern":"^[A-Za-z]{3}$"},{"type":"null"}],"title":"Default Currency"}},"type":"object","required":["conversion_id","report_token","transactions"],"title":"RevenueExpenseReportRequest"},"RevenueExpenseSummary":{"properties":{"basis":{"type":"string","const":"cash","title":"Basis","default":"cash"},"status":{"type":"string","const":"draft","title":"Status","default":"draft"},"currency":{"type":"string","pattern":"^[A-Z]{3}$","title":"Currency"},"period_start":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period Start"},"period_end":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period End"},"total_inflows":{"type":"number","minimum":0.0,"title":"Total Inflows"},"total_outflows":{"type":"number","minimum":0.0,"title":"Total Outflows"},"net_cash_movement":{"type":"number","title":"Net Cash Movement"},"candidate_income":{"type":"number","minimum":0.0,"title":"Candidate Income"},"candidate_expenses":{"type":"number","minimum":0.0,"title":"Candidate Expenses"},"unclassified_inflows":{"type":"number","minimum":0.0,"title":"Unclassified Inflows"},"unclassified_outflows":{"type":"number","minimum":0.0,"title":"Unclassified Outflows"},"excluded_inflows":{"type":"number","minimum":0.0,"title":"Excluded Inflows"},"excluded_outflows":{"type":"number","minimum":0.0,"title":"Excluded Outflows"},"classified_activity":{"type":"number","minimum":0.0,"title":"Classified Activity"},"total_activity":{"type":"number","minimum":0.0,"title":"Total Activity"},"classification_coverage":{"type":"number","maximum":100.0,"minimum":0.0,"title":"Classification Coverage"},"category_rows":{"items":{"$ref":"#/components/schemas/RevenueExpenseCategoryRow"},"type":"array","title":"Category Rows"},"monthly_rows":{"items":{"$ref":"#/components/schemas/RevenueExpenseMonthlyRow"},"type":"array","title":"Monthly Rows"},"disclaimer":{"type":"string","title":"Disclaimer"}},"type":"object","required":["currency","total_inflows","total_outflows","net_cash_movement","candidate_income","candidate_expenses","unclassified_inflows","unclassified_outflows","excluded_inflows","excluded_outflows","classified_activity","total_activity","classification_coverage","disclaimer"],"title":"RevenueExpenseSummary"},"Transaction":{"properties":{"date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date"},"description":{"type":"string","title":"Description"},"ref_no":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ref No"},"value_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Value Date"},"debit":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Debit"},"credit":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Credit"},"balance":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Balance"},"confidence":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Confidence"},"method":{"type":"string","enum":["deterministic","llm","camelot","camt_xml","table_recovery"],"title":"Method"},"page_num":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Num"},"category":{"type":"string","title":"Category","default":"uncategorized"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"},"account_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Number"},"transaction_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transaction Hash"},"evidence_codes":{"items":{"type":"string"},"type":"array","title":"Evidence Codes"},"review_reasons":{"items":{"type":"string"},"type":"array","title":"Review Reasons"},"txn_kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Txn Kind"}},"type":"object","required":["description","confidence","method"],"title":"Transaction"},"UsageResponse":{"properties":{"user_id":{"type":"string","title":"User Id"},"month":{"type":"string","title":"Month"},"pages_used":{"type":"integer","title":"Pages Used"},"pages_limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pages Limit"},"conversions":{"type":"integer","title":"Conversions","default":0}},"type":"object","required":["user_id","month","pages_used"],"title":"UsageResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VerifyCheckoutRequest":{"properties":{"subscription_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subscription Id"},"session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Id"}},"type":"object","title":"VerifyCheckoutRequest","description":"Return-page verification payload.\n\nEither identifier may be supplied (Dodo appends `subscription_id`/`status`\nto the configured return_url on subscription checkouts). Both are optional:\nwhen neither is present the endpoint falls back to the caller's stored\ncheckout intent session id."}}}}