{"openapi":"3.1.0","info":{"title":"Billing — DayZero API","version":"1.0.0","description":"Subscription billing, plan management, and usage tracking."},"servers":[{"url":"https://api.ondayzero.com","description":"Production"}],"paths":{"/api/v1/billing/catalog":{"get":{"tags":["billing"],"summary":"Get Billing Catalog","description":"Return the Stripe price catalog (slug → price details).\n\nUsed by the frontend to get price IDs for checkout without hardcoding.\nAnnual variants are stored as ``<slug>_annual`` entries.","operationId":"get_billing_catalog","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_GetBillingCatalogResponse_"}}}}},"x-fastapi-operation-id":"get_billing_catalog_api_v1_billing_catalog_get"}},"/api/v1/billing/pricing-config":{"get":{"tags":["billing"],"summary":"Get Pricing Config","description":"Return billing pricing configuration derived from the single discount knob.\n\nThe frontend uses this to render annual savings and badge labels without\nduplicating the discount percentage. Changing the discount on the backend\n(``ANNUAL_DISCOUNT_PCT``) automatically updates every UI surface.\n\n**Returns:**\n- `annual_discount_pct`: Fractional annual discount (e.g. `0.1667`).\n- `annual_discount_label`: Human label for the annual badge.","operationId":"get_pricing_config","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_GetPricingConfigResponse_"}}}}},"x-fastapi-operation-id":"get_pricing_config_api_v1_billing_pricing_config_get"}},"/api/v1/billing/status":{"get":{"tags":["billing"],"summary":"Get Billing Status","description":"Return the current billing state for the authenticated business.","operationId":"get_billing_status","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_GetBillingStatusResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"get_billing_status_api_v1_billing_status_get"}},"/api/v1/billing/ai-usage":{"get":{"tags":["billing"],"summary":"Get Ai Usage","description":"Return current daily and monthly AI request counts with plan limits.","operationId":"get_ai_usage","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_GetAiUsageResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"get_ai_usage_api_v1_billing_ai_usage_get"}},"/api/v1/billing/ai/pause":{"post":{"tags":["billing"],"summary":"Pause Ai Features","description":"Pause all AI features for the authenticated business.\n\nSets ``businesses.ai_paused_at`` so:\n- ``check_ai_quota`` returns ``allowed=False, paused=True`` for any\n  subsequent AI call (chat, panels, OCR, etc.).\n- ``track_business_usage`` short-circuits, stopping the Stripe\n  overage fire-and-forget.\n- ``AITransactionCleaner`` downshifts to rule-only cleaning during\n  Plaid sync (no LLM calls).\n\nIdempotent. Returns the refreshed AI usage payload so the widget /\nbanner can transition to the paused state without a second\nround-trip.","operationId":"pause_ai_features","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_PauseAiFeaturesResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"pause_ai_features_api_v1_billing_ai_pause_post"}},"/api/v1/billing/ai/resume":{"post":{"tags":["billing"],"summary":"Resume Ai Features","description":"Resume AI features for the authenticated business.\n\nClears ``ai_paused_at`` and ``ai_paused_by_user_id``. Idempotent —\nresuming an already-active business is a no-op. Returns the\nrefreshed AI usage payload so the widget transitions back to the\nCalm / Warning / Overage state without a second round-trip.","operationId":"resume_ai_features","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_ResumeAiFeaturesResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"resume_ai_features_api_v1_billing_ai_resume_post"}},"/api/v1/billing/checkout":{"post":{"tags":["billing"],"summary":"Create Checkout Session","description":"Create a Stripe Checkout session so the user can subscribe.\n\nRefused (400 `BILLING_023`) on a business billed under a partner\nagreement (`partner_program`): its plan is set by the agreement.","operationId":"create_checkout_session","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_CreateCheckoutSessionResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"create_checkout_session_api_v1_billing_checkout_post"}},"/api/v1/billing/portal":{"post":{"tags":["billing"],"summary":"Create Portal Session","description":"Create a Stripe Billing Portal session for subscription management.\n\nOpen to every plan: the portal cannot start a subscription, and on a\nbusiness billed under a partner agreement it is how a subscription from\nbefore the agreement is cancelled.","operationId":"create_portal_session","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_CreatePortalSessionResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"create_portal_session_api_v1_billing_portal_post"}},"/api/v1/billing/addon/preview":{"post":{"tags":["billing"],"summary":"Preview Addon Change","description":"Preview the billing impact of adding or removing an add-on.\n\n**Request Body:**\n- `addon_slug`: Add-on module slug from AddOnModule enum\n- `action`: 'add' or 'remove'\n\n**Returns:** Prorated amount (cents; `null` when Stripe could not\nproduce a preview), addon price, and effective date for removals.\nRefused (400 `BILLING_023`) on a business billed under a partner\nagreement.","operationId":"preview_addon_change","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddonPreviewRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_PreviewAddonChangeResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"preview_addon_change_api_v1_billing_addon_preview_post"}},"/api/v1/billing/addon":{"post":{"tags":["billing"],"summary":"Toggle Addon","description":"Add or remove an add-on from the business's Stripe subscription.\n\n**Request Body:**\n- `addon_slug`: Add-on module slug from AddOnModule enum\n- `action`: 'add' (charges prorated amount immediately) or 'remove' (effective at period end, no refund)\n\n**Effect:**\n- Adding: Stripe subscription is updated, prorated amount is charged immediately\n- Removing: Item removed with no proration, takes effect at period end\n\n**Returns:** Updated active_addons list and effective date. Refused\n(400 `BILLING_023`) on a business billed under a partner agreement, whose\nadd-ons the agreement sets.","operationId":"toggle_addon","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddonToggleRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_ToggleAddonResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"toggle_addon_api_v1_billing_addon_post"}},"/api/v1/billing/grandfathered-summary":{"get":{"tags":["billing"],"summary":"Get Grandfathered Summary","description":"Return a summary of the grandfathered business's current access and available plans.\n\n**Returns:**\n- `current_access`: What the grandfathered account includes today\n- `available_plans`: Plans the business can migrate to with pricing","operationId":"get_grandfathered_summary","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_GetGrandfatheredSummaryResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"get_grandfathered_summary_api_v1_billing_grandfathered_summary_get"}},"/api/v1/billing/grandfather":{"post":{"tags":["billing"],"summary":"Grandfather the current business (superuser only)","description":"Mark the current business as grandfathered so it keeps access without billing.\n\n**Effect:**\n- Sets ``plan_tier`` to ``grandfathered`` and ``billing_status`` to ``active``\n- Clears ``trial_ends_at``\n- Grants the default grandfathered add-on set\n\n**Prerequisites:**\n- Caller must be a superuser. Regular users never see this in the UI\n  and receive 403 if they call the endpoint directly.","operationId":"grandfather_business","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_GrandfatherBusinessResponse_"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"grandfather_business_api_v1_billing_grandfather_post"}},"/api/v1/billing/migrate-from-grandfathered":{"post":{"tags":["billing"],"summary":"Migrate grandfathered account to a paid plan","description":"Create a Stripe Checkout session to move from a grandfathered plan to a paid plan.\n\n**Request Body:**\n- `target_plan`: Plan tier to migrate to (`self_directed` or `managed`)\n- `success_url`: Redirect URL after successful payment\n- `cancel_url`: Redirect URL if checkout is canceled\n\n**Prerequisites:**\n- Business must currently be on the `grandfathered` plan tier\n\n**Effect:**\n- Creates a Stripe Checkout session\n- On payment completion, `plan_tier` is updated to the target plan\n\n**Returns:** Checkout URL and session ID.","operationId":"migrate_from_grandfathered","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrandfatheredMigrateRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_MigrateFromGrandfatheredResponse_"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"example":{"error":"validation_error","message":"Validation failed: due_date: Input should be a valid date","errors":{"due_date":"Input should be a valid date"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"migrate_from_grandfathered_api_v1_billing_migrate_from_grandfathered_post"}},"/api/v1/billing/change-plan":{"post":{"tags":["billing"],"summary":"Change Plan","description":"Switch the base subscription plan to a different price.\n\n**Request Body:**\n- `price_id`: Stripe Price ID for the new plan\n\n**Effect:** The base plan line item is swapped and the proration is invoiced immediately.\nRefused (400 `BILLING_023`) on a business billed under a partner agreement.","operationId":"change_plan","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanChangeRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_ChangePlanResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"change_plan_api_v1_billing_change_plan_post"}},"/api/v1/billing/firm/client-usage":{"get":{"tags":["billing"],"summary":"Get Firm Client Usage","description":"Return the firm's active client count, tier cap, and remaining seats.\n\nFor non-advisory businesses (self-directed/managed) this returns\n``is_advisory_firm: false`` with no limit so callers can hide the\nclient/upgrade UI.","operationId":"get_firm_client_usage","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_GetFirmClientUsageResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"get_firm_client_usage_api_v1_billing_firm_client_usage_get"}},"/api/v1/billing/firm/change-tier":{"post":{"tags":["billing"],"summary":"Change Firm Tier","description":"Upgrade or downgrade the firm's plan tier, in-app.\n\nSwaps the per-client price, adds/removes the platform fee, and re-applies\nthe current client quantity in one prorated Stripe update. Requires the\ncaller to be an owner/admin of the firm. Blocks a downgrade that would drop\nthe firm below its current client count.","operationId":"change_firm_tier","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FirmTierChangeRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_ChangeFirmTierResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"change_firm_tier_api_v1_billing_firm_change_tier_post"}},"/api/v1/billing/invoices":{"get":{"tags":["billing"],"summary":"Get Invoice History","description":"Return the business's Stripe subscription invoice history.\n\nEach invoice includes a hosted URL for viewing and a PDF download link.","operationId":"get_invoice_history","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Max invoices to return","default":24,"title":"Limit"},"description":"Max invoices to return"},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_GetInvoiceHistoryResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"get_invoice_history_api_v1_billing_invoices_get"}},"/api/v1/billing/ai-usage/details":{"get":{"tags":["billing"],"summary":"Get Ai Usage Details","description":"Return detailed AI usage stats: top users, model breakdown, daily trend.\n\n**Query Parameters:**\n- `scope`: Optional. Set to 'firm' to see firm-wide AI usage.\n\n**Returns:** Summary, top_users, by_model, daily arrays.","operationId":"get_ai_usage_details","parameters":[{"name":"scope","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set to 'firm' to aggregate across all firm businesses.","title":"Scope"},"description":"Set to 'firm' to aggregate across all firm businesses."},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_GetAiUsageDetailsResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"validation_error","message":"Validation failed: amount: Input should be a valid integer","errors":{"amount":"Input should be a valid integer"},"code":"GEN_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"401":{"description":"Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"unauthorized","message":"Authentication required","code":"AUTH_001","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"forbidden","message":"You don't have permission to access this resource","code":"AUTH_002","request_id":"3f0e7c2a-9b4d-4e1a-8c6f-2d5b7a1e9c30"}}}}},"x-fastapi-operation-id":"get_ai_usage_details_api_v1_billing_ai_usage_details_get"}}},"components":{"schemas":{"AIOverageBreakdown":{"properties":{"light":{"type":"integer","title":"Light"},"standard":{"type":"integer","title":"Standard"},"heavy":{"type":"integer","title":"Heavy"}},"additionalProperties":true,"type":"object","required":["light","standard","heavy"],"title":"AIOverageBreakdown"},"AIOverageRatesCents":{"properties":{"light":{"type":"integer","title":"Light"},"standard":{"type":"integer","title":"Standard"},"heavy":{"type":"integer","title":"Heavy"}},"additionalProperties":true,"type":"object","required":["light","standard","heavy"],"title":"AIOverageRatesCents"},"AIUpgradeSuggestion":{"properties":{"addon_or_plan_slug":{"type":"string","title":"Addon Or Plan Slug"},"label":{"type":"string","title":"Label"},"monthly_quota":{"type":"integer","title":"Monthly Quota"},"monthly_price_cents":{"type":"integer","title":"Monthly Price Cents"},"would_save_cents":{"type":"integer","title":"Would Save Cents"}},"additionalProperties":true,"type":"object","required":["addon_or_plan_slug","label","monthly_quota","monthly_price_cents","would_save_cents"],"title":"AIUpgradeSuggestion"},"AIUsageByModel":{"properties":{"model":{"type":"string","title":"Model"},"requests":{"type":"integer","title":"Requests"},"tokens":{"type":"integer","title":"Tokens"},"pct":{"type":"number","title":"Pct"}},"additionalProperties":true,"type":"object","required":["model","requests","tokens","pct"],"title":"AIUsageByModel"},"AIUsageDaily":{"properties":{"date":{"type":"string","title":"Date"},"requests":{"type":"integer","title":"Requests"},"tokens":{"type":"integer","title":"Tokens"}},"additionalProperties":true,"type":"object","required":["date","requests","tokens"],"title":"AIUsageDaily"},"AIUsageDetailsSummary":{"properties":{"requests_used":{"type":"integer","title":"Requests Used"},"monthly_limit":{"type":"integer","title":"Monthly Limit"},"is_unlimited":{"type":"boolean","title":"Is Unlimited"},"total_tokens":{"type":"integer","title":"Total Tokens"},"estimated_cost_usd":{"type":"number","title":"Estimated Cost Usd"},"unique_users":{"type":"integer","title":"Unique Users"},"plan_tier":{"type":"string","title":"Plan Tier"},"has_ai_pro":{"type":"boolean","title":"Has Ai Pro"},"is_trial":{"type":"boolean","title":"Is Trial"}},"additionalProperties":true,"type":"object","required":["requests_used","monthly_limit","is_unlimited","total_tokens","estimated_cost_usd","unique_users","plan_tier","has_ai_pro","is_trial"],"title":"AIUsageDetailsSummary"},"AIUsageTopUser":{"properties":{"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"name":{"type":"string","title":"Name"},"requests":{"type":"integer","title":"Requests"},"tokens":{"type":"integer","title":"Tokens"},"pct":{"type":"number","title":"Pct"}},"additionalProperties":true,"type":"object","required":["name","requests","tokens","pct"],"title":"AIUsageTopUser"},"AddonPreviewRequest":{"properties":{"addon_slug":{"type":"string","title":"Addon Slug","description":"Add-on module slug (e.g. 'ai_pro')."},"action":{"type":"string","enum":["add","remove"],"title":"Action","description":"'add' or 'remove'."}},"type":"object","required":["addon_slug","action"],"title":"AddonPreviewRequest"},"AddonToggleRequest":{"properties":{"addon_slug":{"type":"string","title":"Addon Slug","description":"Add-on module slug (e.g. 'ai_pro')."},"action":{"type":"string","enum":["add","remove"],"title":"Action","description":"'add' or 'remove'."}},"type":"object","required":["addon_slug","action"],"title":"AddonToggleRequest"},"BillingInvoiceItem":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Number"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"amount_due":{"type":"integer","title":"Amount Due","default":0},"amount_paid":{"type":"integer","title":"Amount Paid","default":0},"currency":{"type":"string","title":"Currency","default":"usd"},"created":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Created"},"period_start":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Period Start"},"period_end":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Period End"},"hosted_invoice_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hosted Invoice Url"},"invoice_pdf":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invoice Pdf"}},"additionalProperties":true,"type":"object","title":"BillingInvoiceItem"},"ChangeFirmTierResponse":{"properties":{"status":{"type":"string","title":"Status"},"firm_plan_tier":{"type":"string","title":"Firm Plan Tier"},"previous_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Previous Tier"},"active_clients":{"type":"integer","title":"Active Clients"}},"additionalProperties":true,"type":"object","required":["status","firm_plan_tier","active_clients"],"title":"ChangeFirmTierResponse","description":"Response for ``change_firm_tier``."},"ChangePlanResponse":{"properties":{"status":{"type":"string","title":"Status"},"subscription_id":{"type":"string","title":"Subscription Id"}},"additionalProperties":true,"type":"object","required":["status","subscription_id"],"title":"ChangePlanResponse","description":"Response for ``change_plan``."},"CheckoutRequest":{"properties":{"price_id":{"type":"string","title":"Price Id","description":"Stripe Price ID for the plan."},"success_url":{"type":"string","title":"Success Url","description":"URL to redirect after successful payment."},"cancel_url":{"type":"string","title":"Cancel Url","description":"URL to redirect if checkout is canceled."}},"type":"object","required":["price_id","success_url","cancel_url"],"title":"CheckoutRequest"},"CreateCheckoutSessionResponse":{"properties":{"checkout_url":{"type":"string","title":"Checkout Url"},"session_id":{"type":"string","title":"Session Id"}},"additionalProperties":true,"type":"object","required":["checkout_url","session_id"],"title":"CreateCheckoutSessionResponse","description":"Response for ``create_checkout_session``."},"CreatePortalSessionResponse":{"properties":{"portal_url":{"type":"string","title":"Portal Url"}},"additionalProperties":true,"type":"object","required":["portal_url"],"title":"CreatePortalSessionResponse","description":"Response for ``create_portal_session``."},"FirmTierChangeRequest":{"properties":{"firm_plan_tier":{"type":"string","title":"Firm Plan Tier","description":"Target firm tier: 'firm_starter', 'firm_professional', or 'firm_enterprise'."}},"type":"object","required":["firm_plan_tier"],"title":"FirmTierChangeRequest"},"FirmTierOption":{"properties":{"value":{"type":"string","title":"Value"},"client_limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Client Limit"}},"additionalProperties":true,"type":"object","required":["value"],"title":"FirmTierOption"},"GetAiUsageDetailsResponse":{"properties":{"summary":{"$ref":"#/components/schemas/AIUsageDetailsSummary"},"top_users":{"items":{"$ref":"#/components/schemas/AIUsageTopUser"},"type":"array","title":"Top Users"},"by_model":{"anyOf":[{"items":{"$ref":"#/components/schemas/AIUsageByModel"},"type":"array"},{"type":"null"}],"title":"By Model"},"daily":{"items":{"$ref":"#/components/schemas/AIUsageDaily"},"type":"array","title":"Daily"}},"additionalProperties":true,"type":"object","required":["summary","top_users","daily"],"title":"GetAiUsageDetailsResponse","description":"Response for ``get_ai_usage_details``."},"GetAiUsageResponse":{"properties":{"requests_used":{"type":"integer","title":"Requests Used"},"monthly_limit":{"type":"integer","title":"Monthly Limit"},"remaining":{"type":"integer","title":"Remaining"},"is_unlimited":{"type":"boolean","title":"Is Unlimited"},"plan_tier":{"type":"string","title":"Plan Tier"},"has_ai_pro":{"type":"boolean","title":"Has Ai Pro"},"is_trial":{"type":"boolean","title":"Is Trial"},"overage_enabled":{"type":"boolean","title":"Overage Enabled"},"overage_requests":{"type":"integer","title":"Overage Requests"},"overage_rates_cents":{"$ref":"#/components/schemas/AIOverageRatesCents"},"overage_breakdown":{"$ref":"#/components/schemas/AIOverageBreakdown"},"estimated_overage_cost_cents":{"type":"integer","title":"Estimated Overage Cost Cents"},"projected_month_end_overage_cents":{"type":"integer","title":"Projected Month End Overage Cents"},"ai_paused_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ai Paused At"},"ai_paused_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ai Paused By"},"upgrade_suggestion":{"anyOf":[{"$ref":"#/components/schemas/AIUpgradeSuggestion"},{"type":"null"}]},"disabled_features_when_paused":{"items":{"type":"string"},"type":"array","title":"Disabled Features When Paused"}},"additionalProperties":true,"type":"object","required":["requests_used","monthly_limit","remaining","is_unlimited","plan_tier","has_ai_pro","is_trial","overage_enabled","overage_requests","overage_rates_cents","overage_breakdown","estimated_overage_cost_cents","projected_month_end_overage_cents","disabled_features_when_paused"],"title":"GetAiUsageResponse","description":"Response for ``get_ai_usage`` (also returned by pause/resume)."},"GetBillingCatalogResponse":{"properties":{},"additionalProperties":true,"type":"object","title":"GetBillingCatalogResponse","description":"Stripe slug → price details (handler returns the catalog dict directly).\n\nKeys are catalog slugs; values match :class:`BillingCatalogEntry`."},"GetBillingStatusResponse":{"properties":{"billing_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Billing Status"},"plan_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plan Tier"},"firm_plan_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firm Plan Tier"},"trial_ends_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trial Ends At"},"trial_days_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Trial Days Remaining"},"is_billing_active":{"type":"boolean","title":"Is Billing Active"},"has_stripe_subscription":{"type":"boolean","title":"Has Stripe Subscription"},"active_addons":{"items":{"type":"string"},"type":"array","title":"Active Addons"},"grandfathered_addons":{"items":{"type":"string"},"type":"array","title":"Grandfathered Addons"},"firm_bundled_addons":{"items":{"type":"string"},"type":"array","title":"Firm Bundled Addons","default":[]},"unlocked_addons":{"items":{"type":"string"},"type":"array","title":"Unlocked Addons","default":[]},"subscription_period_end":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subscription Period End"},"monthly_total":{"type":"integer","title":"Monthly Total"},"annual_total":{"type":"integer","title":"Annual Total","default":0},"billing_interval":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Billing Interval"},"base_plan_price":{"type":"integer","title":"Base Plan Price","default":0},"is_demo":{"type":"boolean","title":"Is Demo","default":false}},"additionalProperties":true,"type":"object","required":["is_billing_active","has_stripe_subscription","active_addons","grandfathered_addons","monthly_total"],"title":"GetBillingStatusResponse","description":"Response for ``get_billing_status``."},"GetFirmClientUsageResponse":{"properties":{"is_advisory_firm":{"type":"boolean","title":"Is Advisory Firm"},"firm_plan_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firm Plan Tier"},"active_clients":{"type":"integer","title":"Active Clients"},"client_limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Client Limit"},"seats_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seats Remaining"},"can_add_client":{"type":"boolean","title":"Can Add Client"},"tiers":{"items":{"$ref":"#/components/schemas/FirmTierOption"},"type":"array","title":"Tiers"},"firm_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firm Id"}},"additionalProperties":true,"type":"object","required":["is_advisory_firm","active_clients","can_add_client","tiers"],"title":"GetFirmClientUsageResponse","description":"Response for ``get_firm_client_usage``."},"GetGrandfatheredSummaryResponse":{"properties":{"plan_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plan Tier"},"is_grandfathered":{"type":"boolean","title":"Is Grandfathered"},"current_access":{"$ref":"#/components/schemas/GrandfatheredCurrentAccess"},"available_plans":{"items":{"$ref":"#/components/schemas/GrandfatheredAvailablePlan"},"type":"array","title":"Available Plans"}},"additionalProperties":true,"type":"object","required":["is_grandfathered","current_access","available_plans"],"title":"GetGrandfatheredSummaryResponse","description":"Response for ``get_grandfathered_summary``."},"GetInvoiceHistoryResponse":{"properties":{"invoices":{"items":{"$ref":"#/components/schemas/BillingInvoiceItem"},"type":"array","title":"Invoices"}},"additionalProperties":true,"type":"object","required":["invoices"],"title":"GetInvoiceHistoryResponse","description":"Response for ``get_invoice_history``."},"GetPricingConfigResponse":{"properties":{"annual_discount_pct":{"type":"number","title":"Annual Discount Pct"},"annual_discount_label":{"type":"string","title":"Annual Discount Label"}},"additionalProperties":true,"type":"object","required":["annual_discount_pct","annual_discount_label"],"title":"GetPricingConfigResponse","description":"Response for ``get_pricing_config``."},"GrandfatherBusinessResponse":{"properties":{"plan_tier":{"type":"string","title":"Plan Tier"},"billing_status":{"type":"string","title":"Billing Status"},"grandfathered_addons":{"items":{"type":"string"},"type":"array","title":"Grandfathered Addons"},"trial_ends_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trial Ends At"},"is_billing_active":{"type":"boolean","title":"Is Billing Active","default":true}},"additionalProperties":true,"type":"object","required":["plan_tier","billing_status","grandfathered_addons"],"title":"GrandfatherBusinessResponse","description":"Response for superuser-only ``grandfather_business``."},"GrandfatheredAvailablePlan":{"properties":{"plan_tier":{"type":"string","title":"Plan Tier"},"catalog_slug":{"type":"string","title":"Catalog Slug"},"price_amount":{"type":"integer","title":"Price Amount"},"interval":{"type":"string","title":"Interval"}},"additionalProperties":true,"type":"object","required":["plan_tier","catalog_slug","price_amount","interval"],"title":"GrandfatheredAvailablePlan"},"GrandfatheredCurrentAccess":{"properties":{"all_addons_included":{"type":"boolean","title":"All Addons Included"},"addons":{"items":{"type":"string"},"type":"array","title":"Addons"},"ai_monthly_limit":{"type":"integer","title":"Ai Monthly Limit"},"has_ai_pro":{"type":"boolean","title":"Has Ai Pro"},"billing_status":{"type":"string","title":"Billing Status"},"no_payment_required":{"type":"boolean","title":"No Payment Required"}},"additionalProperties":true,"type":"object","required":["all_addons_included","addons","ai_monthly_limit","has_ai_pro","billing_status","no_payment_required"],"title":"GrandfatheredCurrentAccess"},"GrandfatheredMigrateRequest":{"properties":{"target_plan":{"type":"string","title":"Target Plan","description":"Target plan tier: 'self_directed' or 'managed'."},"success_url":{"type":"string","title":"Success Url","description":"URL to redirect after successful payment."},"cancel_url":{"type":"string","title":"Cancel Url","description":"URL to redirect if checkout is canceled."},"billing_interval":{"type":"string","enum":["month","year"],"title":"Billing Interval","description":"Billing cadence: 'month' or discounted annual 'year'.","default":"month"}},"type":"object","required":["target_plan","success_url","cancel_url"],"title":"GrandfatheredMigrateRequest"},"MigrateFromGrandfatheredResponse":{"properties":{"checkout_url":{"type":"string","title":"Checkout Url"},"session_id":{"type":"string","title":"Session Id"}},"additionalProperties":true,"type":"object","required":["checkout_url","session_id"],"title":"MigrateFromGrandfatheredResponse","description":"Response for ``migrate_from_grandfathered``."},"PauseAiFeaturesResponse":{"properties":{"requests_used":{"type":"integer","title":"Requests Used"},"monthly_limit":{"type":"integer","title":"Monthly Limit"},"remaining":{"type":"integer","title":"Remaining"},"is_unlimited":{"type":"boolean","title":"Is Unlimited"},"plan_tier":{"type":"string","title":"Plan Tier"},"has_ai_pro":{"type":"boolean","title":"Has Ai Pro"},"is_trial":{"type":"boolean","title":"Is Trial"},"overage_enabled":{"type":"boolean","title":"Overage Enabled"},"overage_requests":{"type":"integer","title":"Overage Requests"},"overage_rates_cents":{"$ref":"#/components/schemas/AIOverageRatesCents"},"overage_breakdown":{"$ref":"#/components/schemas/AIOverageBreakdown"},"estimated_overage_cost_cents":{"type":"integer","title":"Estimated Overage Cost Cents"},"projected_month_end_overage_cents":{"type":"integer","title":"Projected Month End Overage Cents"},"ai_paused_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ai Paused At"},"ai_paused_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ai Paused By"},"upgrade_suggestion":{"anyOf":[{"$ref":"#/components/schemas/AIUpgradeSuggestion"},{"type":"null"}]},"disabled_features_when_paused":{"items":{"type":"string"},"type":"array","title":"Disabled Features When Paused"}},"additionalProperties":true,"type":"object","required":["requests_used","monthly_limit","remaining","is_unlimited","plan_tier","has_ai_pro","is_trial","overage_enabled","overage_requests","overage_rates_cents","overage_breakdown","estimated_overage_cost_cents","projected_month_end_overage_cents","disabled_features_when_paused"],"title":"PauseAiFeaturesResponse","description":"Response for ``pause_ai_features``."},"PlanChangeRequest":{"properties":{"price_id":{"type":"string","title":"Price Id","description":"Stripe Price ID for the new plan."}},"type":"object","required":["price_id"],"title":"PlanChangeRequest"},"PortalRequest":{"properties":{"return_url":{"type":"string","title":"Return Url","description":"URL to redirect after leaving the portal."}},"type":"object","required":["return_url"],"title":"PortalRequest"},"PreviewAddonChangeResponse":{"properties":{"prorated_amount":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Prorated Amount"},"addon_price":{"type":"integer","title":"Addon Price"},"action":{"type":"string","enum":["add","remove"],"title":"Action"},"effective_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Date"}},"additionalProperties":true,"type":"object","required":["addon_price","action"],"title":"PreviewAddonChangeResponse","description":"Response for ``preview_addon_change``.\n\n``prorated_amount`` is ``None`` when Stripe could not produce a proration\npreview (or there is no subscription to preview against). Clients must\nrender that as \"calculated by Stripe\" — never as ``$0.00``."},"ResumeAiFeaturesResponse":{"properties":{"requests_used":{"type":"integer","title":"Requests Used"},"monthly_limit":{"type":"integer","title":"Monthly Limit"},"remaining":{"type":"integer","title":"Remaining"},"is_unlimited":{"type":"boolean","title":"Is Unlimited"},"plan_tier":{"type":"string","title":"Plan Tier"},"has_ai_pro":{"type":"boolean","title":"Has Ai Pro"},"is_trial":{"type":"boolean","title":"Is Trial"},"overage_enabled":{"type":"boolean","title":"Overage Enabled"},"overage_requests":{"type":"integer","title":"Overage Requests"},"overage_rates_cents":{"$ref":"#/components/schemas/AIOverageRatesCents"},"overage_breakdown":{"$ref":"#/components/schemas/AIOverageBreakdown"},"estimated_overage_cost_cents":{"type":"integer","title":"Estimated Overage Cost Cents"},"projected_month_end_overage_cents":{"type":"integer","title":"Projected Month End Overage Cents"},"ai_paused_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ai Paused At"},"ai_paused_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ai Paused By"},"upgrade_suggestion":{"anyOf":[{"$ref":"#/components/schemas/AIUpgradeSuggestion"},{"type":"null"}]},"disabled_features_when_paused":{"items":{"type":"string"},"type":"array","title":"Disabled Features When Paused"}},"additionalProperties":true,"type":"object","required":["requests_used","monthly_limit","remaining","is_unlimited","plan_tier","has_ai_pro","is_trial","overage_enabled","overage_requests","overage_rates_cents","overage_breakdown","estimated_overage_cost_cents","projected_month_end_overage_cents","disabled_features_when_paused"],"title":"ResumeAiFeaturesResponse","description":"Response for ``resume_ai_features``."},"SuccessEnvelope_ChangeFirmTierResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/ChangeFirmTierResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[ChangeFirmTierResponse]"},"SuccessEnvelope_ChangePlanResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/ChangePlanResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[ChangePlanResponse]"},"SuccessEnvelope_CreateCheckoutSessionResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/CreateCheckoutSessionResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[CreateCheckoutSessionResponse]"},"SuccessEnvelope_CreatePortalSessionResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/CreatePortalSessionResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[CreatePortalSessionResponse]"},"SuccessEnvelope_GetAiUsageDetailsResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/GetAiUsageDetailsResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[GetAiUsageDetailsResponse]"},"SuccessEnvelope_GetAiUsageResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/GetAiUsageResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[GetAiUsageResponse]"},"SuccessEnvelope_GetBillingCatalogResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/GetBillingCatalogResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[GetBillingCatalogResponse]"},"SuccessEnvelope_GetBillingStatusResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/GetBillingStatusResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[GetBillingStatusResponse]"},"SuccessEnvelope_GetFirmClientUsageResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/GetFirmClientUsageResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[GetFirmClientUsageResponse]"},"SuccessEnvelope_GetGrandfatheredSummaryResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/GetGrandfatheredSummaryResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[GetGrandfatheredSummaryResponse]"},"SuccessEnvelope_GetInvoiceHistoryResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/GetInvoiceHistoryResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[GetInvoiceHistoryResponse]"},"SuccessEnvelope_GetPricingConfigResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/GetPricingConfigResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[GetPricingConfigResponse]"},"SuccessEnvelope_GrandfatherBusinessResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/GrandfatherBusinessResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[GrandfatherBusinessResponse]"},"SuccessEnvelope_MigrateFromGrandfatheredResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/MigrateFromGrandfatheredResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[MigrateFromGrandfatheredResponse]"},"SuccessEnvelope_PauseAiFeaturesResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/PauseAiFeaturesResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[PauseAiFeaturesResponse]"},"SuccessEnvelope_PreviewAddonChangeResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/PreviewAddonChangeResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[PreviewAddonChangeResponse]"},"SuccessEnvelope_ResumeAiFeaturesResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/ResumeAiFeaturesResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[ResumeAiFeaturesResponse]"},"SuccessEnvelope_ToggleAddonResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/ToggleAddonResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[ToggleAddonResponse]"},"ToggleAddonResponse":{"properties":{"status":{"type":"string","title":"Status"},"action":{"type":"string","enum":["add","remove"],"title":"Action"},"addon_slug":{"type":"string","title":"Addon Slug"},"active_addons":{"items":{"type":"string"},"type":"array","title":"Active Addons"},"effective_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Effective Date"}},"additionalProperties":true,"type":"object","required":["status","action","addon_slug","active_addons"],"title":"ToggleAddonResponse","description":"Response for ``toggle_addon``."},"ErrorResponse":{"title":"ErrorResponse","type":"object","description":"Envelope returned by every non-2xx response. Branch on `code` (stable) rather than `message` (human-readable, may change).","required":["error","message","code"],"properties":{"error":{"type":"string","description":"Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`."},"message":{"type":"string","description":"Human-readable explanation, safe to show to end users."},"code":{"type":"string","description":"Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`)."},"request_id":{"type":"string","description":"Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied."},"errors":{"type":"object","additionalProperties":{"type":"string"},"description":"Field-level validation messages keyed by field name. Present on 400/422 validation failures only."}}}},"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Token","description":"API token authentication. Format: `Bearer dz_...`"}}},"security":[{"BearerAuth":[]}]}