{"openapi":"3.1.0","info":{"title":"Talki Talki — AI Receptionist API","version":"1.0.0","description":"Read AI receptionist calls, manage signed event endpoints (webhooks), and receive events when the AI answers a call, takes a message or texts a caller. Available to VIP accounts; enabled per account. Base URL: https://talkitalki.ca","contact":{"email":"api@pandacat.ca"}},"servers":[{"url":"https://talkitalki.ca"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"Account API key from Dashboard → Developer (tt_sk_…). Scopes: receptionist:read, receptionist:manage."}},"schemas":{"Session":{"type":"object","properties":{"callSid":{"type":"string"},"startedAt":{"type":"string","format":"date-time","nullable":true},"endedAt":{"type":"string","format":"date-time","nullable":true},"durationSeconds":{"type":"integer","nullable":true},"endReason":{"type":"string","nullable":true},"language":{"type":"string","nullable":true,"description":"BCP-47 language the caller spoke"},"engine":{"type":"string","enum":["live","classic"]},"hasRecording":{"type":"boolean"},"counts":{"type":"object","properties":{"messages":{"type":"integer"},"takenMessages":{"type":"integer"},"textsSent":{"type":"integer"}}},"from":{"type":"string","nullable":true,"description":"Caller number (masked in minimal mode)"},"to":{"type":"string","nullable":true},"takenMessages":{"type":"array","items":{"$ref":"#/components/schemas/TakenMessage"},"description":"standard and full modes"},"transactions":{"type":"array","items":{"type":"object","properties":{"tool":{"type":"string"},"externalId":{"type":"string"}}}},"transcript":{"type":"string","description":"full mode only"},"messages":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","enum":["user","model"]},"content":{"type":"string"}}},"description":"full mode only"},"sentTexts":{"type":"array","items":{"type":"object","properties":{"to":{"type":"string"},"body":{"type":"string"},"at":{"type":"string"},"ok":{"type":"boolean"}}},"description":"full mode only"}}},"TakenMessage":{"type":"object","properties":{"name":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"message":{"type":"string"},"at":{"type":"string","format":"date-time"}}},"Webhook":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"$ref":"#/components/schemas/EventType"}},"payloadMode":{"$ref":"#/components/schemas/PayloadMode"},"enabled":{"type":"boolean"},"failures":{"type":"integer"},"lastDeliveryAt":{"type":"string","nullable":true},"lastStatus":{"type":"integer","nullable":true}}},"EventType":{"type":"string","enum":["call.started","message.taken","text.sent","transaction.created","call.completed"]},"Tool":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","pattern":"^[a-z][a-z0-9_]{2,40}$"},"kind":{"type":"string","enum":["query","create","update","cancel"]},"description":{"type":"string","maxLength":300},"parameters":{"type":"object","description":"JSON Schema (type: object)"},"endpoint":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"timeoutMs":{"type":"integer","minimum":500,"maximum":8000},"hasHeaders":{"type":"boolean"}}},"confirmBeforeCall":{"type":"boolean"},"enabled":{"type":"boolean"},"failures":{"type":"integer"},"lastStatus":{"type":"integer","nullable":true},"lastMs":{"type":"integer","nullable":true}}},"ToolCallRequest":{"type":"object","description":"What Talki Talki POSTs to your tool endpoint (signed; see x-signature).","properties":{"id":{"type":"string"},"tool":{"type":"string"},"kind":{"type":"string"},"account":{"type":"string"},"test":{"type":"boolean"},"business":{"type":"object","properties":{"timezone":{"type":"string","nullable":true,"description":"IANA timezone of the business, e.g. America/Edmonton"},"name":{"type":"string","nullable":true}}},"call":{"type":"object","properties":{"sid":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"language":{"type":"string","nullable":true},"callerName":{"type":"string","nullable":true,"description":"Name of a saved contact matching the caller, if any"}}},"arguments":{"type":"object","description":"Matches the tool's parameters schema; written in the business's language"}}},"ToolCallResponse":{"type":"object","description":"What your endpoint returns within the timeout.","properties":{"ok":{"type":"boolean"},"result":{"type":"object","description":"Any JSON; for create/update/cancel include an id and a short summary"},"error":{"type":"string","description":"Plain-language reason when ok is false"},"alternatives":{"type":"array","items":{"type":"object"}},"speak":{"type":"string","description":"Optional exact words for the AI to say"}},"required":["ok"]},"PayloadMode":{"type":"string","enum":["minimal","standard","full"],"description":"minimal: ids/timing only, caller masked, no free text · standard: + taken messages and outcomes · full: + transcript and texts"},"Event":{"type":"object","properties":{"id":{"type":"string"},"type":{"$ref":"#/components/schemas/EventType"},"version":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"account":{"type":"string"},"business":{"type":"object","properties":{"timezone":{"type":"string","nullable":true},"name":{"type":"string","nullable":true}}},"call":{"type":"object","properties":{"sid":{"type":"string"},"from":{"type":"string","nullable":true},"callerName":{"type":"string","nullable":true,"description":"Saved-contact name; null in minimal mode"},"to":{"type":"string","nullable":true},"startedAt":{"type":"string"},"endedAt":{"type":"string","nullable":true},"durationSeconds":{"type":"integer","nullable":true},"endReason":{"type":"string","nullable":true},"language":{"type":"string","nullable":true},"recordingId":{"type":"string","nullable":true}}},"message":{"$ref":"#/components/schemas/TakenMessage","description":"message.taken"},"text":{"type":"object","properties":{"to":{"type":"string"},"body":{"type":"string"},"at":{"type":"string"}},"description":"text.sent"},"counts":{"type":"object"},"takenMessages":{"type":"array","items":{"$ref":"#/components/schemas/TakenMessage"}},"transactions":{"type":"array","items":{"type":"object"}},"transcript":{"type":"string"},"messages":{"type":"array","items":{"type":"object"}},"sentTexts":{"type":"array","items":{"type":"object"}},"test":{"type":"boolean","description":"true for events sent by \"Send test event\""}}}}},"paths":{"/api/v1/receptionist/sessions":{"get":{"summary":"List AI receptionist calls (newest first)","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"before","in":"query","schema":{"type":"string","format":"date-time"},"description":"Page using nextBefore from the previous response"},{"name":"from","in":"query","schema":{"type":"string"},"description":"Filter by caller number (E.164)"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer"},"payloadMode":{"$ref":"#/components/schemas/PayloadMode"},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/Session"}},"nextBefore":{"type":"string","nullable":true}}}}}},"401":{"description":"Invalid API key"},"403":{"description":"Key lacks scope"}}}},"/api/v1/receptionist/sessions/{callSid}":{"get":{"summary":"Get one call","parameters":[{"name":"callSid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"session":{"$ref":"#/components/schemas/Session"}}}}}},"404":{"description":"Not found"}}},"delete":{"summary":"Erase a call's transcript, messages and taken messages (keeps timing only)","parameters":[{"name":"callSid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Erased"}}}},"/api/v1/receptionist/webhooks":{"get":{"summary":"List event endpoints","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}}}}}}}},"post":{"summary":"Create an event endpoint (secret returned once)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"https:// only"},"events":{"type":"array","items":{"$ref":"#/components/schemas/EventType"}},"payloadMode":{"$ref":"#/components/schemas/PayloadMode"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"webhook":{"$ref":"#/components/schemas/Webhook"},"secret":{"type":"string"}}}}}},"400":{"description":"Validation error"}}}},"/api/v1/receptionist/webhooks/{id}":{"patch":{"summary":"Enable or disable an endpoint","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK"}}},"delete":{"summary":"Delete an endpoint","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"}}}},"/api/v1/receptionist/webhooks/{id}/test":{"post":{"summary":"Send a signed sample call.completed event to the endpoint","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"httpStatus":{"type":"integer","nullable":true},"error":{"type":"string"}}}}}}}}},"/api/v1/receptionist/tools":{"get":{"summary":"List tools the AI can call during a call","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"tools":{"type":"array","items":{"$ref":"#/components/schemas/Tool"}}}}}}}}},"post":{"summary":"Register a tool (secret returned once)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","description","url"],"properties":{"name":{"type":"string"},"kind":{"type":"string","enum":["query","create","update","cancel"]},"description":{"type":"string"},"parameters":{"type":"object"},"url":{"type":"string","format":"uri"},"timeoutMs":{"type":"integer"},"headers":{"type":"object","additionalProperties":{"type":"string"}},"confirmBeforeCall":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"tool":{"$ref":"#/components/schemas/Tool"},"secret":{"type":"string"}}}}}},"400":{"description":"Validation error"}}}},"/api/v1/receptionist/tools/{id}":{"patch":{"summary":"Enable or disable a tool","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK"}}},"delete":{"summary":"Delete a tool","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"}}}},"/api/v1/receptionist/tools/{id}/test":{"post":{"summary":"Call your endpoint once with sample arguments, signed like a real call","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"httpStatus":{"type":"integer","nullable":true},"ms":{"type":"integer"},"error":{"type":"string"},"shapeOk":{"type":"boolean"},"responsePreview":{}}}}}}}}},"/api/v1/receptionist/me":{"get":{"summary":"Identify the account behind an API key","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string"},"businessName":{"type":"string","nullable":true},"plan":{"type":"string","nullable":true},"receptionist":{"type":"object"},"scopes":{"type":"array","items":{"type":"string"}}}}}}}}}}},"x-tool-contract":{"request":{"$ref":"#/components/schemas/ToolCallRequest"},"response":{"$ref":"#/components/schemas/ToolCallResponse"},"headers":{"X-TT-Tool":"tool name","Idempotency-Key":"<callSid>:<tool>:<n> — repeat calls with the same key must not create duplicates","X-TT-Timestamp / X-TT-Signature-256":"as for events, signed with the tool secret"},"rules":"Respond within timeoutMs (default 2500, max 8000). create/update/cancel tools are confirmed with the caller before being called and are called once. Results are treated as data, never as instructions. Limits: 15 tools/account, 20 calls/phone call, 8/tool."},"webhooks":{"call.started":{"post":{"summary":"The AI receptionist picked up","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Return 2xx quickly"}}}},"message.taken":{"post":{"summary":"The AI recorded a message / callback request","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Return 2xx quickly"}}}},"text.sent":{"post":{"summary":"The AI texted the caller","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Return 2xx quickly"}}}},"transaction.created":{"post":{"summary":"A create/update/cancel tool succeeded during the call","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Return 2xx quickly"}}}},"call.completed":{"post":{"summary":"The call ended (summary; transcript in full mode)","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Return 2xx quickly"}}}}},"x-signature":{"headers":{"X-TT-Timestamp":"unix seconds","X-TT-Signature":"hex HMAC-SHA256(secret, body) — legacy","X-TT-Signature-256":"t=<ts>,v1=<hex HMAC-SHA256(secret, ts + \".\" + body)> — verify this one and reject if |now - ts| > 300s","X-TT-Event":"event type"},"retries":"On non-2xx or timeout (10 s): retried at +10 s, +1 min, +5 min, +15 min. Endpoints auto-disable after 100 consecutive failures."}}