{"openapi":"3.1.0","info":{"title":"tt-conductor","version":"0.3.0"},"paths":{"/auth/signup":{"post":{"tags":["auth"],"summary":"Signup","description":"Create tenant + owner user. Sends verify-email best-effort; on\nmailer failure, still returns 201 (the verify-link is logged so\nstaging operators can recover by sharing it manually).","operationId":"signup_auth_signup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Signup Auth Signup Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/verify-email":{"get":{"tags":["auth"],"summary":"Verify Email","operationId":"verify_email_auth_verify_email_get","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Verify Email Auth Verify Email Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/login":{"post":{"tags":["auth"],"summary":"Login","operationId":"login_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Login Auth Login Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/logout":{"post":{"tags":["auth"],"summary":"Logout","description":"Clear the cookie + revoke the bearer's jti server-side. Idempotent —\nre-logging-out the same token is a no-op.","operationId":"logout_auth_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Logout Auth Logout Post"}}}}}}},"/auth/me":{"get":{"tags":["auth"],"summary":"Me","operationId":"me_auth_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Me Auth Me Get"}}}}}}},"/onboarding/providers":{"get":{"tags":["onboarding"],"summary":"List Providers","description":"Public catalog used to render the wizard.","operationId":"list_providers_onboarding_providers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Providers Onboarding Providers Get"}}}}}}},"/onboarding/status":{"get":{"tags":["onboarding"],"summary":"Status Route","operationId":"status_route_onboarding_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Status Route Onboarding Status Get"}}}}}}},"/onboarding/mode":{"put":{"tags":["onboarding"],"summary":"Set Mode","operationId":"set_mode_onboarding_mode_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Set Mode Onboarding Mode Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/onboarding/credentials/{provider}":{"put":{"tags":["onboarding"],"summary":"Put Credential","description":"Save + live-validate. Validation rejection still stores the row\n(status='failed') so the UI can echo back what failed and the user\ncan edit + retry without re-typing everything.\n\nWe refuse to save while the tenant is still in bundled mode — flip\nto BYOK explicitly first.","operationId":"put_credential_onboarding_credentials__provider__put","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Put Credential Onboarding Credentials  Provider  Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["onboarding"],"summary":"Delete Credential","operationId":"delete_credential_onboarding_credentials__provider__delete","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Credential Onboarding Credentials  Provider  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/onboarding/complete":{"post":{"tags":["onboarding"],"summary":"Complete","operationId":"complete_onboarding_complete_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Complete Onboarding Complete Post"}}}}}}},"/api/voice-avatars/clone":{"post":{"tags":["voices"],"summary":"Clone","operationId":"clone_api_voice_avatars_clone_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_clone_api_voice_avatars_clone_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Clone Api Voice Avatars Clone Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/voice-avatars":{"get":{"tags":["voices"],"summary":"List Voices","operationId":"list_voices_api_voice_avatars_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Voices Api Voice Avatars Get"}}}}}}},"/api/voice-avatars/{voice_id}":{"delete":{"tags":["voices"],"summary":"Delete","operationId":"delete_api_voice_avatars__voice_id__delete","parameters":[{"name":"voice_id","in":"path","required":true,"schema":{"type":"integer","title":"Voice Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Api Voice Avatars  Voice Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/voice-avatars/assign":{"put":{"tags":["voices"],"summary":"Assign","description":"Assign (or clear) a voice on a workflow. body: {workflow_id:int,\nvoice_id:int|null}. voice_id=null clears the assignment (back to the\ngeography-default persona voice).","operationId":"assign_api_voice_avatars_assign_put","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Assign Api Voice Avatars Assign Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/personas":{"get":{"tags":["personas"],"summary":"List Personas","operationId":"list_personas_api_personas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Personas Api Personas Get"}}}}}},"post":{"tags":["personas"],"summary":"Create","operationId":"create_api_personas_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Create Api Personas Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/personas/assign":{"put":{"tags":["personas"],"summary":"Assign","description":"Assign (or clear) a persona on a workflow. body: {workflow_id:int,\npersona_id:int|null}. persona_id=null clears it (→ geo default).","operationId":"assign_api_personas_assign_put","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Assign Api Personas Assign Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/personas/{persona_id}":{"put":{"tags":["personas"],"summary":"Edit","operationId":"edit_api_personas__persona_id__put","parameters":[{"name":"persona_id","in":"path","required":true,"schema":{"type":"integer","title":"Persona Id"}}],"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 Edit Api Personas  Persona Id  Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["personas"],"summary":"Delete","operationId":"delete_api_personas__persona_id__delete","parameters":[{"name":"persona_id","in":"path","required":true,"schema":{"type":"integer","title":"Persona Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Api Personas  Persona Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sim/personas":{"get":{"tags":["sim"],"summary":"List Personas","operationId":"list_personas_api_sim_personas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Personas Api Sim Personas Get"}}}}}}},"/api/sim/campaigns":{"post":{"tags":["sim"],"summary":"Start","operationId":"start_api_sim_campaigns_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartBody"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Start Api Sim Campaigns Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sim/campaigns/{campaign_id}/run-batch":{"post":{"tags":["sim"],"summary":"Run Batch","operationId":"run_batch_api_sim_campaigns__campaign_id__run_batch_post","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"integer","title":"Campaign Id"}}],"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Run Batch Api Sim Campaigns  Campaign Id  Run Batch Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sim/campaigns/{campaign_id}":{"get":{"tags":["sim"],"summary":"Get Status","operationId":"get_status_api_sim_campaigns__campaign_id__get","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"integer","title":"Campaign Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Status Api Sim Campaigns  Campaign Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sim/campaigns/{campaign_id}/answer":{"post":{"tags":["sim"],"summary":"Answer","operationId":"answer_api_sim_campaigns__campaign_id__answer_post","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"integer","title":"Campaign Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnswerBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Answer Api Sim Campaigns  Campaign Id  Answer Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sim/campaigns/{campaign_id}/resume":{"post":{"tags":["sim"],"summary":"Resume","operationId":"resume_api_sim_campaigns__campaign_id__resume_post","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"integer","title":"Campaign Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Resume Api Sim Campaigns  Campaign Id  Resume Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sim/campaigns/{campaign_id}/stop":{"post":{"tags":["sim"],"summary":"Stop","operationId":"stop_api_sim_campaigns__campaign_id__stop_post","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"integer","title":"Campaign Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Stop Api Sim Campaigns  Campaign Id  Stop Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/balance":{"get":{"tags":["billing"],"summary":"Get Balance","operationId":"get_balance_billing_balance_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Get Balance Billing Balance Get"}}}}}}},"/billing/precheck":{"get":{"tags":["billing"],"summary":"Precheck","operationId":"precheck_billing_precheck_get","parameters":[{"name":"expected_seconds","in":"query","required":false,"schema":{"type":"integer","default":180,"title":"Expected Seconds"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Precheck Billing Precheck Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/history":{"get":{"tags":["billing"],"summary":"History","operationId":"history_billing_history_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response History Billing History Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/topup":{"post":{"tags":["billing"],"summary":"Topup","description":"Create a payment intent on the appropriate gateway. Returns a\ncheckout_url the user opens to actually pay. The wallet isn't\ncredited until the webhook confirms.","operationId":"topup_billing_topup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Topup Billing Topup Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/autocharge":{"put":{"tags":["billing"],"summary":"Set Autocharge","operationId":"set_autocharge_billing_autocharge_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutochargeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Set Autocharge Billing Autocharge Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/razorpay/checkout":{"get":{"tags":["billing"],"summary":"Razorpay Checkout","description":"Serve the HTML page that mounts Razorpay's Checkout.js SDK and\nopens the modal for `order_id`. Razorpay does NOT host a\nstandalone Checkout page like Stripe Checkout Sessions — the\nCheckout.js SDK has to be loaded on a page WE serve. This is\nthat page.\n\nURL is built by RazorpayGateway.create_intent (see providers.py)\nand emailed/SMS'd to the customer. Anonymous — Razorpay's own\nflow authenticates the actual payment (UPI / card 3DS / etc.)\nand the webhook signature is the auth gate on settlement.\n\nThe page is intentionally minimal — Razorpay's modal is the UI;\nwe just initialize it and redirect to /billing/return on\nsuccess or dismiss so the customer always lands on a page that\nconfirms their state (rather than a half-rendered checkout).","operationId":"razorpay_checkout_billing_razorpay_checkout_get","parameters":[{"name":"order_id","in":"query","required":true,"schema":{"type":"string","title":"Order Id"}},{"name":"key_id","in":"query","required":true,"schema":{"type":"string","title":"Key Id"}},{"name":"amount","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Amount"}},{"name":"currency","in":"query","required":false,"schema":{"type":"string","default":"INR","title":"Currency"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/return":{"get":{"tags":["billing"],"summary":"Billing Return","description":"Customer lands here after Razorpay (or Stripe) finishes. The\nwallet has NOT been credited yet — that happens asynchronously\nin the webhook handler when the provider confirms settlement.\nThis page just tells the customer what to expect.\n\nURL param is `?status=`; alias keeps the python identifier from\nshadowing the imported `status` HTTP constant module.","operationId":"billing_return_billing_return_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"","title":"Status"}},{"name":"order_id","in":"query","required":false,"schema":{"type":"string","default":"","title":"Order Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/subscription":{"get":{"tags":["billing"],"summary":"Subscription Status","operationId":"subscription_status_billing_subscription_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Subscription Status Billing Subscription Get"}}}}}},"post":{"tags":["billing"],"summary":"Start Subscription","description":"Start the BYOK monthly platform-fee subscription. Returns a\nshort_url the tenant opens to authorise the Razorpay mandate; the\nfirst charge happens on authorisation, then monthly auto-debit.","operationId":"start_subscription_billing_subscription_post","responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Start Subscription Billing Subscription Post"}}}}}}},"/billing/subscription/cancel":{"post":{"tags":["billing"],"summary":"Cancel Subscription Route","operationId":"cancel_subscription_route_billing_subscription_cancel_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Cancel Subscription Route Billing Subscription Cancel Post"}}}}}}},"/billing/webhooks/stub":{"post":{"tags":["billing"],"summary":"Webhook Stub","description":"Fake webhook for the StubGateway. Body: {external_id, status:\n'succeeded'|'failed', amount_minor?}. NOT auth-required — same\ncontract as a real provider webhook (signature verification is\nthe only auth surface and we accept all signatures in stub mode).\n\nIdempotent on the (external_id, status) pair via ledger.idempotency_key.","operationId":"webhook_stub_billing_webhooks_stub_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Webhook Stub Billing Webhooks Stub Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/webhooks/stripe":{"post":{"tags":["billing"],"summary":"Webhook Stripe","description":"Stripe webhook: verify Stripe-Signature header, then credit ledger\non `checkout.session.completed` (the event Stripe Checkout Sessions\nfires when a payment succeeds) or `payment_intent.succeeded`.\n\nIdempotent on Stripe event id — the same event firing twice yields\none ledger credit. PaymentIntent row lookup is by either:\n  - body.data.object.id (cs_xxx)        → for checkout.session.* events\n  - body.data.object.payment_intent     → for payment_intent.* events\nWe store cs_xxx as our external_id (matches what create_intent saves).","operationId":"webhook_stripe_billing_webhooks_stripe_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Webhook Stripe Billing Webhooks Stripe Post"}}}}}}},"/billing/webhooks/razorpay":{"post":{"tags":["billing"],"summary":"Webhook Razorpay","description":"Razorpay webhook: HMAC-SHA256 over the raw body, hex digest in\nX-Razorpay-Signature. On `payment.captured` event, find the\nPaymentIntent by order_id and credit the wallet.","operationId":"webhook_razorpay_billing_webhooks_razorpay_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Webhook Razorpay Billing Webhooks Razorpay Post"}}}}}}},"/api/internal/usage-events":{"post":{"tags":["internal"],"summary":"Ingest Usage","operationId":"ingest_usage_api_internal_usage_events_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageEventBatch"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Ingest Usage Api Internal Usage Events Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/internal/attribution/signups":{"get":{"tags":["internal"],"summary":"Attribution Signups","operationId":"attribution_signups_api_internal_attribution_signups_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":90,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Attribution Signups Api Internal Attribution Signups Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/internal/outreach/email":{"post":{"tags":["internal"],"summary":"Outreach Email","operationId":"outreach_email_api_internal_outreach_email_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Outreach Email Api Internal Outreach Email Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/internal/outreach/call":{"post":{"tags":["internal"],"summary":"Outreach Call","operationId":"outreach_call_api_internal_outreach_call_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Outreach Call Api Internal Outreach Call Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/internal/outreach/patch-in":{"post":{"tags":["internal"],"summary":"Outreach Patch In","description":"Patch the operator into a live call: move the callee's leg into a\nrecorded conference, then dial the operator into the same room. Mira\nhands off + drops (a media-stream bot can't sit in a Plivo conference).\n``call_uuid`` is the callee's live Plivo CallUUID; operator_number\ndefaults to OPERATOR_PATCH_NUMBER.","operationId":"outreach_patch_in_api_internal_outreach_patch_in_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Outreach Patch In Api Internal Outreach Patch In Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/pricing":{"get":{"tags":["pricing"],"summary":"Get Pricing","description":"Snapshot of every published price, in every supported currency.\n\nResponse shape (load-bearing — the marketing site reads each path\ndirectly):\n\n  plans.byok.fee_minor       : { INR, USD } in minor units\n  plans.byok.fee_display     : { INR: \"₹10,000\", USD: \"$150\" }\n  plans.all_inclusive.rate_per_minute_minor   : { INR, USD }\n  plans.all_inclusive.rate_per_minute_display : { INR: \"₹7\", USD: \"$0.10\" }\n  trial_credit_minor         : { INR, USD }\n  trial_credit_display       : { INR: \"₹350\", USD: \"$5\" }\n  topup.minimum_minor        : { INR, USD }\n  examples.max_utilisation_hours_per_month   : 120\n  examples.max_utilisation_minutes           : 7200\n  examples.max_utilisation_cost_display      : { INR: \"₹50,400\", ... }","operationId":"get_pricing_pricing_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Get Pricing Pricing Get"}}}}}}},"/demo/call":{"post":{"tags":["demo"],"summary":"Call Me","operationId":"call_me_demo_call_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DemoCallRequest"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DemoCallResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/demo/feed":{"get":{"tags":["demo"],"summary":"Feed","description":"Public, token-gated live feed for the \"Call me\" modal. Returns the\nsanitised lifecycle + transcript events for ONE call (the one the\ntoken was minted for) with seq > `after`. 404 for unknown / expired\ntokens. No auth: the unguessable token is the capability.","operationId":"feed_demo_feed_get","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","title":"Token"}},{"name":"after","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"After"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Feed Demo Feed Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/demo/clone-voice":{"post":{"tags":["demo"],"summary":"Clone Voice Demo","description":"Anonymous public-demo voice clone (live-mic recording). Returns the\nElevenLabs voice_id + the script text to preview. Ephemeral: tracked\nfor a TTL sweep so demo clones never accumulate. Per-IP capped.","operationId":"clone_voice_demo_demo_clone_voice_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_clone_voice_demo_demo_clone_voice_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Clone Voice Demo Demo Clone Voice Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/demo/voice-preview":{"post":{"tags":["demo"],"summary":"Voice Preview Demo","description":"Synthesize the script in the cloned voice so the visitor can hear\nthemselves before committing to a call. Honors only voice_ids we\nminted (anti-injection).","operationId":"voice_preview_demo_demo_voice_preview_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/numbers":{"get":{"tags":["numbers"],"summary":"List Numbers","operationId":"list_numbers_numbers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Numbers Numbers Get"}}}}}}},"/numbers/search":{"post":{"tags":["numbers"],"summary":"Search","operationId":"search_numbers_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Search Numbers Search Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/numbers/provision":{"post":{"tags":["numbers"],"summary":"Provision","description":"Bundled tenant: purchase a number under our platform Twilio/Exotel\naccount. Searches inventory if `phone_number` not specified, then\npurchases. Stores as source='provisioned'.","operationId":"provision_numbers_provision_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Provision Numbers Provision Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/numbers/import":{"post":{"tags":["numbers"],"summary":"Import Byok","description":"BYOK tenant: register a number they own with us. Looks up their\nonboarding credentials for the provider to confirm we'll actually\nbe able to USE this number when placing calls. We don't re-validate\nagainst the provider here (the onboarding wizard did that).","operationId":"import_byok_numbers_import_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Import Byok Numbers Import Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/numbers/{number_id}":{"delete":{"tags":["numbers"],"summary":"Release","operationId":"release_numbers__number_id__delete","parameters":[{"name":"number_id","in":"path","required":true,"schema":{"type":"integer","title":"Number Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Release Numbers  Number Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api-keys":{"get":{"tags":["api-keys"],"summary":"List Keys","operationId":"list_keys_api_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Keys Api Keys Get"}}}}}},"post":{"tags":["api-keys"],"summary":"Create Key","operationId":"create_key_api_keys_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Create Key Api Keys Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api-keys/{key_id}/revoke":{"post":{"tags":["api-keys"],"summary":"Revoke Key","operationId":"revoke_key_api_keys__key_id__revoke_post","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"integer","title":"Key Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Revoke Key Api Keys  Key Id  Revoke Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api-keys/{key_id}":{"delete":{"tags":["api-keys"],"summary":"Delete Key","description":"Hard delete. Only allowed AFTER revoke (keeps the audit trail\nuntil the user explicitly clears it).","operationId":"delete_key_api_keys__key_id__delete","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"integer","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Key Api Keys  Key Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/email/unsubscribe":{"get":{"tags":["email"],"summary":"Unsubscribe","description":"One-click unsubscribe. Idempotent.","operationId":"unsubscribe_email_unsubscribe_get","parameters":[{"name":"t","in":"query","required":true,"schema":{"type":"string","description":"HMAC unsub token","title":"T"},"description":"HMAC unsub token"}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/email/preferences":{"get":{"tags":["email"],"summary":"Preferences","description":"Show all channels for this email, with toggles. Re-subscribe is a POST in a follow-up; this\nGET is the human-friendly status page that links to it.","operationId":"preferences_email_preferences_get","parameters":[{"name":"t","in":"query","required":true,"schema":{"type":"string","description":"HMAC unsub token (any channel)","title":"T"},"description":"HMAC unsub token (any channel)"}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/email/resubscribe":{"get":{"tags":["email"],"summary":"Resubscribe","operationId":"resubscribe_email_resubscribe_get","parameters":[{"name":"t","in":"query","required":true,"schema":{"type":"string","title":"T"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/email/webhooks/brevo":{"post":{"tags":["email-webhooks"],"summary":"Brevo Webhook","description":"Receive Brevo transactional-email webhook events.\n\nAuth: the webhook URL is registered in Brevo with `?key=<BREVO_WEBHOOK_SECRET>`\nappended. We compare via constant-time HMAC. If the secret is unset\nwe accept the call (dev/staging convenience) but warn.\n\nBody shape (single event):\n  { \"event\": \"...\", \"email\": \"...\", \"message-id\": \"...\", \"ts\": ..., ... }\n\nOr an array of events for batching. We handle both.","operationId":"brevo_webhook_email_webhooks_brevo_post","parameters":[{"name":"key","in":"query","required":false,"schema":{"type":"string","description":"shared secret","default":"","title":"Key"},"description":"shared secret"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Brevo Webhook Email Webhooks Brevo Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/email/webhooks/elastic-email":{"post":{"tags":["email-webhooks"],"summary":"Elastic Email Webhook","description":"Receive Elastic Email event webhooks.\n\nAuth: HMAC-SHA256 over the raw request body, with the shared secret\n`ELASTIC_EMAIL_WEBHOOK_SECRET`. Provider sends it as\n`X-ElasticEmail-Signature: <hex>`. We compare via constant-time.\n\nBody shape: a single event OR an array. EE doesn't fix the shape across\nplans, so we handle both. Key fields per event:\n  event, msgid, to, status, reason","operationId":"elastic_email_webhook_email_webhooks_elastic_email_post","parameters":[{"name":"X-ElasticEmail-Signature","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-Elasticemail-Signature"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Elastic Email Webhook Email Webhooks Elastic Email Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/data/sources":{"get":{"tags":["data"],"summary":"List Sources","operationId":"list_sources_data_sources_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Sources Data Sources Get"}}}}}},"post":{"tags":["data"],"summary":"Create Source","operationId":"create_source_data_sources_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSourceRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Create Source Data Sources Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/data/sources/{source_id}":{"get":{"tags":["data"],"summary":"Get Source","operationId":"get_source_data_sources__source_id__get","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"integer","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Source Data Sources  Source Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["data"],"summary":"Delete Source","operationId":"delete_source_data_sources__source_id__delete","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"integer","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Source Data Sources  Source Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/data/sources/{source_id}/chat":{"post":{"tags":["data"],"summary":"Chat","operationId":"chat_data_sources__source_id__chat_post","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"integer","title":"Source Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Chat Data Sources  Source Id  Chat Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["data"],"summary":"Get Chat History","operationId":"get_chat_history_data_sources__source_id__chat_get","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"integer","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Chat History Data Sources  Source Id  Chat Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/data/sources/{source_id}/fetch":{"post":{"tags":["data"],"summary":"Fetch New","description":"Shortcut that posts 'Please fetch new data' to the agent.","operationId":"fetch_new_data_sources__source_id__fetch_post","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"integer","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Fetch New Data Sources  Source Id  Fetch Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/data/sources/{source_id}/rows":{"get":{"tags":["data"],"summary":"List Rows","operationId":"list_rows_data_sources__source_id__rows_get","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"integer","title":"Source Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Rows Data Sources  Source Id  Rows Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/shopify/install":{"get":{"tags":["shopify"],"summary":"Install","operationId":"install_shopify_install_get","parameters":[{"name":"shop","in":"query","required":true,"schema":{"type":"string","title":"Shop"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/shopify/callback":{"get":{"tags":["shopify"],"summary":"Callback","operationId":"callback_shopify_callback_get","parameters":[{"name":"shop","in":"query","required":true,"schema":{"type":"string","title":"Shop"}},{"name":"code","in":"query","required":true,"schema":{"type":"string","title":"Code"}},{"name":"state","in":"query","required":true,"schema":{"type":"string","title":"State"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/shopify/status":{"get":{"tags":["shopify"],"summary":"Conn Status","description":"Lightweight check the UI can poll: is this tenant connected?","operationId":"conn_status_shopify_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Conn Status Shopify Status Get"}}}}}}},"/kb/rules":{"post":{"tags":["kb"],"summary":"Create Rule","operationId":"create_rule_kb_rules_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRuleRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Create Rule Kb Rules Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["kb"],"summary":"List Rules","operationId":"list_rules_kb_rules_get","parameters":[{"name":"bucket","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bucket"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Archived"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":200,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Rules Kb Rules Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/kb/rules/{rule_id}":{"get":{"tags":["kb"],"summary":"Get Rule","operationId":"get_rule_kb_rules__rule_id__get","parameters":[{"name":"rule_id","in":"path","required":true,"schema":{"type":"integer","title":"Rule Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Rule Kb Rules  Rule Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["kb"],"summary":"Update Rule","operationId":"update_rule_kb_rules__rule_id__put","parameters":[{"name":"rule_id","in":"path","required":true,"schema":{"type":"integer","title":"Rule Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRuleRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Update Rule Kb Rules  Rule Id  Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["kb"],"summary":"Delete Rule","operationId":"delete_rule_kb_rules__rule_id__delete","parameters":[{"name":"rule_id","in":"path","required":true,"schema":{"type":"integer","title":"Rule Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Rule Kb Rules  Rule Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/kb/export":{"get":{"tags":["kb"],"summary":"Export Rules","description":"Download this tenant's KB as CSV or JSON. Round-trips with\n/kb/import. Archived rules excluded unless include_archived=true.","operationId":"export_rules_kb_export_get","parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","default":"csv","title":"Format"}},{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Archived"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/kb/import":{"post":{"tags":["kb"],"summary":"Import Rules","description":"Bulk-import KB rules from CSV or JSON.\n\nValidation is strict + all-or-nothing: if ANY row fails schema\nvalidation the whole import is rejected (422 with per-row errors)\nand nothing is written — so a bad CSV never half-applies.\n\nmode=merge (default) adds the rows alongside existing KB.\nmode=replace archives existing active/paused rules in the buckets\npresent in the import, then adds the new rows. dry_run=true\nvalidates + reports without writing.","operationId":"import_rules_kb_import_post","parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","default":"csv","title":"Format"}},{"name":"mode","in":"query","required":false,"schema":{"type":"string","default":"merge","title":"Mode"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Dry Run"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Import Rules Kb Import Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/kb/feedback":{"post":{"tags":["kb"],"summary":"Create Feedback","operationId":"create_feedback_kb_feedback_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFeedbackRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Create Feedback Kb Feedback Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["kb"],"summary":"List Feedback","operationId":"list_feedback_kb_feedback_get","parameters":[{"name":"turn_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Turn Id"}},{"name":"verdict","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Verdict"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":200,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Feedback Kb Feedback Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/kb/rollup":{"get":{"tags":["kb"],"summary":"Feedback Rollup","description":"Aggregate the kb_feedback ledger over the last N days so operators\ncan see what their agent is being rewarded / punished / banned for\nand which rules came out of that feedback. Optional workflow_id\nfilter scopes to one campaign.\n\nReturns:\n  counts             reward/punish/ban totals + promoted-to-rule count\n  top_turns          most-flagged turns with their verdicts + text\n                     snippet (sorted by total flag count desc)\n  rules_from_feedback rules with source_kind='feedback', most recent\n                     first, with feedback-attached count\n\nThe \"rules earning their keep\" framing on the dashboard comes from\nrules_from_feedback. Once we wire rule-firing telemetry in a later\nphase, that list will also carry firing counts.","operationId":"feedback_rollup_kb_rollup_get","parameters":[{"name":"workflow_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Workflow Id"}},{"name":"window_days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":30,"title":"Window Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Feedback Rollup Kb Rollup Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/runs/live":{"get":{"tags":["turns"],"summary":"List Live Calls","description":"Tenant-scoped list of calls currently in flight. Powers the\nlive-calls strip on the dashboard. Returns at most 20 entries,\neach with the run/target IDs the SSE endpoint needs.","operationId":"list_live_calls_api_runs_live_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Live Calls Api Runs Live Get"}}}}}}},"/internal/turns":{"post":{"tags":["turns"],"summary":"Post Turn","description":"voice_bot pushes one turn. Auth: X-System-Key + X-Tenant-Id.\nIdempotent on (outcome_id, seq) when outcome_id is set.","operationId":"post_turn_internal_turns_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TurnIn"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Post Turn Internal Turns Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/runs/{run_id}/turns/stream":{"get":{"tags":["turns"],"summary":"Stream Turns","description":"SSE feed of turns for one run. Replays history first (filtered\nby target_id if given, since_seq > -1 for resume), then streams\nlive turns. 15s keepalive, 30-minute idle cap. Disconnect on\nclient close releases the subscription cleanly.","operationId":"stream_turns_api_runs__run_id__turns_stream_get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"integer","title":"Run Id"}},{"name":"target_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Target Id"}},{"name":"since_seq","in":"query","required":false,"schema":{"type":"integer","minimum":-1,"default":-1,"title":"Since Seq"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/otp/start":{"post":{"tags":["auth-otp"],"summary":"Otp Start","operationId":"otp_start_auth_otp_start_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtpStartRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Otp Start Auth Otp Start Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/otp/resend":{"post":{"tags":["auth-otp"],"summary":"Otp Resend","operationId":"otp_resend_auth_otp_resend_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtpStartRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Otp Resend Auth Otp Resend Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/otp/verify":{"post":{"tags":["auth-otp"],"summary":"Otp Verify","operationId":"otp_verify_auth_otp_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtpVerifyRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Otp Verify Auth Otp Verify Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/altcha/challenge":{"get":{"tags":["auth-altcha"],"summary":"Altcha Challenge","operationId":"altcha_challenge_auth_altcha_challenge_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/dnc":{"get":{"tags":["compliance"],"summary":"List Dnc","operationId":"list_dnc_dnc_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Dnc Dnc Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dnc/add":{"post":{"tags":["compliance"],"summary":"Dnc Add","operationId":"dnc_add_dnc_add_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DncAddRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Dnc Add Dnc Add Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dnc/{e164}":{"delete":{"tags":["compliance"],"summary":"Dnc Remove","operationId":"dnc_remove_dnc__e164__delete","parameters":[{"name":"e164","in":"path","required":true,"schema":{"type":"string","title":"E164"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Dnc Remove Dnc  E164  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dnc/check":{"get":{"tags":["compliance"],"summary":"Dnc Check","operationId":"dnc_check_dnc_check_get","parameters":[{"name":"phone","in":"query","required":true,"schema":{"type":"string","title":"Phone"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Dnc Check Dnc Check Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dnc/import":{"post":{"tags":["compliance"],"summary":"Dnc Import","description":"Bulk-import a DNC list from CSV. First column must be the phone\nnumber (with or without the `phone` header). Optional second column\nbecomes notes.","operationId":"dnc_import_dnc_import_post","responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Dnc Import Dnc Import Post"}}}}}}},"/api/workflows/{wid}/compliance":{"put":{"tags":["compliance"],"summary":"Attest","operationId":"attest_api_workflows__wid__compliance_put","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComplianceAttestationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Attest Api Workflows  Wid  Compliance Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/compliance/stats":{"get":{"tags":["compliance"],"summary":"Admin Stats","operationId":"admin_stats_admin_compliance_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Admin Stats Admin Compliance Stats Get"}}}}}}},"/admin/compliance/evaluate":{"post":{"tags":["compliance"],"summary":"Admin Evaluate","description":"Run the auto-flag monitor for this tenant. Idempotent — returns\nnew incidents opened in this run (existing open ones aren't re-opened).","operationId":"admin_evaluate_admin_compliance_evaluate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Admin Evaluate Admin Compliance Evaluate Post"}}}}}}},"/admin/compliance/incidents":{"get":{"tags":["compliance"],"summary":"Admin Incidents","operationId":"admin_incidents_admin_compliance_incidents_get","parameters":[{"name":"resolved","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Resolved"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Admin Incidents Admin Compliance Incidents Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/compliance/incidents/{iid}/resolve":{"post":{"tags":["compliance"],"summary":"Admin Resolve Incident","operationId":"admin_resolve_incident_admin_compliance_incidents__iid__resolve_post","parameters":[{"name":"iid","in":"path","required":true,"schema":{"type":"integer","title":"Iid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResolveRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Admin Resolve Incident Admin Compliance Incidents  Iid  Resolve Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/auth/login":{"post":{"tags":["admin"],"summary":"Admin Login","description":"Admin login. Same password as the user's regular tenant login —\nbut the issued token has `pscope=admin_console` and a 30-min TTL.\n\nReturns generic 401 on any failure (bad email, bad password, not a\nplatform admin, TOTP missing/wrong) to prevent admin-account\nenumeration.","operationId":"admin_login_admin_api_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminLoginRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Admin Login Admin Api Auth Login Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/auth/logout":{"post":{"tags":["admin"],"summary":"Admin Logout","description":"Best-effort logout: clear cookie + revoke jti if present.\nIdempotent — re-logging-out same token is a no-op.","operationId":"admin_logout_admin_api_auth_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Admin Logout Admin Api Auth Logout Post"}}}}}}},"/admin/api/me":{"get":{"tags":["admin"],"summary":"Admin Me","operationId":"admin_me_admin_api_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Admin Me Admin Api Me Get"}}}}}}},"/admin/api/dashboard/summary":{"get":{"tags":["admin"],"summary":"Dashboard Summary","operationId":"dashboard_summary_admin_api_dashboard_summary_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Dashboard Summary Admin Api Dashboard Summary Get"}}}}}}},"/admin/api/ops":{"get":{"tags":["admin"],"summary":"Admin Ops","operationId":"admin_ops_admin_api_ops_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Admin Ops Admin Api Ops Get"}}}}}}},"/admin/api/tenants":{"get":{"tags":["admin"],"summary":"List Tenants","operationId":"list_tenants_admin_api_tenants_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"status_filter","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status Filter"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Tenants Admin Api Tenants Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/tenants/{tid}":{"get":{"tags":["admin"],"summary":"Get Tenant","operationId":"get_tenant_admin_api_tenants__tid__get","parameters":[{"name":"tid","in":"path","required":true,"schema":{"type":"integer","title":"Tid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Tenant Admin Api Tenants  Tid  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/users":{"get":{"tags":["admin"],"summary":"List Users","operationId":"list_users_admin_api_users_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Users Admin Api Users Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/users/{uid}":{"get":{"tags":["admin"],"summary":"Get User","operationId":"get_user_admin_api_users__uid__get","parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"integer","title":"Uid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get User Admin Api Users  Uid  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/credits/grant":{"post":{"tags":["admin"],"summary":"Grant Credit","description":"Add wallet credit to a tenant identified by user email. Mandatory\nreason. Audit-logged. Admin role only (support cannot grant credit).\n\nSupport users can READ credit history but cannot mint new credits —\nmoving money is admin-only by policy.","operationId":"grant_credit_admin_api_credits_grant_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GrantCreditRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Grant Credit Admin Api Credits Grant Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/audit-log":{"get":{"tags":["admin"],"summary":"Get Audit Log","operationId":"get_audit_log_admin_api_audit_log_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kind"}},{"name":"target_tenant_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Target Tenant Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Audit Log Admin Api Audit Log Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/payments":{"get":{"tags":["admin"],"summary":"List Payments","description":"List recent wallet topups + payment intents.\n\n`range` ∈ {today, 7d, 30d, all}.\n`format` ∈ {json, csv} — csv streams a single-table flat dump\nmerging both topups and intents, suitable for accounting handoff.","operationId":"list_payments_admin_api_payments_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"range","in":"query","required":false,"schema":{"type":"string","default":"today","title":"Range"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","default":"json","title":"Format"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/workflows":{"get":{"tags":["admin"],"summary":"List Workflows","operationId":"list_workflows_admin_api_workflows_get","parameters":[{"name":"status_filter","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status Filter"}},{"name":"tenant_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tenant Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Workflows Admin Api Workflows Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/health":{"get":{"tags":["admin"],"summary":"System Health","description":"Lightweight liveness signals for the dashboard. Cheap queries only.","operationId":"system_health_admin_api_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response System Health Admin Api Health Get"}}}}}}},"/admin/api/totp/setup":{"get":{"tags":["admin"],"summary":"Totp Setup","description":"Step 1 of TOTP enrollment. Generates a NEW secret + the otpauth\nprovisioning URI + an inline QR PNG data URI. The secret is NOT\npersisted yet — the client must echo it back to /totp/enroll along\nwith a valid 6-digit code to actually save it.\n\nRe-runnable. If the admin reloads the page, they get a fresh\nsecret — closing the tab doesn't half-break the account.","operationId":"totp_setup_admin_api_totp_setup_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Totp Setup Admin Api Totp Setup Get"}}}}}}},"/admin/api/totp/enroll":{"post":{"tags":["admin"],"summary":"Totp Enroll","description":"Step 2 of TOTP enrollment. Verifies that `code` matches `secret`,\nthen encrypts + persists the secret and flips totp_enabled=True.\n\nFrom this moment forward, the admin must supply a TOTP code on\nevery /admin/api/auth/login. Lost-phone recovery: a full-admin\nruns `python -m scripts.seed_admin --email X --reset-totp` (CLI\nonly — there's no UI for resetting someone else's TOTP).","operationId":"totp_enroll_admin_api_totp_enroll_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TotpEnrollRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Totp Enroll Admin Api Totp Enroll Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/totp/disable":{"post":{"tags":["admin"],"summary":"Totp Disable","description":"Reset another admin/support user's TOTP. Full admin only.\nUse case: a teammate lost their phone. After this, the target\nmust re-enroll on next login.\n\nCannot be used to disable your OWN TOTP — that would let a\ncompromised session permanently bypass 2FA. Self-disable is\nCLI-only via seed_admin.","operationId":"totp_disable_admin_api_totp_disable_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TotpDisableRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Totp Disable Admin Api Totp Disable Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/tenants/bulk-archive":{"post":{"tags":["admin"],"summary":"Tenants Bulk Archive","description":"Mark tenants status='deleted' + set suspended_at + suspension_reason.\nSoft-delete: data stays intact (legal retention + recovery).\n\nRefuses to archive: tenant 1 (Tradetron itself) and the acting\nadmin's own tenant — both common foot-guns.","operationId":"tenants_bulk_archive_admin_api_tenants_bulk_archive_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkArchiveRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Tenants Bulk Archive Admin Api Tenants Bulk Archive Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/users/bulk-archive":{"post":{"tags":["admin"],"summary":"Users Bulk Archive","description":"Mark users status='deleted'. Soft. Cannot archive self.","operationId":"users_bulk_archive_admin_api_users_bulk_archive_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkArchiveRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Users Bulk Archive Admin Api Users Bulk Archive Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/workflows/bulk-archive":{"post":{"tags":["admin"],"summary":"Workflows Bulk Archive","description":"Mark workflows status='retired' + archived_at. Refuses workflows\nwith any run currently 'running' unless force=true.","operationId":"workflows_bulk_archive_admin_api_workflows_bulk_archive_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkArchiveRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Workflows Bulk Archive Admin Api Workflows Bulk Archive Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/dnc/bulk-delete":{"post":{"tags":["admin"],"summary":"Dnc Bulk Delete","description":"HARD delete DNC entries for one tenant. No FK fanout, so a real\nDELETE is safe here. One audit row per number with kind='admin.dnc.delete'.","operationId":"dnc_bulk_delete_admin_api_dnc_bulk_delete_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DncBulkDeleteRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Dnc Bulk Delete Admin Api Dnc Bulk Delete Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/impersonate/{target_user_id}":{"post":{"tags":["admin"],"summary":"Impersonate Start","operationId":"impersonate_start_admin_api_impersonate__target_user_id__post","parameters":[{"name":"target_user_id","in":"path","required":true,"schema":{"type":"integer","title":"Target User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImpersonateStartRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Impersonate Start Admin Api Impersonate  Target User Id  Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/impersonate-clear":{"post":{"tags":["admin"],"summary":"Impersonate Clear","operationId":"impersonate_clear_admin_api_impersonate_clear_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Impersonate Clear Admin Api Impersonate Clear Post"}}}}}}},"/admin/api/workflows/{wid}":{"get":{"tags":["admin"],"summary":"Get Workflow Detail","description":"Full workflow drill-down: workflow row + last 20 runs + last 20\noutcomes + tenant snippet. Used by the side-drawer in the UI.","operationId":"get_workflow_detail_admin_api_workflows__wid__get","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Workflow Detail Admin Api Workflows  Wid  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/runs/{rid}":{"get":{"tags":["admin"],"summary":"Get Run Detail","description":"One run + its outcomes. Transcripts are stripped for support.","operationId":"get_run_detail_admin_api_runs__rid__get","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"integer","title":"Rid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Run Detail Admin Api Runs  Rid  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/compliance/incidents":{"get":{"tags":["admin"],"summary":"List Compliance Incidents","description":"Cross-tenant compliance incidents. resolved=false (default for\ntriage UIs) shows everything still open. Critical-severity\npayloads are stripped for support (PII in DNC-rate rows).","operationId":"list_compliance_incidents_admin_api_compliance_incidents_get","parameters":[{"name":"resolved","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Resolved"}},{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity"}},{"name":"tenant_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tenant Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Compliance Incidents Admin Api Compliance Incidents Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/compliance/incidents/{iid}/resolve":{"post":{"tags":["admin"],"summary":"Resolve Compliance Incident","description":"Close an open incident. Both admin and support can resolve\n(compliance triage is a legitimate support task).","operationId":"resolve_compliance_incident_admin_api_compliance_incidents__iid__resolve_post","parameters":[{"name":"iid","in":"path","required":true,"schema":{"type":"integer","title":"Iid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveIncidentRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Resolve Compliance Incident Admin Api Compliance Incidents  Iid  Resolve Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/tenants/{tid}/suspend":{"post":{"tags":["admin"],"summary":"Suspend Tenant","description":"Flip a tenant to status='suspended'. Admin only. Cannot suspend\ntenant 1 or the actor's own tenant. Distinct from archive\n(suspension is reversible; archive is a softer deletion).","operationId":"suspend_tenant_admin_api_tenants__tid__suspend_post","parameters":[{"name":"tid","in":"path","required":true,"schema":{"type":"integer","title":"Tid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuspendTenantRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Suspend Tenant Admin Api Tenants  Tid  Suspend Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/tenants/{tid}/unsuspend":{"post":{"tags":["admin"],"summary":"Unsuspend Tenant","operationId":"unsuspend_tenant_admin_api_tenants__tid__unsuspend_post","parameters":[{"name":"tid","in":"path","required":true,"schema":{"type":"integer","title":"Tid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnsuspendTenantRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Unsuspend Tenant Admin Api Tenants  Tid  Unsuspend Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/search":{"get":{"tags":["admin"],"summary":"Admin Search","description":"Cross-resource search for the command palette.\n\nMatches against tenants (name + signup_email), users (email + name),\nworkflows (name). Returns up to `limit_per` of each kind.\nNumeric q also matches resource id.","operationId":"admin_search_admin_api_search_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"title":"Q"}},{"name":"limit_per","in":"query","required":false,"schema":{"type":"integer","default":8,"title":"Limit Per"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Admin Search Admin Api Search Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/email/stats":{"get":{"tags":["admin"],"summary":"Email Stats","description":"Counts + by-template rollup for the email console.\n\nReads directly from email_send_log + email_suppressions (created by\nthe existing email funnel). All emails routed through DRIP /\nLIFECYCLE class go via Elastic Email per dispatcher.py wiring.\nTRANSACTIONAL / DUNNING route via the other provider.","operationId":"email_stats_admin_api_email_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Email Stats Admin Api Email Stats Get"}}}}}}},"/admin/api/email/sends":{"get":{"tags":["admin"],"summary":"Email Sends","operationId":"email_sends_admin_api_email_sends_get","parameters":[{"name":"range","in":"query","required":false,"schema":{"type":"string","default":"7d","title":"Range"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":200,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Email Sends Admin Api Email Sends Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/email/suppressions":{"get":{"tags":["admin"],"summary":"Email Suppressions","operationId":"email_suppressions_admin_api_email_suppressions_get","parameters":[{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kind"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":200,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Email Suppressions Admin Api Email Suppressions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/email/compose":{"post":{"tags":["admin"],"summary":"Email Compose","description":"One-off DRIP-class email to a segment of tenants.\n\nSegments:\n  all_active           — every user whose tenant.status ∈ (active, trial)\n  trial_only           — tenant.status='trial'\n  signed_up_last_n_days — tenant.created_at within last N (segment_param=N)\n  wallet_above_minor   — tenant.wallet_balance_minor ≥ X (segment_param=X)\n  single_email         — segment_param is the single target email\n\ndry_run=True returns the resolved recipient count + a 10-row sample\nWITHOUT sending. dry_run=False sends via Elastic Email provider,\nhonouring MARKETING suppression. Each send writes to email_send_log\nwith klass='drip', template='admin_compose'.\n\nAdmin role only. Audit-logged with reason + recipient count.","operationId":"email_compose_admin_api_email_compose_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComposeEmailRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Email Compose Admin Api Email Compose Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/dashboard/live":{"get":{"tags":["admin"],"summary":"Dashboard Live","description":"Lightweight live tick — meant to be polled every 5s by the\ndashboard. Keeps payload minimal (4 counts + 2 timestamps).\nDoes NOT include recent_actions to avoid 5x-per-second AuditLog\nscans; the static /summary endpoint still surfaces those.","operationId":"dashboard_live_admin_api_dashboard_live_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Dashboard Live Admin Api Dashboard Live Get"}}}}}}},"/admin/api/pricing":{"get":{"tags":["admin"],"summary":"Admin Get Pricing","operationId":"admin_get_pricing_admin_api_pricing_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Admin Get Pricing Admin Api Pricing Get"}}}}}},"put":{"tags":["admin"],"summary":"Admin Put Pricing","operationId":"admin_put_pricing_admin_api_pricing_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingPutBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Admin Put Pricing Admin Api Pricing Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/costs":{"get":{"tags":["admin"],"summary":"List Costs","operationId":"list_costs_admin_api_costs_get","parameters":[{"name":"range","in":"query","required":false,"schema":{"type":"string","description":"day|week|month|last30d|YYYY-MM-DD..YYYY-MM-DD","default":"week","title":"Range"},"description":"day|week|month|last30d|YYYY-MM-DD..YYYY-MM-DD"},{"name":"group_by","in":"query","required":false,"schema":{"type":"string","description":"tenant|provider","default":"tenant","title":"Group By"},"description":"tenant|provider"},{"name":"tenant_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"filter to one tenant","title":"Tenant Id"},"description":"filter to one tenant"},{"name":"include_rental","in":"query","required":false,"schema":{"type":"boolean","description":"allocate Exotel rental proportionally — OFF by default so revenue dashboard is apples-to-apples variable cost","default":false,"title":"Include Rental"},"description":"allocate Exotel rental proportionally — OFF by default so revenue dashboard is apples-to-apples variable cost"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"search tenant name (case-insensitive substring)","title":"Q"},"description":"search tenant name (case-insensitive substring)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Costs Admin Api Costs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/costs/outcome/{outcome_id}":{"get":{"tags":["admin"],"summary":"Cost For One Outcome","operationId":"cost_for_one_outcome_admin_api_costs_outcome__outcome_id__get","parameters":[{"name":"outcome_id","in":"path","required":true,"schema":{"type":"integer","title":"Outcome Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Cost For One Outcome Admin Api Costs Outcome  Outcome Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/api/costs/rate-card":{"get":{"tags":["admin"],"summary":"Get Rate Card","description":"Surface the live rate card so the dashboard can show 'we're\npricing Cartesia at X INR/M chars at FX 95.82'. Read-only.","operationId":"get_rate_card_admin_api_costs_rate_card_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Get Rate Card Admin Api Costs Rate Card Get"}}}}}}},"/admin/api/fx/refresh":{"post":{"tags":["admin"],"summary":"Refresh Fx","description":"Force a re-fetch of USD→INR from the upstream API. Used when\nyou've just dropped a fresh rate-card change and want the\ndashboard to show the new conversion immediately.","operationId":"refresh_fx_admin_api_fx_refresh_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Refresh Fx Admin Api Fx Refresh Post"}}}}}}},"/healthz":{"get":{"summary":"Healthz","operationId":"healthz_healthz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Healthz Healthz Get"}}}}}}},"/api/workflows":{"get":{"summary":"List Workflows","operationId":"list_workflows_api_workflows_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Workflows Api Workflows Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Create Workflow","description":"Author types NL → Opus generates rule book → row saved.\n\nRequest body: {nl_prompt: str, persona_override?: str, is_test?: bool,\n               author_user_id?: str}","operationId":"create_workflow_api_workflows_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Create Workflow Api Workflows Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workflows/{wid}":{"get":{"summary":"Get Workflow","operationId":"get_workflow_api_workflows__wid__get","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Workflow Api Workflows  Wid  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Edit Workflow","description":"Partial-update editable workflow fields. Refuses any field in\n_PUT_FORBIDDEN. To change consent/attestation use PUT\n/api/workflows/{id}/compliance. To regenerate the rule book,\ndelete + create a new workflow.","operationId":"edit_workflow_api_workflows__wid__put","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Edit Workflow Api Workflows  Wid  Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Workflow","description":"Archive (soft-delete) a workflow. Sets status='retired' +\narchived_at. Refuses if any of its runs are currently 'running'\n— pause/stop them first.","operationId":"delete_workflow_api_workflows__wid__delete","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Workflow Api Workflows  Wid  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workflows/{wid}/effective-prompt":{"get":{"summary":"Get Effective Prompt","description":"Preview the system prompt that would be sent to voice_bot for this\nworkflow RIGHT NOW (workflow.raw_prompt + active tenant Behavior +\nProhibitions). Operators use this from the KB page to confirm a new\nrule landed correctly; the dialer composes the same thing at dial-time.","operationId":"get_effective_prompt_api_workflows__wid__effective_prompt_get","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Effective Prompt Api Workflows  Wid  Effective Prompt Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/internal/redteam/open-run":{"post":{"summary":"Redteam Open Run","operationId":"redteam_open_run_internal_redteam_open_run_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Redteam Open Run Internal Redteam Open Run Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/internal/redteam/close-run/{rid}":{"post":{"summary":"Redteam Close Run","operationId":"redteam_close_run_internal_redteam_close_run__rid__post","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"integer","title":"Rid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Redteam Close Run Internal Redteam Close Run  Rid  Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workflows/{wid}/audience":{"post":{"summary":"Upload Audience","description":"Accept a CSV body. Creates a draft run + Target rows.\n\nBody: raw CSV text (Content-Type: text/csv) OR JSON {csv: \"...\"}.","operationId":"upload_audience_api_workflows__wid__audience_post","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Upload Audience Api Workflows  Wid  Audience Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tenant/cooldown":{"get":{"summary":"Get Tenant Cooldown","description":"Whether this tenant enforces the re-dial cool-down. OFF during\ntesting; flipped on once the tenant is ready to suppress recent dials.\nThe window itself is per-workflow (per_user_cooldown_days).","operationId":"get_tenant_cooldown_api_tenant_cooldown_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Get Tenant Cooldown Api Tenant Cooldown Get"}}}}}},"put":{"summary":"Set Tenant Cooldown","operationId":"set_tenant_cooldown_api_tenant_cooldown_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Set Tenant Cooldown Api Tenant Cooldown Put"}}}}}}},"/api/workflows/{wid}/run":{"post":{"summary":"Run Workflow","operationId":"run_workflow_api_workflows__wid__run_post","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Run Workflow Api Workflows  Wid  Run Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workflows/{wid}/pause":{"post":{"summary":"Pause Workflow","operationId":"pause_workflow_api_workflows__wid__pause_post","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Pause Workflow Api Workflows  Wid  Pause Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/runs/{rid}/emergency-stop":{"post":{"summary":"Emergency Stop Run","description":"Kill switch for an in-flight WorkflowRun.\n\nDistinct from /api/workflows/{id}/pause — pause stops NEW dials\nbut lets in-flight ones finish; emergency-stop freezes EVERYTHING\nfor this run, including refusing to write further outcomes.\n\nFlips run.status → \"stopped\", sets ended_at, writes a\nrun-emergency-stop AuditLog row. Idempotent on already-terminal\nruns (returns the existing status, no 4xx).\n\nWrite-scoped. Accepts an empty body OR JSON {reason: str} (max\n2000 chars truncated).","operationId":"emergency_stop_run_api_runs__rid__emergency_stop_post","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"integer","title":"Rid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Emergency Stop Run Api Runs  Rid  Emergency Stop Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workflows/{wid}/retire":{"post":{"summary":"Retire Workflow","operationId":"retire_workflow_api_workflows__wid__retire_post","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Retire Workflow Api Workflows  Wid  Retire Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workflows/{wid}/runs":{"get":{"summary":"List Workflow Runs","description":"List runs for a workflow, tenant-scoped, newest first.","operationId":"list_workflow_runs_api_workflows__wid__runs_get","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Workflow Runs Api Workflows  Wid  Runs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/runs/{rid}/analyze":{"post":{"summary":"Analyze Run Endpoint","description":"Read the run's transcripts → conversion verdict + agent commitments,\nand refresh converted_n. Idempotent; force=1 re-analyzes.","operationId":"analyze_run_endpoint_api_runs__rid__analyze_post","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"integer","title":"Rid"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Force"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Analyze Run Endpoint Api Runs  Rid  Analyze Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/runs/{rid}/outcomes":{"get":{"summary":"List Run Outcomes","description":"Per-call outcomes for the live monitor: transcript + disposition +\nconversion verdict + structured analysis. Lazily analyzes any finished\nbut un-analyzed calls so conversion + insights populate on their own.","operationId":"list_run_outcomes_api_runs__rid__outcomes_get","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"integer","title":"Rid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Run Outcomes Api Runs  Rid  Outcomes Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/runs/{rid}/report":{"post":{"summary":"Generate Run Report","description":"Campaign success report for a run — Claude synthesis over the per-call\nanalyses (rating, what worked/didn't, follow-ups, commitments we can't\nyet keep). Persists it; the PDF is at /api/runs/{rid}/report.pdf.","operationId":"generate_run_report_api_runs__rid__report_post","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"integer","title":"Rid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Generate Run Report Api Runs  Rid  Report Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/runs/{rid}/report.pdf":{"get":{"summary":"Get Run Report Pdf","operationId":"get_run_report_pdf_api_runs__rid__report_pdf_get","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"integer","title":"Rid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/runs/{rid}/report/reply":{"post":{"summary":"Report Reply","description":"Tenant replies to a run's report; Claude digests report + reply and\nproposes rule-book edits (e.g. 'add the venue + time'). NOT auto-applied\n— the proposed rule book is returned for the tenant to finalise via\nPUT /api/workflows/{id}/rule-book (which snapshots a new version).","operationId":"report_reply_api_runs__rid__report_reply_post","parameters":[{"name":"rid","in":"path","required":true,"schema":{"type":"integer","title":"Rid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Report Reply Api Runs  Rid  Report Reply Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workflows/{wid}/rule-book/versions":{"get":{"summary":"List Rule Book Versions","description":"Rule-book version history + per-version run results — makes the\n'one workflow that keeps getting better' loop measurable.","operationId":"list_rule_book_versions_api_workflows__wid__rule_book_versions_get","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Rule Book Versions Api Workflows  Wid  Rule Book Versions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workflows/{wid}/rule-book":{"put":{"summary":"Override Rule Book","description":"Tenant override of Claude's generated rule book — the final say.\n\nFlow: Claude drafts the rule book on create; the tenant can rewrite it\nhere and THAT becomes what the agent follows. No regeneration round-trip.\nWe set both the readable `rule_book_md` and the OPERATIVE `raw_prompt`\n(what compose_effective_prompt feeds the bot) to the tenant's text, so\nthe edit actually changes call behaviour. A live workflow drops back to\n'draft' so the override is applied deliberately on the next run.","operationId":"override_rule_book_api_workflows__wid__rule_book_put","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Override Rule Book Api Workflows  Wid  Rule Book Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workflows/{wid}/regenerate-rule-book":{"post":{"summary":"Regenerate Rule Book","description":"Replace the workflow's rule book by calling Opus with a new NL\nprompt. Preserves the row's id, runs, outcomes, and audit log —\nuseful for iterating on a campaign without losing call history.\n\nAuto-resolves consent_missing / sender_id_missing /\nopen_incident_block incidents tied to this workflow (the regen\nis a fresh authorship event; the tenant must re-attest via\n/api/workflows/{id}/compliance before /run will pass).","operationId":"regenerate_rule_book_api_workflows__wid__regenerate_rule_book_post","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Regenerate Rule Book Api Workflows  Wid  Regenerate Rule Book Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workflows/{wid}/test-run":{"post":{"summary":"Test Run Workflow","description":"Run ONE adversarial test call (text simulation) against this\nworkflow's effective prompt (rule book + tenant KB) and review the\ntranscript for hallucinations / policy / brand leaks.\n\nBody: {scenario?: str}. The frontend calls this N times (one test\nper request) so each request stays short and the UI can stream\nprogress. Returns {transcript: [...], review: {passed, summary,\nfindings: [...]}}.","operationId":"test_run_workflow_api_workflows__wid__test_run_post","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Test Run Workflow Api Workflows  Wid  Test Run Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workflows/{wid}/test-propose":{"post":{"summary":"Test Propose Addition","description":"Given aggregated findings from the test calls, draft a rule-book\naddition (anti-hallucination guardrails + missing-fact TODOs) for the\ntenant to edit and apply via PUT /api/workflows/{id}/rule-book.\n\nBody: {findings: [{severity, issue, evidence}, ...]}.\nReturns {addition_md: str}.","operationId":"test_propose_addition_api_workflows__wid__test_propose_post","parameters":[{"name":"wid","in":"path","required":true,"schema":{"type":"integer","title":"Wid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Test Propose Addition Api Workflows  Wid  Test Propose Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mira/video":{"post":{"summary":"Mira Video","description":"Mint a Tavus CVI conversation for Mira's video avatar and return its\nembeddable URL. Used by the MyChiefs console (POST /mc/api/mira/video).\nRequires a logged-in user (CallFunnel account) and Tavus env config:\nTAVUS_API_KEY + TAVUS_REPLICA_ID + TAVUS_PERSONA_ID.\n\nOptional body {context, greeting}: the console passes who Mira is\nspeaking with (name + their MyChiefs budget/goal/brief) so she opens\npersonally and stays on-context even on the stock Tavus LLM. (The\ndeeper memory/learning brain is the Mira-service custom-LLM proxy wired\nat the persona level — separate from this minting call.)","operationId":"mira_video_mira_video_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Mira Video Mira Video Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/objections":{"get":{"summary":"List Objections","operationId":"list_objections_api_objections_get","parameters":[{"name":"family","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Family"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Objections Api Objections Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/approvals/{aid}":{"get":{"summary":"Get Approval","description":"Single-approval read. Used by voice_bot's check_approval_status\ntool to learn whether a pending approval has been resolved while\nthe call is still on the line. Tenant-scoped — caller cannot read\nanother tenant's approval row.","operationId":"get_approval_api_approvals__aid__get","parameters":[{"name":"aid","in":"path","required":true,"schema":{"type":"integer","title":"Aid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Approval Api Approvals  Aid  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/approvals":{"get":{"summary":"List Approvals","operationId":"list_approvals_api_approvals_get","parameters":[{"name":"state","in":"query","required":false,"schema":{"type":"string","default":"pending","title":"State"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Approvals Api Approvals Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Create Approval","description":"Create an Approval row + run the routing policy + post to Slack.\n\nThis is the \"faucet\" the agent uses to request a concession (or\npatch / DNC override) mid-call. Called by voice_bot's\nrequest_concession tool; write-auth gated by JWT / api-key /\nX-System-Key (voice_bot uses the system key over loopback).\n\nBody:\n    kind            \"concession\" | \"patch\" | \"dnc_override\"  (required)\n    proposed        {offer: str, value_paise: int, reason: str} (required)\n    target_e164     called party E.164\n    target_user_id  resolved TT user id, if known\n    workflow_id, run_id, target_id, outcome_id   contextual FKs\n    transcript_snippet                           short quote for the card\n    user_lifetime_concession_value_paise         lifetime-cap input\n    workflow_week_concession_count, _cap         weekly-cap inputs\n\nReturns 201 + {\n    approval_id, status, decision, auto_justification,\n    slack_posted, slack_thread_ts,\n}\n\nSlack post happens here when decision is ASK_HUMAN. If the post\nfails the row is still created in `pending` state and\nslack_posted=False; the in-browser /api/approvals UI is a\nparallel decide surface and works without Slack.","operationId":"create_approval_api_approvals_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Create Approval Api Approvals Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/approvals/{aid}/decide":{"post":{"summary":"Decide Approval","description":"Approve or deny a pending Approval row. Mirrors the\nSlack-button path: flips status, records who/when, optional\njustification. Idempotent on already-terminal rows (returns the\nexisting decision instead of 4xx so the caller's confirmation UX\ndoesn't have to special-case races with the Slack flow).\n\nRequest body: {decision: \"approve\"|\"deny\", justification?: str}","operationId":"decide_approval_api_approvals__aid__decide_post","parameters":[{"name":"aid","in":"path","required":true,"schema":{"type":"integer","title":"Aid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Decide Approval Api Approvals  Aid  Decide Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/timeline":{"get":{"summary":"Get Timeline","operationId":"get_timeline_api_timeline_get","parameters":[{"name":"phone","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"}},{"name":"user_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"}},{"name":"n","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"N"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Timeline Api Timeline Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/timeline/recent":{"get":{"summary":"Get Timeline Recent","operationId":"get_timeline_recent_api_timeline_recent_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Timeline Recent Api Timeline Recent Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/reports/weekly":{"get":{"summary":"Report Weekly","description":"On-demand weekly PDF report. Query: ?from=YYYY-MM-DD (UTC).\nDefaults to the Monday of the current week if omitted. Returns\napplication/pdf bytes inline; clients are expected to save.","operationId":"report_weekly_api_reports_weekly_get","parameters":[{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"From"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dsr/export":{"post":{"summary":"Dsr Export","operationId":"dsr_export_dsr_export_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Dsr Export Dsr Export Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/dsr/erase":{"post":{"summary":"Dsr Erase","operationId":"dsr_erase_dsr_erase_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Dsr Erase Dsr Erase Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workflows/preview-opening":{"post":{"summary":"Preview Opening","description":"Generate an MP3 of `text` spoken by `persona`. Returns audio/mpeg bytes.\n\nRequest body: {text: str, persona: str (skylar|gemma|jacqueline|katie|\n               blake|daniel|<sarvam-voice>), language?: \"en\"|\"hi\"}","operationId":"preview_opening_api_workflows_preview_opening_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/voices":{"get":{"summary":"List Voices","description":"Catalog of available personas for the Build page voice picker.","operationId":"list_voices_api_voices_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Voices Api Voices Get"}}}}}}},"/voice/twilio/incoming":{"post":{"summary":"Twilio Incoming","description":"Twilio inbound-call webhook. Tenant resolved from ?tenant_id=\nquery string (set when we provisioned the number). Returns TwiML.\n\nv1 behavior: recording-disclosure preamble + generic \"leave a\nmessage\" + 120s record + hangup. Voice-bot WS bridge ships when\ntt-proxy nginx WS upgrade is unblocked (currently dependency on\nAkshay/Cloudflare Tunnel per the project notes).","operationId":"twilio_incoming_voice_twilio_incoming_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/twilio/status":{"post":{"summary":"Twilio Status","description":"Twilio status callback. Two kinds of POSTs land here:\n\n  1. Outbound CALL status — CallSid + CallStatus (ringing → completed/failed/...)\n     Updates the Outcome row by provider_sid.\n  2. Recording status — RecordingSid + RecordingUrl + RecordingStatus\n     (completed/failed/absent). On 'completed', fetch the audio,\n     transcribe via Deepgram, summarize via Claude Haiku, log to\n     timeline + update Outcome (if it exists).\n\nSignature-verified via twilio.request_validator using the URL we\nregistered with Twilio (auth_public_base_url + /api/twilio/status).\nBest-effort everything: Deepgram/Anthropic/recording-fetch failures\nDO NOT bounce the 200 (Twilio would retry, and we can't act on retries).","operationId":"twilio_status_api_twilio_status_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/exotel/status":{"post":{"summary":"Exotel Status","description":"Exotel posts call-progress events here after the call's\nterminal state. Different body shape from Twilio:\n  - Content-Type: application/json\n  - Top-level keys: CallSid, Status, Duration, From, To,\n    StartTime, EndTime, CustomField, Price, RecordingUrl.\n  - No signature header (Exotel doesn't sign these — we trust\n    them by virtue of the call_sid being one we issued).\n\nBest-effort: idempotent Outcome update + Run counter bump +\nTimeline event. Failures DO NOT bounce the 200, otherwise\nExotel retries which would double-update counters.","operationId":"exotel_status_api_exotel_status_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/plivo/status":{"post":{"summary":"Plivo Status","description":"Plivo posts call-progress here. Two hooks point at this endpoint:\n  - ring_url   (?event=ringing) — fired when the leg starts ringing.\n  - hangup_url (no marker)      — fired on the terminal event.\n\nBody: application/x-www-form-urlencoded. Fields we use:\n  RequestUUID  — matches Outcome.provider_sid (stored at dial-time).\n  CallUUID     — Plivo's per-call id (not stored; logged only).\n  From / To    — E.164 legs.\n  CallStatus   — completed | busy | failed | timeout | no-answer | cancel.\n  Duration     — billable seconds (terminal only).\n\nIdempotent best-effort like the Exotel handler: failures never bounce\nthe 200 (else Plivo retries and double-counts).","operationId":"plivo_status_api_plivo_status_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/slack/interactivity":{"post":{"summary":"Slack Interactivity","description":"Slack interactive-component callback. Verifies the request\nsignature, parses the `payload` form field (Slack ships it as\nurl-encoded JSON), and dispatches `cf_approval_approve` /\n`cf_approval_deny` button clicks to `_apply_decision`.\n\nTenant is read from the Approval row (Slack doesn't carry our\ntenant id; the approval id originated from a card we posted, so\nit's already trusted-by-server).\n\nReturns 401 if signature verification fails so Slack stops\nretrying that delivery, and 200 with a small JSON ack on the\nsuccess path so Slack closes the request modally.","operationId":"slack_interactivity_slack_interactivity_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AdminLoginRequest":{"properties":{"email":{"type":"string","title":"Email"},"password":{"type":"string","maxLength":200,"minLength":1,"title":"Password"},"totp_code":{"anyOf":[{"type":"string","maxLength":10},{"type":"null"}],"title":"Totp Code"}},"type":"object","required":["email","password"],"title":"AdminLoginRequest"},"AnswerBody":{"properties":{"question_id":{"type":"integer","title":"Question Id"},"answer":{"type":"string","maxLength":4000,"minLength":1,"title":"Answer"}},"type":"object","required":["question_id","answer"],"title":"AnswerBody"},"AutochargeRequest":{"properties":{"enabled":{"type":"boolean","title":"Enabled"},"threshold_minor":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Threshold Minor"},"amount_minor":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Amount Minor"}},"type":"object","required":["enabled"],"title":"AutochargeRequest"},"Body_clone_api_voice_avatars_clone_post":{"properties":{"name":{"type":"string","title":"Name"},"consent":{"type":"boolean","title":"Consent","default":false},"consent_text":{"type":"string","title":"Consent Text","default":""},"sample":{"type":"string","contentMediaType":"application/octet-stream","title":"Sample"}},"type":"object","required":["name","sample"],"title":"Body_clone_api_voice_avatars_clone_post"},"Body_clone_voice_demo_demo_clone_voice_post":{"properties":{"sample":{"type":"string","contentMediaType":"application/octet-stream","title":"Sample"},"consent":{"type":"boolean","title":"Consent","default":false}},"type":"object","required":["sample"],"title":"Body_clone_voice_demo_demo_clone_voice_post"},"BulkArchiveRequest":{"properties":{"ids":{"items":{"type":"integer"},"type":"array","maxItems":500,"minItems":1,"title":"Ids"},"reason":{"type":"string","maxLength":500,"minLength":4,"title":"Reason"},"force":{"type":"boolean","title":"Force","default":false}},"type":"object","required":["ids","reason"],"title":"BulkArchiveRequest"},"ChatRequest":{"properties":{"message":{"type":"string","maxLength":8000,"minLength":1,"title":"Message"}},"type":"object","required":["message"],"title":"ChatRequest"},"ComplianceAttestationRequest":{"properties":{"consent_attestation_text":{"type":"string","maxLength":2000,"minLength":20,"title":"Consent Attestation Text"},"tcpa_sender_id":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}],"title":"Tcpa Sender Id"},"dlt_template_id":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Dlt Template Id"}},"type":"object","required":["consent_attestation_text"],"title":"ComplianceAttestationRequest"},"ComposeEmailRequest":{"properties":{"segment":{"type":"string","maxLength":64,"minLength":1,"title":"Segment"},"segment_param":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Segment Param"},"from_name":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"From Name"},"subject":{"type":"string","maxLength":180,"minLength":1,"title":"Subject"},"html":{"type":"string","maxLength":200000,"minLength":20,"title":"Html"},"text":{"anyOf":[{"type":"string","maxLength":200000},{"type":"null"}],"title":"Text"},"reason":{"type":"string","maxLength":500,"minLength":4,"title":"Reason"},"dry_run":{"type":"boolean","title":"Dry Run","default":false}},"type":"object","required":["segment","subject","html","reason"],"title":"ComposeEmailRequest"},"CreateFeedbackRequest":{"properties":{"turn_id":{"type":"integer","title":"Turn Id"},"verdict":{"type":"string","title":"Verdict"},"note":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Note"},"rule_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rule Id"}},"type":"object","required":["turn_id","verdict"],"title":"CreateFeedbackRequest"},"CreateRequest":{"properties":{"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name"},"scope":{"type":"string","pattern":"^(read|write|admin)$","title":"Scope","default":"admin"},"expires_in_days":{"anyOf":[{"type":"integer","maximum":3650.0,"minimum":1.0},{"type":"null"}],"title":"Expires In Days"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"}},"type":"object","required":["name"],"title":"CreateRequest"},"CreateRuleRequest":{"properties":{"bucket":{"type":"string","title":"Bucket"},"title":{"type":"string","maxLength":200,"minLength":1,"title":"Title"},"content":{"type":"string","minLength":1,"title":"Content"},"severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity"},"source_kind":{"type":"string","title":"Source Kind","default":"user"},"source_outcome_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Source Outcome Id"},"source_turn_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Source Turn Id"}},"type":"object","required":["bucket","title","content"],"title":"CreateRuleRequest"},"CreateSourceRequest":{"properties":{"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name"}},"type":"object","required":["name"],"title":"CreateSourceRequest"},"CredentialRequest":{"properties":{"primary_id":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Primary Id"},"secret":{"type":"string","maxLength":1000,"minLength":1,"title":"Secret"},"extra":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Extra"}},"type":"object","required":["secret"],"title":"CredentialRequest"},"DemoCallRequest":{"properties":{"phone":{"type":"string","maxLength":24,"minLength":4,"title":"Phone"},"name":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}],"title":"Name"},"source_page":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Source Page"},"voice_choice":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}],"title":"Voice Choice"},"clone_voice_id":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Clone Voice Id"}},"type":"object","required":["phone"],"title":"DemoCallRequest"},"DemoCallResponse":{"properties":{"ok":{"type":"boolean","title":"Ok"},"message":{"type":"string","title":"Message"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"eta_seconds":{"type":"integer","title":"Eta Seconds","default":15},"call_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Call Token"}},"type":"object","required":["ok","message"],"title":"DemoCallResponse"},"DncAddRequest":{"properties":{"e164":{"type":"string","maxLength":20,"minLength":4,"title":"E164"},"source":{"type":"string","maxLength":40,"title":"Source","default":"admin"},"notes":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Notes"}},"type":"object","required":["e164"],"title":"DncAddRequest"},"DncBulkDeleteRequest":{"properties":{"tenant_id":{"type":"integer","title":"Tenant Id"},"e164s":{"items":{"type":"string"},"type":"array","maxItems":500,"minItems":1,"title":"E164S"},"reason":{"type":"string","maxLength":500,"minLength":4,"title":"Reason"},"force":{"type":"boolean","title":"Force","default":false}},"type":"object","required":["tenant_id","e164s","reason"],"title":"DncBulkDeleteRequest"},"GrantCreditRequest":{"properties":{"email":{"type":"string","maxLength":254,"minLength":3,"title":"Email"},"amount_minor":{"type":"integer","maximum":100000000.0,"exclusiveMinimum":0.0,"title":"Amount Minor"},"reason":{"type":"string","maxLength":500,"minLength":4,"title":"Reason"}},"type":"object","required":["email","amount_minor","reason"],"title":"GrantCreditRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ImpersonateStartRequest":{"properties":{"reason":{"type":"string","maxLength":500,"minLength":4,"title":"Reason"}},"type":"object","required":["reason"],"title":"ImpersonateStartRequest"},"ImportRequest":{"properties":{"phone_e164":{"type":"string","maxLength":20,"minLength":8,"title":"Phone E164"},"provider":{"anyOf":[{"type":"string","pattern":"^(twilio|exotel)$"},{"type":"null"}],"title":"Provider"},"friendly_name":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Friendly Name"}},"type":"object","required":["phone_e164"],"title":"ImportRequest"},"IncidentResolveRequest":{"properties":{"resolution_note":{"type":"string","maxLength":2000,"minLength":1,"title":"Resolution Note"}},"type":"object","required":["resolution_note"],"title":"IncidentResolveRequest"},"LoginRequest":{"properties":{"email":{"type":"string","title":"Email"},"password":{"type":"string","title":"Password"}},"type":"object","required":["email","password"],"title":"LoginRequest"},"ModeRequest":{"properties":{"mode":{"type":"string","pattern":"^(bundled|byok)$","title":"Mode"}},"type":"object","required":["mode"],"title":"ModeRequest"},"OtpStartRequest":{"properties":{"phone_e164":{"type":"string","maxLength":20,"minLength":4,"title":"Phone E164"},"purpose":{"type":"string","maxLength":20,"title":"Purpose","default":"signup"}},"type":"object","required":["phone_e164"],"title":"OtpStartRequest"},"OtpVerifyRequest":{"properties":{"phone_e164":{"type":"string","maxLength":20,"minLength":4,"title":"Phone E164"},"code":{"type":"string","maxLength":10,"minLength":4,"title":"Code"},"purpose":{"type":"string","maxLength":20,"title":"Purpose","default":"signup"}},"type":"object","required":["phone_e164","code"],"title":"OtpVerifyRequest"},"PreviewRequest":{"properties":{"voice_id":{"type":"string","maxLength":120,"minLength":4,"title":"Voice Id"},"text":{"anyOf":[{"type":"string","maxLength":600},{"type":"null"}],"title":"Text"}},"type":"object","required":["voice_id"],"title":"PreviewRequest"},"PricingPutBody":{"properties":{"bundled_rate_inr_minor":{"anyOf":[{"type":"integer","maximum":1000000.0,"minimum":0.0},{"type":"null"}],"title":"Bundled Rate Inr Minor"},"bundled_rate_usd_minor":{"anyOf":[{"type":"integer","maximum":10000.0,"minimum":0.0},{"type":"null"}],"title":"Bundled Rate Usd Minor"},"byok_monthly_fee_inr_minor":{"anyOf":[{"type":"integer","maximum":100000000.0,"minimum":0.0},{"type":"null"}],"title":"Byok Monthly Fee Inr Minor"},"byok_monthly_fee_usd_minor":{"anyOf":[{"type":"integer","maximum":1000000.0,"minimum":0.0},{"type":"null"}],"title":"Byok Monthly Fee Usd Minor"},"trial_bonus_inr_minor":{"anyOf":[{"type":"integer","maximum":1000000.0,"minimum":0.0},{"type":"null"}],"title":"Trial Bonus Inr Minor"},"trial_bonus_usd_minor":{"anyOf":[{"type":"integer","maximum":1000000.0,"minimum":0.0},{"type":"null"}],"title":"Trial Bonus Usd Minor"},"minimum_topup_inr_minor":{"anyOf":[{"type":"integer","maximum":1000000.0,"minimum":0.0},{"type":"null"}],"title":"Minimum Topup Inr Minor"},"minimum_topup_usd_minor":{"anyOf":[{"type":"integer","maximum":1000000.0,"minimum":0.0},{"type":"null"}],"title":"Minimum Topup Usd Minor"}},"type":"object","title":"PricingPutBody","description":"Pricing-override PUT body. MUST stay at module scope: with\n`from __future__ import annotations`, FastAPI resolves the handler's\nannotation against module globals — a closure-local model can't be\nfound there and silently degrades to a query param (422). Each field\noptional; None clears the override and falls back to the Python default.\nCaps prevent a typo from charging ₹1,000,000/min or zeroing everything."},"ProvisionRequest":{"properties":{"country":{"anyOf":[{"type":"string","maxLength":4},{"type":"null"}],"title":"Country"},"area_code":{"anyOf":[{"type":"string","maxLength":10},{"type":"null"}],"title":"Area Code"},"phone_number":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}],"title":"Phone Number"},"friendly_name":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Friendly Name"}},"type":"object","title":"ProvisionRequest"},"ResolveIncidentRequest":{"properties":{"note":{"type":"string","maxLength":500,"minLength":4,"title":"Note"}},"type":"object","required":["note"],"title":"ResolveIncidentRequest"},"RevokeRequest":{"properties":{"reason":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}],"title":"Reason"}},"type":"object","title":"RevokeRequest"},"SearchRequest":{"properties":{"country":{"type":"string","maxLength":4,"minLength":2,"title":"Country"},"area_code":{"anyOf":[{"type":"string","maxLength":10},{"type":"null"}],"title":"Area Code"},"limit":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"Limit","default":20}},"type":"object","required":["country"],"title":"SearchRequest"},"SignupRequest":{"properties":{"email":{"type":"string","title":"Email"},"password":{"type":"string","maxLength":200,"minLength":10,"title":"Password"},"full_name":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Full Name"},"country":{"anyOf":[{"type":"string","maxLength":4},{"type":"null"}],"title":"Country"},"workspace_name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Workspace Name"},"phone_e164":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}],"title":"Phone E164"},"otp_code":{"anyOf":[{"type":"string","maxLength":10},{"type":"null"}],"title":"Otp Code"},"altcha":{"anyOf":[{"type":"string","maxLength":4000},{"type":"null"}],"title":"Altcha"},"acquisition":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Acquisition"}},"type":"object","required":["email","password"],"title":"SignupRequest"},"StartBody":{"properties":{"workflow_id":{"type":"integer","title":"Workflow Id"},"persona_ids":{"items":{"type":"string"},"type":"array","title":"Persona Ids"},"batch_size":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"Batch Size","default":6}},"type":"object","required":["workflow_id"],"title":"StartBody"},"SuspendTenantRequest":{"properties":{"reason":{"type":"string","maxLength":500,"minLength":4,"title":"Reason"}},"type":"object","required":["reason"],"title":"SuspendTenantRequest"},"TopupRequest":{"properties":{"amount_minor":{"type":"integer","maximum":10000000.0,"exclusiveMinimum":0.0,"title":"Amount Minor"},"return_url":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Return Url"}},"type":"object","required":["amount_minor"],"title":"TopupRequest"},"TotpDisableRequest":{"properties":{"target_user_id":{"type":"integer","title":"Target User Id"},"reason":{"type":"string","maxLength":500,"minLength":4,"title":"Reason"}},"type":"object","required":["target_user_id","reason"],"title":"TotpDisableRequest"},"TotpEnrollRequest":{"properties":{"secret":{"type":"string","maxLength":64,"minLength":16,"title":"Secret"},"code":{"type":"string","maxLength":6,"minLength":6,"title":"Code"}},"type":"object","required":["secret","code"],"title":"TotpEnrollRequest"},"TurnIn":{"properties":{"run_id":{"type":"integer","title":"Run Id"},"seq":{"type":"integer","minimum":0.0,"title":"Seq"},"role":{"type":"string","title":"Role"},"text":{"type":"string","maxLength":8000,"minLength":1,"title":"Text"},"target_e164":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target E164"},"target_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Target Id"},"outcome_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Outcome Id"},"reasoning":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Reasoning"}},"type":"object","required":["run_id","seq","role","text"],"title":"TurnIn","description":"Wire shape for POST /internal/turns. tenant_id is from X-Tenant-Id\nheader (set by the system-key auth path), not the body, so a malicious\nvoice_bot can't cross-write."},"UnsuspendTenantRequest":{"properties":{"reason":{"type":"string","maxLength":500,"minLength":4,"title":"Reason"}},"type":"object","required":["reason"],"title":"UnsuspendTenantRequest"},"UpdateRuleRequest":{"properties":{"title":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Title"},"content":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Content"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"severity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity"}},"type":"object","title":"UpdateRuleRequest"},"UsageEventBatch":{"properties":{"events":{"items":{"$ref":"#/components/schemas/UsageEventBody"},"type":"array","maxItems":200,"minItems":1,"title":"Events"}},"type":"object","required":["events"],"title":"UsageEventBatch"},"UsageEventBody":{"properties":{"at":{"type":"string","title":"At"},"provider":{"type":"string","maxLength":40,"minLength":1,"title":"Provider"},"model":{"type":"string","maxLength":80,"title":"Model","default":""},"service_type":{"type":"string","maxLength":20,"minLength":1,"title":"Service Type"},"event_kind":{"type":"string","maxLength":40,"minLength":1,"title":"Event Kind"},"units":{"type":"number","title":"Units"},"unit_type":{"type":"string","maxLength":20,"minLength":1,"title":"Unit Type"},"outcome_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Outcome Id"},"turn_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Turn Id"},"idempotency_key":{"anyOf":[{"type":"string","maxLength":160},{"type":"null"}],"title":"Idempotency Key"},"raw_payload":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Raw Payload"}},"type":"object","required":["at","provider","service_type","event_kind","units","unit_type"],"title":"UsageEventBody"},"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"}}}}