{"openapi":"3.1.0","info":{"title":"aiivr compliance API","version":"0.1.0"},"paths":{"/webhooks/vapi":{"post":{"tags":["vapi"],"summary":"Vapi Webhook","description":"Dispatch one Vapi server message, logging how long the waited-on ones took.","operationId":"vapi_webhook_webhooks_vapi_post","parameters":[{"name":"x-vapi-secret","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Vapi-Secret"}}],"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 Vapi Webhook Webhooks Vapi Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/leads":{"post":{"summary":"Api Lead","description":"Async only to read the body; the key lookup, the hourly count and the writes\nblock, so they run off the event loop (code review 2026-10-03).","operationId":"api_lead_api_v1_leads_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"get":{"summary":"Api Find Lead","operationId":"api_find_lead_api_v1_leads_get","parameters":[{"name":"phone","in":"query","required":false,"schema":{"type":"string","default":"","title":"Phone"}},{"name":"lead_id","in":"query","required":false,"schema":{"type":"string","default":"","title":"Lead Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/calls":{"post":{"summary":"Api Call","operationId":"api_call_api_v1_calls_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/calls/{call_id}/recording":{"get":{"summary":"Api Call Recording","description":"A call's recording, for anything holding the account's key (owner, 2026-10-15:\n\"ability to pull recordings\"; Zapier's call triggers hand it on as a file). Streamed\nthrough as an attachment, never a redirect: the signed audio URLs are short-lived, and\na client following a redirect with its Authorization header is refused by them. Only\nthe key's own account's calls; any other is not found. Plain `def`: FastAPI runs it\noff the event loop.","operationId":"api_call_recording_api_v1_calls__call_id__recording_get","parameters":[{"name":"call_id","in":"path","required":true,"schema":{"type":"string","title":"Call Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/transfers":{"get":{"summary":"Api Transfers","description":"The account's calls put through to its advisor, newest first, with whether each was\napproved (093): true, false, or null for not reviewed yet. A sheet or CRM marks the\napproved ones by it (owner, 2026-10-20: Ray's \"Solar 2026\" sheet turns them green).","operationId":"api_transfers_api_v1_transfers_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/me":{"get":{"summary":"Api Me","description":"Who the key is: Zapier's connection test.","operationId":"api_me_api_v1_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/events":{"get":{"summary":"Api Events","description":"The account's events, newest first (a polling trigger, and a hook's sample); with\n`after_id`, those after it, oldest first, to read every one page by page (code review\n2026-10-22: a reader of the newest 100 skipped any more than that between its reads).","operationId":"api_events_api_v1_events_get","parameters":[{"name":"event","in":"query","required":false,"schema":{"type":"string","default":"","title":"Event"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":25,"title":"Limit"}},{"name":"after_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"After Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/hooks":{"post":{"summary":"Api Hook Add","description":"Subscribe `target_url` to `event` (REST hooks): {\"event\", \"target_url\"}.","operationId":"api_hook_add_api_v1_hooks_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/hooks/{hook_id}":{"get":{"summary":"Api Hook Get","description":"One of the caller's own hooks, or 404: whether a subscription still stands (code\nreview 2026-10-22: the n8n node's checkExists). Another account's is a 404 too.","operationId":"api_hook_get_api_v1_hooks__hook_id__get","parameters":[{"name":"hook_id","in":"path","required":true,"schema":{"type":"integer","title":"Hook Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Api Hook Delete","operationId":"api_hook_delete_api_v1_hooks__hook_id__delete","parameters":[{"name":"hook_id","in":"path","required":true,"schema":{"type":"integer","title":"Hook Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/lists":{"get":{"summary":"Api Lists","operationId":"api_lists_api_v1_lists_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/campaigns":{"get":{"summary":"Api Campaigns","operationId":"api_campaigns_api_v1_campaigns_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/crm/triggers/subscription":{"post":{"summary":"Subscription","description":"A workflow's trigger created, updated or deleted in a business account.","operationId":"subscription_crm_triggers_subscription_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Health Health Get"}}}}}}},"/pre-dial":{"post":{"summary":"Pre Dial","description":"May we dial this lead right now?\n\nComposes state rules, suppression, calling window and retry pacing.\nReturns every failure rather than the first, so a bad list import produces one\ndiagnosable report instead of thousands of half-answers.","operationId":"pre_dial_pre_dial_post","parameters":[{"name":"x-aiivr-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Aiivr-Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreDialRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreDialResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/actions/qualification":{"post":{"summary":"Log Qualification","operationId":"log_qualification_actions_qualification_post","parameters":[{"name":"x-aiivr-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Aiivr-Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QualificationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ack"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/actions/transfer":{"post":{"summary":"Request Transfer","description":"The model *requests*; this decides.\n\nGates are checked here, in code, because a model that decides on vibes will\neventually transfer a renter.","operationId":"request_transfer_actions_transfer_post","parameters":[{"name":"x-aiivr-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Aiivr-Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/actions/dnc":{"post":{"summary":"Mark Dnc","description":"Suppress immediately. Never conditional, never deferred.","operationId":"mark_dnc_actions_dnc_post","parameters":[{"name":"x-aiivr-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Aiivr-Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DncRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ack"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/actions/callback":{"post":{"summary":"Schedule Callback","operationId":"schedule_callback_actions_callback_post","parameters":[{"name":"x-aiivr-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Aiivr-Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallbackRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ack"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/calls/complete":{"post":{"summary":"Call Complete","description":"Terminal record for one call attempt.\n\n`hooked` is computed here rather than trusted from the caller — it is the Phase 2\nselection metric, and a platform-supplied value would not be comparable across\nplatforms.","operationId":"call_complete_calls_complete_post","parameters":[{"name":"x-aiivr-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Aiivr-Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallCompleteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ack"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"Ack":{"properties":{"ok":{"type":"boolean","title":"Ok","default":true},"detail":{"type":"string","title":"Detail","default":""}},"type":"object","title":"Ack"},"CallCompleteRequest":{"properties":{"call_id":{"type":"string","title":"Call Id"},"lead_id":{"type":"string","title":"Lead Id"},"arm_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Arm Id"},"started_at":{"type":"string","format":"date-time","title":"Started At"},"answered_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Answered At"},"ended_at":{"type":"string","format":"date-time","title":"Ended At"},"disposition":{"type":"string","title":"Disposition"},"recording_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recording Url"},"transcript":{"items":{"$ref":"#/components/schemas/TurnRecord"},"type":"array","title":"Transcript"},"cost_cents":{"type":"integer","title":"Cost Cents","default":0}},"type":"object","required":["call_id","lead_id","started_at","ended_at","disposition"],"title":"CallCompleteRequest","description":"Posted when a call ends, whatever placed it."},"CallbackRequest":{"properties":{"call_id":{"type":"string","title":"Call Id"},"when_text":{"type":"string","title":"When Text"},"channel":{"type":"string","enum":["phone","email","sms"],"title":"Channel","default":"phone"},"contact":{"type":"string","title":"Contact","default":""}},"type":"object","required":["call_id","when_text"],"title":"CallbackRequest"},"DncRequest":{"properties":{"call_id":{"type":"string","title":"Call Id"},"phone":{"type":"string","title":"Phone"},"verbatim":{"type":"string","title":"Verbatim","default":""},"source":{"type":"string","enum":["stop_guard","model","manual"],"title":"Source","default":"model"}},"type":"object","required":["call_id","phone"],"title":"DncRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"PreDialRequest":{"properties":{"lead_id":{"type":"string","title":"Lead Id"},"phone":{"type":"string","title":"Phone"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"attempt_count":{"type":"integer","title":"Attempt Count","default":0},"last_attempt_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Attempt At"}},"type":"object","required":["lead_id","phone"],"title":"PreDialRequest","description":"Asked before every origination. There is no other sanctioned path."},"PreDialResponse":{"properties":{"allowed":{"type":"boolean","title":"Allowed"},"reason":{"type":"string","title":"Reason","default":""},"blocks":{"items":{"type":"string"},"type":"array","title":"Blocks"},"script_variant":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Script Variant"},"arm_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Arm Id"},"disclosure_required":{"type":"boolean","title":"Disclosure Required","default":true},"recording_disclosure_required":{"type":"boolean","title":"Recording Disclosure Required","default":true}},"type":"object","required":["allowed"],"title":"PreDialResponse"},"QualificationRequest":{"properties":{"call_id":{"type":"string","title":"Call Id"},"field":{"type":"string","enum":["homeowner","decision_maker","monthly_bill","roof","credit_band"],"title":"Field"},"value":{"type":"string","title":"Value"},"verbatim":{"type":"string","title":"Verbatim","default":""}},"type":"object","required":["call_id","field","value"],"title":"QualificationRequest"},"TransferRequest":{"properties":{"call_id":{"type":"string","title":"Call Id"},"reason":{"type":"string","title":"Reason"},"whisper_summary":{"type":"string","title":"Whisper Summary"}},"type":"object","required":["call_id","reason","whisper_summary"],"title":"TransferRequest"},"TransferResponse":{"properties":{"outcome":{"type":"string","enum":["connecting","no_rep_available","not_qualified"],"title":"Outcome"},"instruction":{"type":"string","title":"Instruction"},"rep_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rep Id"}},"type":"object","required":["outcome","instruction"],"title":"TransferResponse"},"TurnRecord":{"properties":{"seq":{"type":"integer","title":"Seq"},"role":{"type":"string","enum":["agent","caller"],"title":"Role"},"text":{"type":"string","title":"Text"},"stt_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Stt Ms"},"llm_ttft_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Llm Ttft Ms"},"tts_ttfb_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Tts Ttfb Ms"}},"type":"object","required":["seq","role","text"],"title":"TurnRecord"},"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"}}}}