{"openapi":"3.1.0","info":{"title":"Callshift API","version":"1.0.0","description":"Callshift public API for managing contacts, calls, and more."},"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key passed as a Bearer token"}},"schemas":{"HealthResponse":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","unhealthy"]},"database":{"type":"string","enum":["connected","disconnected"]}},"required":["status","database"]},"AgentLanguage":{"type":"string","enum":["fr","en","nl","pt","es"],"example":"en"},"AgentListItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"name":{"type":"string","example":"Alice"},"gender":{"type":"string","enum":["FEMALE","MALE"],"example":"FEMALE"},"language":{"$ref":"#/components/schemas/AgentLanguage"},"entityId":{"type":"string","nullable":true,"format":"uuid","description":"The agent's entity, or `null` when the agent is shared.","example":null}},"required":["id","name","gender","language","entityId"]},"AgentListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AgentListItem"}},"pageCount":{"type":"number","example":3}},"required":["data","pageCount"]},"ValidationIssue":{"type":"object","properties":{"code":{"type":"string","example":"invalid_enum_value"},"path":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]},"example":["contacts",0,"email"]},"message":{"type":"string","example":"Invalid email"}},"required":["code","path","message"]},"ValidationErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"name":{"type":"string","enum":["ZodError"]},"issues":{"type":"array","items":{"$ref":"#/components/schemas/ValidationIssue"}}},"required":["name","issues"]}},"required":["success","error"]},"ErrorResponse":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"AgentDiagram":{"type":"object","properties":{"nodes":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["startCall"]},"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"]},"data":{"type":"object","properties":{"brief":{"type":"string"},"welcomeMessage":{"type":"string"},"outbound":{"type":"object","properties":{"voiceMailEnabled":{"type":"boolean"},"voiceMailMessage":{"type":"string"},"voiceMailExpectedDuration":{"type":"number","minimum":5,"maximum":60},"voiceMailProvider":{"anyOf":[{"type":"string","enum":["google"]},{"type":"string","enum":["openai"]},{"type":"string","enum":["vapi"]}]},"welcomeMessage":{"type":"string"},"firstMessageMode":{"anyOf":[{"type":"string","enum":["assistant-speaks-first"]},{"type":"string","enum":["assistant-waits-for-user"]},{"type":"string","enum":["assistant-speaks-first-with-model-generated-message"]}]},"pauseBeforeSpeakingSeconds":{"type":"number","minimum":0,"maximum":5}},"required":["voiceMailMessage","welcomeMessage"]}},"required":["brief","welcomeMessage"]}},"required":["id","type","position","data"]},{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["endCall"]},"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"]},"data":{"type":"object","properties":{"endCallMessage":{"type":"string"}},"required":["endCallMessage"]}},"required":["id","type","position","data"]},{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["knowHow"]},"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"]},"data":{"type":"object","properties":{"title":{"type":"string"},"prompt":{"type":"string"}},"required":["title","prompt"]}},"required":["id","type","position","data"]},{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["forwardAgent"]},"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"]},"data":{"type":"object","properties":{"agentId":{"type":"string","minLength":1},"message":{"type":"string"},"description":{"type":"string"}},"required":["agentId","message","description"]}},"required":["id","type","position","data"]},{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["forwardCall"]},"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"]},"data":{"oneOf":[{"type":"object","properties":{"title":{"type":"string","minLength":1},"prompt":{"type":"string","minLength":1},"forwardingMessage":{"type":"string","minLength":1},"destinationType":{"type":"string","enum":["fixed","lookup"],"default":"fixed"},"forwardingPhoneNumber":{"type":"string"},"lookupUrl":{"type":"string"},"lookupMessage":{"type":"string"},"lookupParameters":{"type":"object","properties":{"type":{"type":"string","enum":["object"]},"properties":{"type":"object","additionalProperties":{"type":"object","properties":{"type":{"type":"string"},"description":{"type":"string"},"enum":{"type":"array","items":{"nullable":true}},"format":{"type":"string"},"default":{"nullable":true},"minimum":{"type":"number"},"maximum":{"type":"number"}},"required":["type"]}},"required":{"type":"array","items":{"type":"string"}}},"required":["type","properties"]},"holdMusic":{"type":"string","enum":["default","calm","custom"],"default":"default"},"holdMusicUrl":{"anyOf":[{"type":"string","format":"uri"},{"type":"string","enum":[""]}]},"humanDetectionEnabled":{"type":"boolean","default":false},"humanDetectionTimeout":{"type":"number","minimum":10,"maximum":120,"default":30},"whisperMessage":{"type":"string"},"threeWayIntroduction":{"type":"string"},"transferTimeout":{"type":"number","minimum":30,"maximum":300,"default":60},"fallbackMessage":{"type":"string"},"transferMode":{"type":"string","enum":["cold"]},"greetingMessage":{"type":"string"}},"required":["title","prompt","forwardingMessage","transferMode"]},{"type":"object","properties":{"title":{"type":"string","minLength":1},"prompt":{"type":"string","minLength":1},"forwardingMessage":{"type":"string","minLength":1},"destinationType":{"type":"string","enum":["fixed","lookup"],"default":"fixed"},"forwardingPhoneNumber":{"type":"string"},"lookupUrl":{"type":"string"},"lookupMessage":{"type":"string"},"lookupParameters":{"type":"object","properties":{"type":{"type":"string","enum":["object"]},"properties":{"type":"object","additionalProperties":{"type":"object","properties":{"type":{"type":"string"},"description":{"type":"string"},"enum":{"type":"array","items":{"nullable":true}},"format":{"type":"string"},"default":{"nullable":true},"minimum":{"type":"number"},"maximum":{"type":"number"}},"required":["type"]}},"required":{"type":"array","items":{"type":"string"}}},"required":["type","properties"]},"holdMusic":{"type":"string","enum":["default","calm","custom"],"default":"default"},"holdMusicUrl":{"anyOf":[{"type":"string","format":"uri"},{"type":"string","enum":[""]}]},"humanDetectionEnabled":{"type":"boolean","default":false},"humanDetectionTimeout":{"type":"number","minimum":10,"maximum":120,"default":30},"whisperMessage":{"type":"string"},"threeWayIntroduction":{"type":"string"},"transferTimeout":{"type":"number","minimum":30,"maximum":300,"default":60},"fallbackMessage":{"type":"string"},"transferMode":{"type":"string","enum":["warm"]},"greetingMessage":{"type":"string","minLength":1}},"required":["title","prompt","forwardingMessage","transferMode","greetingMessage"]}]}},"required":["id","type","position","data"]}]}},"edges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"source":{"type":"string"},"target":{"type":"string"},"data":{"type":"object","properties":{"condition":{"type":"string","enum":["isExistingContact","notExistingContact","notNewCaller","isNewCaller","inboundOnly","outboundOnly"]}},"required":["condition"]}},"required":["id","source","target"]}}},"required":["nodes","edges"],"description":"The conversation flow. `knowHow` node prompts are HTML. A tool (see `GET /v1/tools`) is attached to the agent by referencing it in a prompt with a `<tool-node>` element:\n\n`<tool-node functionname=\"checkOrder\" category=\"custom\" toolslug=\"\" toolid=\"550e8400-e29b-41d4-a716-446655440000\">Use checkOrder to look up the caller's order.</tool-node>`\n\n- `functionname` is the camelCase form of the tool name (`Check order` → `checkOrder`). The tool is resolved by this name, so renaming a tool detaches it from the agents that reference it until their prompts are updated.\n- `category` is `custom` or `query` for those types, `notifications` for `sendSms` and `sendEmail`.\n- `toolid` is the tool id. A diagram whose tool node matches no tool of the account by both `toolid` and `functionname` is refused (422).\n- The element's text is the instruction the agent reads.\n\nTransferring the call, handing over to another agent and ending the call are nodes (`forwardCall`, `forwardAgent`, `endCall`), not tools.\n\nA `forwardCall` node with `destinationType: \"lookup\"` has no `forwardingPhoneNumber`: during the call, its `lookupUrl` receives the same request as a custom tool (with the arguments `lookupParameters` describes) and answers `{ \"number\": \"+33…\", \"message\"?, \"context\"? }` or `{ \"error\": \"…\", \"context\"? }` within 5 seconds. The number must be in the country of the line the call is on. The node becomes a tool named after the camelCase of its `title`, which no other tool of the agent may share (422). LiveKit agents only: the node is left out when the agent, or the account it inherits from, uses Vapi."},"AgentWebhookSettings":{"type":"object","nullable":true,"properties":{"enabled":{"type":"boolean","example":true},"webhookId":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"}},"required":["enabled"],"description":"After-call automation webhook settings, or null when never configured."},"AgentTool":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"type":{"type":"string","enum":["custom","query","sendSms","sendEmail"]},"name":{"type":"string","example":"Check order"}},"required":["id","type","name"]},"AgentDetails":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"name":{"type":"string","example":"Alice"},"gender":{"type":"string","enum":["FEMALE","MALE"],"example":"FEMALE"},"language":{"$ref":"#/components/schemas/AgentLanguage"},"entityId":{"type":"string","nullable":true,"format":"uuid","description":"The agent's entity, or `null` when the agent is shared.","example":null},"backgroundSound":{"type":"string","nullable":true,"enum":["office_ambience","city_ambience","forest_ambience","crowded_room","keyboard_typing","keyboard_typing2","hold_music","gym_ambience"],"example":"office_ambience"},"backgroundSoundVolume":{"type":"number","nullable":true,"example":null},"silenceTimeoutSeconds":{"type":"integer","nullable":true,"example":null},"maxDurationSeconds":{"type":"integer","nullable":true,"example":null},"provider":{"type":"string","example":"google"},"model":{"type":"string","example":"gemini-live-3.1-flash"},"temperature":{"type":"number","example":1},"maxTokens":{"type":"number","example":1500},"minEndpointingDelay":{"type":"number","nullable":true,"example":null},"summaryPrompt":{"type":"string","nullable":true,"example":null},"evaluationPrompt":{"type":"string","nullable":true,"example":null},"informationToCollect":{"type":"array","nullable":true,"items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1},"type":{"type":"string","enum":["string","number","boolean","enum"]},"description":{"type":"string"},"enumValues":{"type":"array","items":{"type":"string"}}},"required":["id","name","type"]}},"diagram":{"$ref":"#/components/schemas/AgentDiagram"},"webhook":{"$ref":"#/components/schemas/AgentWebhookSettings"},"tools":{"type":"array","items":{"$ref":"#/components/schemas/AgentTool"},"description":"Tools referenced by the agent's diagram prompts (read-only: attach or detach a tool through `diagram`)."}},"required":["id","name","gender","language","entityId","backgroundSound","backgroundSoundVolume","silenceTimeoutSeconds","maxDurationSeconds","provider","model","temperature","maxTokens","minEndpointingDelay","summaryPrompt","evaluationPrompt","informationToCollect","diagram","webhook","tools"]},"PatchAgentResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]}},"required":["success"]},"PatchAgentBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"gender":{"type":"string","enum":["FEMALE","MALE"]},"language":{"$ref":"#/components/schemas/AgentLanguage"},"backgroundSound":{"type":"string","nullable":true,"enum":["office_ambience","city_ambience","forest_ambience","crowded_room","keyboard_typing","keyboard_typing2","hold_music","gym_ambience"],"description":"Ambience played under the call, or `null` for none.","example":"office_ambience"},"backgroundSoundVolume":{"type":"number","nullable":true,"minimum":0,"maximum":1,"description":"Volume of the background sound, from 0 to 1. `null` uses the default of 0.2.","example":0.2},"silenceTimeoutSeconds":{"type":"integer","nullable":true,"minimum":5,"maximum":120,"description":"Seconds of caller silence before the agent hangs up, from 5 to 120. `null` uses the default of 25.","example":15},"maxDurationSeconds":{"type":"integer","nullable":true,"minimum":60,"maximum":3600,"description":"Maximum length of a call, in seconds, from 60 to 3600. The call then ends with `endedReason` `max-duration-exceeded`. `null` uses the default of 420.","example":600},"provider":{"type":"string","maxLength":50,"description":"Model provider: `google`, `openai` or `xai`. Defaults to `google` on create.","example":"google"},"model":{"type":"string","maxLength":50,"description":"Realtime (speech-to-speech) models: `gemini-3.8-live`, `gemini-live-3.1-flash` (google), `gpt-realtime-2.1-mini`, `gpt-live-1` (openai), `grok-voice-3.0` (xai). Pipeline models: `gpt-4o-mini`, `gpt-4o`, `gpt-4.1-mini`, `gpt-5-mini`, `gpt-5.4-mini` (openai). Defaults to `gemini-live-3.1-flash` on create.","example":"gemini-live-3.1-flash"},"voiceId":{"type":"string","maxLength":50},"temperature":{"type":"number","minimum":0,"maximum":2},"maxTokens":{"type":"number","minimum":1,"maximum":10000},"minEndpointingDelay":{"type":"number","nullable":true,"minimum":0.3,"maximum":2.5,"description":"Minimum time, in seconds, the agent waits after the caller stops speaking before answering, from 0.3 to 2.5. Raise it if callers get cut off mid-sentence (with a slow STT like Azure, try 0.9). Higher values slow every reply. Only applies to pipeline models. `null` uses the default.","example":0.9},"summaryPrompt":{"type":"string","nullable":true},"evaluationPrompt":{"type":"string","nullable":true},"informationToCollect":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1},"type":{"type":"string","enum":["string","number","boolean","enum"]},"description":{"type":"string"},"enumValues":{"type":"array","items":{"type":"string"}}},"required":["id","name","type"]}},"diagram":{"$ref":"#/components/schemas/AgentDiagram"},"entityId":{"type":"string","nullable":true,"format":"uuid","description":"The entity the item belongs to, or `null` to make it shared. Send this or `entityExternalId`, not both.","example":"550e8400-e29b-41d4-a716-446655440000"},"entityExternalId":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"description":"Your external id of the entity the item belongs to, or `null` to make it shared. Send this or `entityId`, not both.","example":"club-42"}}},"DuplicateAgentResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"}},"required":["id"]},"DuplicateAgentBody":{"type":"object","properties":{"entityId":{"type":"string","nullable":true,"format":"uuid","description":"The entity the item belongs to, or `null` to make it shared. Send this or `entityExternalId`, not both.","example":"550e8400-e29b-41d4-a716-446655440000"},"entityExternalId":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"description":"Your external id of the entity the item belongs to, or `null` to make it shared. Send this or `entityId`, not both.","example":"club-42"}},"description":"Omit both fields to keep the copy in the source agent's entity."},"SetAgentWebhookResponse":{"type":"object","properties":{"webhook":{"$ref":"#/components/schemas/AgentWebhookSettings"}},"required":["webhook"]},"SetAgentWebhookRequest":{"oneOf":[{"type":"object","properties":{"enabled":{"type":"boolean","enum":[true]},"webhookId":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"}},"required":["enabled","webhookId"]},{"type":"object","properties":{"enabled":{"type":"boolean","enum":[false]}},"required":["enabled"]}]},"CreateAgentResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"}},"required":["id"]},"CreateAgentBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50,"example":"Alice"},"gender":{"type":"string","enum":["FEMALE","MALE"],"example":"FEMALE"},"language":{"$ref":"#/components/schemas/AgentLanguage"},"backgroundSound":{"type":"string","nullable":true,"enum":["office_ambience","city_ambience","forest_ambience","crowded_room","keyboard_typing","keyboard_typing2","hold_music","gym_ambience"],"description":"Ambience played under the call, or `null` for none.","example":"office_ambience"},"backgroundSoundVolume":{"type":"number","nullable":true,"minimum":0,"maximum":1,"description":"Volume of the background sound, from 0 to 1. `null` uses the default of 0.2.","example":0.2},"silenceTimeoutSeconds":{"type":"integer","nullable":true,"minimum":5,"maximum":120,"description":"Seconds of caller silence before the agent hangs up, from 5 to 120. `null` uses the default of 25.","example":15},"maxDurationSeconds":{"type":"integer","nullable":true,"minimum":60,"maximum":3600,"description":"Maximum length of a call, in seconds, from 60 to 3600. The call then ends with `endedReason` `max-duration-exceeded`. `null` uses the default of 420.","example":600},"provider":{"type":"string","maxLength":50,"description":"Model provider: `google`, `openai` or `xai`. Defaults to `google` on create.","example":"google"},"model":{"type":"string","maxLength":50,"description":"Realtime (speech-to-speech) models: `gemini-3.8-live`, `gemini-live-3.1-flash` (google), `gpt-realtime-2.1-mini`, `gpt-live-1` (openai), `grok-voice-3.0` (xai). Pipeline models: `gpt-4o-mini`, `gpt-4o`, `gpt-4.1-mini`, `gpt-5-mini`, `gpt-5.4-mini` (openai). Defaults to `gemini-live-3.1-flash` on create.","example":"gemini-live-3.1-flash"},"voiceId":{"type":"string","maxLength":50},"temperature":{"type":"number","minimum":0,"maximum":2},"maxTokens":{"type":"number","minimum":1,"maximum":10000},"minEndpointingDelay":{"type":"number","nullable":true,"minimum":0.3,"maximum":2.5,"description":"Minimum time, in seconds, the agent waits after the caller stops speaking before answering, from 0.3 to 2.5. Raise it if callers get cut off mid-sentence (with a slow STT like Azure, try 0.9). Higher values slow every reply. Only applies to pipeline models. `null` uses the default.","example":0.9},"summaryPrompt":{"type":"string","nullable":true},"evaluationPrompt":{"type":"string","nullable":true},"informationToCollect":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","minLength":1},"type":{"type":"string","enum":["string","number","boolean","enum"]},"description":{"type":"string"},"enumValues":{"type":"array","items":{"type":"string"}}},"required":["id","name","type"]}},"diagram":{"$ref":"#/components/schemas/AgentDiagram"},"entityId":{"type":"string","nullable":true,"format":"uuid","description":"The entity the item belongs to, or `null` to make it shared. Send this or `entityExternalId`, not both.","example":"550e8400-e29b-41d4-a716-446655440000"},"entityExternalId":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"description":"Your external id of the entity the item belongs to, or `null` to make it shared. Send this or `entityId`, not both.","example":"club-42"}},"required":["name","gender","language"]},"SuccessResponse":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]},"PatchContactBody":{"type":"object","properties":{"phoneNumber":{"type":"string","example":"+33612345678"},"salutation":{"type":"string","enum":["mr","mrs","ms","miss"],"example":"mr"},"firstName":{"type":"string","example":"John"},"lastName":{"type":"string","example":"Doe"},"email":{"type":"string","format":"email","example":"john@example.com"},"information":{"type":"string","example":"VIP customer"},"metadata":{"type":"object","additionalProperties":{"nullable":true},"description":"Free-form JSON metadata (advanced mode). When set, replaces the entire metadata blob — takes precedence over `information`. Injected into the agent prompt via the `contact.metadata` variable and included in the call-ended webhook payload.","example":{"tier":"gold","priority":1,"tags":["vip","renewal"]}},"optedOut":{"type":"boolean","example":false}}},"ContactOptedOutBody":{"type":"object","properties":{"phoneNumber":{"type":"string","example":"+33612345678"}},"required":["phoneNumber"]},"CallPhone":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"number":{"type":"string","nullable":true,"example":"+33612345678"}},"required":["id","number"],"description":"Agent phone line used for the call. Matches the `phone` field of the call-ended webhook payload."},"CallListItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"agentId":{"type":"string","nullable":true,"format":"uuid"},"agentName":{"type":"string","nullable":true},"customerPhoneNumber":{"type":"string","nullable":true},"status":{"type":"string","enum":["COMPLETED","ERROR","FORWARDED","IN_PROGRESS","READY","REJECTED","SCHEDULED"],"example":"COMPLETED"},"type":{"type":"string","enum":["inbound","outbound","webcall"],"example":"inbound"},"startedAt":{"type":"string","nullable":true,"format":"date-time"},"endedAt":{"type":"string","nullable":true,"format":"date-time"},"endedReason":{"type":"string","nullable":true,"description":"Why the call ended. Known values: agent-line-entity-mismatch, contact-opted-out, cps-limit-exceeded, dial-failed, stuck-in-progress, twilio-call-permission, customer-busy, customer-declined, customer-did-not-answer, customer-number-not-found, customer-unavailable, exceeded-max-duration, max-duration-exceeded, no-international-permission, outbound-call-forbidden, sip-server-error, unknown-reason, voicemail. The value is passed through from the voice provider, so new values can appear; treat unknown values as a generic failure rather than rejecting them.","example":"customer-did-not-answer"},"createdAt":{"type":"string","format":"date-time"},"billingSeconds":{"type":"number","nullable":true,"description":"Billable duration in seconds, rounded up from the connected time. `costEstimationCents` prices it at the overage rate of your plan.","example":84},"costEstimationCents":{"type":"integer","nullable":true,"description":"Indicative cost of the call in euro cents, rounded to the nearest cent. Not a contractual amount: use it to compare calls and forecast spend, and the billing page for what was actually charged.\n\nIt adds up:\n- `billingSeconds` at your plan's per-minute overage rate (rounded up to a full minute first on minute-based plans);\n- the dial fee, on a campaign dial, whatever its outcome.\n\nIt ignores the minutes included in your plan: a call they cover is not charged its minutes, but still shows their price here. A dial fee below a cent can round to 0 on a single call.\n\nNull until the call has a `billingSeconds`, and when your account has no subscription with an overage rate.","example":70},"recordingUrl":{"type":"string","nullable":true,"description":"Direct, non-expiring URL of the call recording. No authentication is required beyond the URL itself. Null while the call is in progress or when no recording was produced.","example":"https://recordings.example.com/recordings/<callId>/<roomSid>.ogg"},"summary":{"type":"string","nullable":true},"isSilent":{"type":"boolean","nullable":true},"isSuccessful":{"type":"boolean","nullable":true},"isReached":{"type":"boolean","nullable":true},"isSignificant":{"type":"boolean","nullable":true},"phone":{"$ref":"#/components/schemas/CallPhone"},"from":{"type":"string","nullable":true,"description":"Number the call originated from: the agent phone for outbound calls, the caller for inbound calls.","example":"+33612345678"},"to":{"type":"string","nullable":true,"description":"Number the call was placed to: the customer for outbound calls, the agent phone for inbound calls.","example":"+33687654321"},"qualificationCriteria":{"type":"object","nullable":true,"additionalProperties":{"nullable":true},"description":"Information collected during the call, as configured in the agent's call analysis settings. Matches the `qualificationCriteria` field of the call-ended webhook payload.","example":{"budget":"500k","isDecisionMaker":true}}},"required":["id","agentId","agentName","customerPhoneNumber","status","type","startedAt","endedAt","endedReason","createdAt","billingSeconds","costEstimationCents","recordingUrl","summary","isSilent","isSuccessful","isReached","isSignificant","phone","from","to","qualificationCriteria"]},"CallListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CallListItem"}},"pageCount":{"type":"number","example":3}},"required":["data","pageCount"]},"CallDetails":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"agentId":{"type":"string","nullable":true,"format":"uuid"},"agentName":{"type":"string","nullable":true},"campaignId":{"type":"string","nullable":true,"format":"uuid"},"customerPhoneNumber":{"type":"string","nullable":true},"endedReason":{"type":"string","nullable":true,"description":"Why the call ended. Known values: agent-line-entity-mismatch, contact-opted-out, cps-limit-exceeded, dial-failed, stuck-in-progress, twilio-call-permission, customer-busy, customer-declined, customer-did-not-answer, customer-number-not-found, customer-unavailable, exceeded-max-duration, max-duration-exceeded, no-international-permission, outbound-call-forbidden, sip-server-error, unknown-reason, voicemail. The value is passed through from the voice provider, so new values can appear; treat unknown values as a generic failure rather than rejecting them.","example":"customer-did-not-answer"},"phoneId":{"type":"string","nullable":true,"format":"uuid"},"phone":{"$ref":"#/components/schemas/CallPhone"},"from":{"type":"string","nullable":true,"description":"Number the call originated from: the agent phone for outbound calls, the caller for inbound calls.","example":"+33612345678"},"to":{"type":"string","nullable":true,"description":"Number the call was placed to: the customer for outbound calls, the agent phone for inbound calls.","example":"+33687654321"},"recordingUrl":{"type":"string","nullable":true,"description":"Direct, non-expiring URL of the call recording. No authentication is required beyond the URL itself. Null while the call is in progress or when no recording was produced.","example":"https://recordings.example.com/recordings/<callId>/<roomSid>.ogg"},"summary":{"type":"string","nullable":true},"transcript":{"type":"string","nullable":true,"description":"Plain-text transcript, one line per turn prefixed by the speaker role. Not yet structured (no per-turn timestamps).","example":"User: Hello\nAssistant: Hi, how can I help?"},"isSilent":{"type":"boolean","nullable":true},"isSuccessful":{"type":"boolean","nullable":true},"isReached":{"type":"boolean","nullable":true},"isSignificant":{"type":"boolean","nullable":true},"qualificationCriteria":{"type":"object","nullable":true,"additionalProperties":{"nullable":true},"description":"Information collected during the call, as configured in the agent's call analysis settings. Matches the `qualificationCriteria` field of the call-ended webhook payload.","example":{"budget":"500k","isDecisionMaker":true}},"createdAt":{"type":"string","format":"date-time"},"billingSeconds":{"type":"number","nullable":true,"description":"Billable duration in seconds, rounded up from the connected time. `costEstimationCents` prices it at the overage rate of your plan.","example":84},"costEstimationCents":{"type":"integer","nullable":true,"description":"Indicative cost of the call in euro cents, rounded to the nearest cent. Not a contractual amount: use it to compare calls and forecast spend, and the billing page for what was actually charged.\n\nIt adds up:\n- `billingSeconds` at your plan's per-minute overage rate (rounded up to a full minute first on minute-based plans);\n- the dial fee, on a campaign dial, whatever its outcome.\n\nIt ignores the minutes included in your plan: a call they cover is not charged its minutes, but still shows their price here. A dial fee below a cent can round to 0 on a single call.\n\nNull until the call has a `billingSeconds`, and when your account has no subscription with an overage rate.","example":70},"endedAt":{"type":"string","nullable":true,"format":"date-time"},"startedAt":{"type":"string","nullable":true,"format":"date-time"},"status":{"type":"string","enum":["COMPLETED","ERROR","FORWARDED","IN_PROGRESS","READY","REJECTED","SCHEDULED"],"example":"COMPLETED"},"type":{"type":"string","enum":["inbound","outbound","webcall"],"example":"inbound"}},"required":["id","agentId","agentName","campaignId","customerPhoneNumber","endedReason","phoneId","phone","from","to","recordingUrl","summary","transcript","isSilent","isSuccessful","isReached","isSignificant","qualificationCriteria","createdAt","billingSeconds","costEstimationCents","endedAt","startedAt","status","type"]},"Phone":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"0d3a7e6b-2b8e-4c5b-9c4e-5f4b9d2a1c8e"},"phoneNumber":{"type":"string","example":"+15550001234"},"provider":{"type":"string","enum":["sip","twilio","telnyx"],"description":"How the number reached the account: a connected SIP trunk, or an import from the vendor.","example":"twilio"},"isOutboundAllowed":{"type":"boolean","example":true},"agent":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":["id","name"],"example":{"id":"550e8400-e29b-41d4-a716-446655440000","name":"Alice"}},"entityId":{"type":"string","nullable":true,"format":"uuid","description":"The number's entity, or `null` when the number is shared.","example":null}},"required":["id","phoneNumber","provider","isOutboundAllowed","agent","entityId"]},"ListPhonesResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Phone"}},"pageCount":{"type":"number","example":3}},"required":["data","pageCount"]},"UpdatePhoneBody":{"type":"object","properties":{"agentId":{"type":"string","nullable":true,"format":"uuid","description":"Agent answering inbound calls on this number; null unassigns it.","example":"550e8400-e29b-41d4-a716-446655440000"},"entityId":{"type":"string","nullable":true,"format":"uuid","description":"The entity the item belongs to, or `null` to make it shared. Send this or `entityExternalId`, not both.","example":"550e8400-e29b-41d4-a716-446655440000"},"entityExternalId":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"description":"Your external id of the entity the item belongs to, or `null` to make it shared. Send this or `entityId`, not both.","example":"club-42"}}},"SipPhone":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"0d3a7e6b-2b8e-4c5b-9c4e-5f4b9d2a1c8e"},"phoneNumber":{"type":"string","example":"+15550001234"},"agent":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":["id","name"],"example":{"id":"550e8400-e29b-41d4-a716-446655440000","name":"Alice"}},"entityId":{"type":"string","nullable":true,"format":"uuid","description":"The number's entity, or `null` when the number is shared.","example":null}},"required":["id","phoneNumber","agent","entityId"]},"ListSipPhonesResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SipPhone"}},"pageCount":{"type":"number","example":3}},"required":["data","pageCount"]},"CreateSipPhoneResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]},"ConnectSipTrunkBody":{"type":"object","properties":{"phoneNumber":{"type":"string","minLength":1,"example":"+15550001234"},"agentId":{"type":"string","nullable":true,"format":"uuid"},"sipTrunkId":{"type":"string","format":"uuid","description":"Attach the number to an existing SIP trunk. When set, the trunk definition fields are ignored."},"name":{"type":"string","minLength":1,"maxLength":100,"description":"Name for a newly created trunk. Defaults to the termination URI.","example":"acme-sip"},"terminationUri":{"type":"string","minLength":1,"maxLength":100,"example":"sip.example.com"},"transport":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[2]},{"type":"number","enum":[3]}],"description":"SIP transport: 1=UDP, 2=TCP, 3=TLS","example":1},"sipUsername":{"type":"string","nullable":true},"sipPassword":{"type":"string","nullable":true},"requireInboundAuth":{"type":"boolean","description":"Generate credentials the carrier must send on inbound calls. Defaults to false; ignored when sipTrunkId is set.","example":false},"entityId":{"type":"string","nullable":true,"format":"uuid","description":"The entity the item belongs to, or `null` to make it shared. Send this or `entityExternalId`, not both.","example":"550e8400-e29b-41d4-a716-446655440000"},"entityExternalId":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"description":"Your external id of the entity the item belongs to, or `null` to make it shared. Send this or `entityId`, not both.","example":"club-42"}},"required":["phoneNumber"]},"Trunk":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"acme-sip"},"provider":{"type":"string","example":"sip"},"region":{"type":"string","nullable":true,"example":null},"phoneNumbersCount":{"type":"integer","example":3},"callsPerSecond":{"type":"integer","example":10},"entityIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The entities of the numbers on this trunk. A trunk shared by several entities lists each of them; a trunk whose numbers are all shared lists none.","example":["550e8400-e29b-41d4-a716-446655440000"]}},"required":["id","name","provider","region","phoneNumbersCount","callsPerSecond","entityIds"]},"ListTrunksResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Trunk"}}},"required":["data"]},"CampaignListItemAgent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"name":{"type":"string","example":"Alice"},"gender":{"type":"string","enum":["FEMALE","MALE"],"example":"FEMALE"}},"required":["id","name","gender"]},"CampaignListItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"name":{"type":"string","example":"Q2 Outreach"},"status":{"type":"string","enum":["active","inactive"],"example":"active"},"phoneId":{"type":"string","format":"uuid","example":"0d3a7e6b-2b8e-4c5b-9c4e-5f4b9d2a1c8e"},"agent":{"$ref":"#/components/schemas/CampaignListItemAgent"}},"required":["id","name","status","phoneId","agent"]},"CampaignListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CampaignListItem"}},"pageCount":{"type":"number","example":3}},"required":["data","pageCount"]},"CreateCampaignResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]},"CreateCampaignBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"example":"Q2 Outreach"},"agentId":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"phoneId":{"type":"string","format":"uuid","description":"The phone the campaign dials from. It must be allowed to place outbound calls (`isOutboundAllowed` in GET /phones).","example":"0d3a7e6b-2b8e-4c5b-9c4e-5f4b9d2a1c8e"},"isActive":{"type":"boolean","default":false,"description":"Whether the campaign starts active. Defaults to false: the campaign is created inactive and dials nothing until it is activated, either here or with PATCH /campaigns/{campaignId}. Set to true to have contacts added afterwards dispatched as soon as they arrive.","example":false},"declinedStopRatio":{"type":"number","minimum":0.35,"maximum":0.7,"description":"The campaign is stopped automatically once this share of its recent calls were declined as soon as they were placed, which usually means the carrier is blocking the number. Recent calls are its last 40 ended in the last 10 minutes, counted once at least 30 have ended. Between 0.35 (14 of 40 calls) and 0.7 (28 of 40 calls); defaults to 0.5 (20 of 40 calls). An advanced setting: an account it is not enabled on gets a 403 and keeps the default. Contact your sales representative to enable it.","example":0.6}},"required":["name","agentId","phoneId"]},"PatchCampaignBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"example":"Q2 Outreach"},"agentId":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"phoneId":{"type":"string","format":"uuid","description":"The phone the campaign dials from. It must be allowed to place outbound calls (`isOutboundAllowed` in GET /phones).","example":"0d3a7e6b-2b8e-4c5b-9c4e-5f4b9d2a1c8e"},"isActive":{"type":"boolean","example":true},"declinedStopRatio":{"type":"number","nullable":true,"minimum":0.35,"maximum":0.7,"description":"The campaign is stopped automatically once this share of its recent calls were declined as soon as they were placed, which usually means the carrier is blocking the number. Recent calls are its last 40 ended in the last 10 minutes, counted once at least 30 have ended. Between 0.35 (14 of 40 calls) and 0.7 (28 of 40 calls); defaults to 0.5 (20 of 40 calls). An advanced setting: an account it is not enabled on gets a 403 and keeps the default. Contact your sales representative to enable it. Set to null to restore the default.","example":0.6}}},"CampaignMetrics":{"type":"object","properties":{"totalCalls":{"type":"integer","example":1200},"reached":{"type":"integer","example":840},"callsCompleted":{"type":"integer","example":760}},"required":["totalCalls","reached","callsCompleted"]},"CampaignDetails":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"name":{"type":"string","example":"Q2 Outreach"},"status":{"type":"string","enum":["active","inactive"],"example":"active"},"declinedStopRatio":{"type":"number","description":"The campaign is stopped automatically once this share of its recent calls were declined as soon as they were placed, which usually means the carrier is blocking the number. Recent calls are its last 40 ended in the last 10 minutes, counted once at least 30 have ended. Between 0.35 (14 of 40 calls) and 0.7 (28 of 40 calls); defaults to 0.5 (20 of 40 calls). An advanced setting: an account it is not enabled on gets a 403 and keeps the default. Contact your sales representative to enable it.","example":0.5},"metrics":{"$ref":"#/components/schemas/CampaignMetrics"}},"required":["id","name","status","declinedStopRatio","metrics"]},"CampaignContact":{"type":"object","properties":{"salutation":{"type":"string","enum":["mr","mrs","ms","miss"],"example":"mr"},"firstName":{"type":"string","example":"John"},"lastName":{"type":"string","example":"Doe"},"email":{"type":"string","format":"email","example":"john@example.com"},"phoneNumber":{"type":"string","description":"Stored in E.164, so the queued call can later be matched by number.","example":"+33612345678"},"information":{"type":"string","example":"VIP customer"},"metadata":{"type":"object","additionalProperties":{"nullable":true},"description":"Free-form JSON metadata (advanced mode). When set, replaces the entire metadata blob — takes precedence over `information`. Injected into the agent prompt via the `contact.metadata` variable and included in the call-ended webhook payload.","example":{"tier":"gold","priority":1,"tags":["vip","renewal"]}},"optedOut":{"type":"boolean","example":false}},"required":["phoneNumber"]},"AddCampaignContactsBody":{"type":"object","properties":{"contacts":{"type":"array","items":{"$ref":"#/components/schemas/CampaignContact"},"minItems":1,"maxItems":1000}},"required":["contacts"]},"DeleteCampaignCallsResponse":{"type":"object","properties":{"deleted":{"type":"integer","example":8213}},"required":["deleted"]},"DeleteCampaignCallsBody":{"type":"object","properties":{"phoneNumbers":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10000,"description":"Restrict the deletion to the queued calls placed to these numbers. Omit the body entirely to delete every queued call of the campaign. Numbers are normalised to E.164, so the formatting sent here does not matter, and a number with nothing queued is simply skipped.","example":["+33612345678","+33612345679"]}}},"RetryCampaignResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"name":{"type":"string","example":"Q2 Outreach | retry"},"callsQueued":{"type":"integer","example":142}},"required":["id","name","callsQueued"]},"RetryCampaignBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"example":"Q2 Outreach | retry"}}},"Webhook":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"name":{"type":"string","example":"CRM sync"},"endpointUrl":{"type":"string","format":"uri","example":"https://example.com/hooks/callshift"},"entityId":{"type":"string","nullable":true,"format":"uuid","description":"The webhook's entity, or `null` when the webhook is shared.","example":null},"createdAt":{"type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"type":"string","nullable":true,"example":"2026-01-01T00:00:00.000Z"}},"required":["id","name","endpointUrl","entityId","createdAt","updatedAt"]},"WebhookListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}},"required":["data"]},"CreateWebhookRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"example":"CRM sync"},"endpointUrl":{"type":"string","format":"uri","example":"https://example.com/hooks/callshift"},"entityId":{"type":"string","nullable":true,"format":"uuid","description":"The entity the item belongs to, or `null` to make it shared. Send this or `entityExternalId`, not both.","example":"550e8400-e29b-41d4-a716-446655440000"},"entityExternalId":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"description":"Your external id of the entity the item belongs to, or `null` to make it shared. Send this or `entityId`, not both.","example":"club-42"}},"required":["name","endpointUrl"]},"UpdateWebhookRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"example":"CRM sync"},"endpointUrl":{"type":"string","format":"uri","example":"https://example.com/hooks/callshift"},"entityId":{"type":"string","nullable":true,"format":"uuid","description":"The entity the item belongs to, or `null` to make it shared. Send this or `entityExternalId`, not both.","example":"550e8400-e29b-41d4-a716-446655440000"},"entityExternalId":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"description":"Your external id of the entity the item belongs to, or `null` to make it shared. Send this or `entityId`, not both.","example":"club-42"}}},"ToolParameterSchema":{"type":"object","description":"A JSON Schema property (OpenAI function calling subset).","properties":{"type":{"type":"string","enum":["string","number","integer","boolean","array","object"]},"description":{"type":"string"},"enum":{"type":"array","items":{"type":"string"},"minItems":1},"format":{"type":"string"},"pattern":{"type":"string"},"title":{"type":"string"},"default":{"oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]},"minimum":{"type":"number"},"maximum":{"type":"number"},"items":{"$ref":"#/components/schemas/ToolParameterSchema"},"properties":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ToolParameterSchema"}},"required":{"type":"array","items":{"type":"string"}}},"required":["type"],"additionalProperties":false},"ToolParameters":{"type":"object","properties":{"type":{"type":"string","enum":["object"]},"properties":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ToolParameterSchema"}},"required":{"type":"array","items":{"type":"string"}}},"required":["type","properties"],"additionalProperties":false,"description":"JSON Schema of the arguments the agent collects before calling the tool, in the OpenAI function calling format. The root must be an object.","example":{"type":"object","properties":{"orderNumber":{"type":"string","description":"The order number, e.g. ORD-1234"}},"required":["orderNumber"]}},"ToolMessages":{"type":"object","properties":{"requestStart":{"type":"object","properties":{"content":{"type":"string","maxLength":1000,"description":"What the agent says, in the agent's language."},"blocking":{"type":"boolean","description":"Wait for the message to be spoken before calling the tool."}},"description":"Spoken when the tool call starts."},"requestComplete":{"type":"object","properties":{"content":{"type":"string","maxLength":1000,"description":"What the agent says, in the agent's language."},"role":{"type":"string","enum":["assistant","system"]}},"description":"Spoken when the tool call succeeds."},"requestFailed":{"type":"object","properties":{"content":{"type":"string","maxLength":1000,"description":"What the agent says, in the agent's language."}},"description":"Spoken when the tool call fails."},"requestDelayed":{"type":"object","properties":{"content":{"type":"string","maxLength":1000,"description":"What the agent says, in the agent's language."},"timingMilliseconds":{"type":"integer","minimum":1000,"maximum":30000}},"description":"Spoken when the tool has not answered after `timingMilliseconds`."}},"description":"Optional sentences the agent speaks around the tool call. An omitted `requestStart` or `requestDelayed` gets a default; one sent without `content` is silent.","example":{"requestStart":{"content":"Let me check that for you.","blocking":true},"requestFailed":{"content":"I could not check that right now."}}},"CustomToolConfig":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"HTTPS endpoint that receives a POST with the collected arguments.","example":"https://example.com/api/orders/lookup"},"apiTimeout":{"type":"integer","minimum":1,"maximum":15,"description":"Seconds to wait for the endpoint (default 10).","example":10},"parameters":{"$ref":"#/components/schemas/ToolParameters"},"async":{"type":"boolean","description":"When true the agent does not wait for the result and continues the conversation.","example":false},"messages":{"$ref":"#/components/schemas/ToolMessages"}},"required":["url"]},"CustomTool":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"type":{"type":"string","enum":["custom"]},"name":{"type":"string","minLength":1,"maxLength":40,"description":"Name shown in the dashboard. Its camelCase form is the function name the agent calls, so keep it unique per tenant. Agent prompts reference a tool by that function name: renaming a tool detaches it from the agents that use it until their `<tool-node functionname>` is updated.","example":"Check order"},"description":{"type":"string","nullable":true,"maxLength":1000,"description":"Tells the agent what the tool does and when to use it.","example":"Looks up an order by its number and returns its status."},"config":{"$ref":"#/components/schemas/CustomToolConfig"},"createdAt":{"type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"type":"string","nullable":true,"example":"2026-01-01T00:00:00.000Z"}},"required":["id","type","name","description","config","createdAt","updatedAt"]},"QueryToolConfig":{"type":"object","properties":{"urls":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri","example":"https://example.com/faq"}},"required":["url"]},"minItems":1,"description":"Web pages the agent may search."},"async":{"type":"boolean","description":"When true the agent does not wait for the result and continues the conversation.","example":false},"messages":{"$ref":"#/components/schemas/ToolMessages"}},"required":["urls"]},"QueryTool":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"type":{"type":"string","enum":["query"]},"name":{"type":"string","minLength":1,"maxLength":40,"description":"Name shown in the dashboard. Its camelCase form is the function name the agent calls, so keep it unique per tenant. Agent prompts reference a tool by that function name: renaming a tool detaches it from the agents that use it until their `<tool-node functionname>` is updated.","example":"Check order"},"description":{"type":"string","nullable":true,"maxLength":1000,"description":"Tells the agent what the tool does and when to use it.","example":"Looks up an order by its number and returns its status."},"config":{"$ref":"#/components/schemas/QueryToolConfig"},"createdAt":{"type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"type":"string","nullable":true,"example":"2026-01-01T00:00:00.000Z"}},"required":["id","type","name","description","config","createdAt","updatedAt"]},"SendSmsToolConfig":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":1600,"description":"SMS text.","example":"Thanks for calling! Your appointment is confirmed."},"to":{"type":"string","pattern":"^\\+[1-9]\\d{6,14}$","description":"Recipient in E.164 format. Omit to send the SMS to the caller.","example":"+33612345678"},"async":{"type":"boolean","description":"When true the agent does not wait for the result and continues the conversation.","example":false},"messages":{"$ref":"#/components/schemas/ToolMessages"}},"required":["body"]},"SendSmsTool":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"type":{"type":"string","enum":["sendSms"]},"name":{"type":"string","minLength":1,"maxLength":40,"description":"Name shown in the dashboard. Its camelCase form is the function name the agent calls, so keep it unique per tenant. Agent prompts reference a tool by that function name: renaming a tool detaches it from the agents that use it until their `<tool-node functionname>` is updated.","example":"Check order"},"description":{"type":"string","nullable":true,"maxLength":1000,"description":"Tells the agent what the tool does and when to use it.","example":"Looks up an order by its number and returns its status."},"config":{"$ref":"#/components/schemas/SendSmsToolConfig"},"createdAt":{"type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"type":"string","nullable":true,"example":"2026-01-01T00:00:00.000Z"}},"required":["id","type","name","description","config","createdAt","updatedAt"]},"SendEmailToolConfig":{"type":"object","properties":{"subject":{"type":"string","minLength":1,"maxLength":998,"description":"Email subject. `<email-placeholder-node variablename=\"…\">…</email-placeholder-node>` tokens are replaced at call time; variables: contact.email, contact.firstName, contact.lastName, caller.phoneNumber, notes.","example":"Your order <email-placeholder-node variablename=\"notes\">notes</email-placeholder-node>"},"body":{"type":"string","minLength":1,"description":"HTML body. Accepts the same variable tokens as the subject.","example":"<p>Summary of the call: <email-placeholder-node variablename=\"notes\">notes</email-placeholder-node></p>"},"to":{"type":"array","items":{"type":"string","example":"billing@example.com"},"minItems":1,"description":"Recipients: email addresses, or `<email-placeholder-node variablename=\"contact.email\">contact email</email-placeholder-node>` to email the contact on the call.","example":["billing@example.com"]},"notesInstructions":{"type":"string","description":"What the agent should put in the `notes` argument it passes to the tool.","example":"Summarise the caller's request in two sentences."},"async":{"type":"boolean","description":"When true the agent does not wait for the result and continues the conversation.","example":false},"messages":{"$ref":"#/components/schemas/ToolMessages"}},"required":["subject","body","to"]},"SendEmailTool":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"type":{"type":"string","enum":["sendEmail"]},"name":{"type":"string","minLength":1,"maxLength":40,"description":"Name shown in the dashboard. Its camelCase form is the function name the agent calls, so keep it unique per tenant. Agent prompts reference a tool by that function name: renaming a tool detaches it from the agents that use it until their `<tool-node functionname>` is updated.","example":"Check order"},"description":{"type":"string","nullable":true,"maxLength":1000,"description":"Tells the agent what the tool does and when to use it.","example":"Looks up an order by its number and returns its status."},"config":{"$ref":"#/components/schemas/SendEmailToolConfig"},"createdAt":{"type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"type":"string","nullable":true,"example":"2026-01-01T00:00:00.000Z"}},"required":["id","type","name","description","config","createdAt","updatedAt"]},"Tool":{"oneOf":[{"$ref":"#/components/schemas/CustomTool"},{"$ref":"#/components/schemas/QueryTool"},{"$ref":"#/components/schemas/SendSmsTool"},{"$ref":"#/components/schemas/SendEmailTool"}],"discriminator":{"propertyName":"type","mapping":{"custom":"#/components/schemas/CustomTool","query":"#/components/schemas/QueryTool","sendSms":"#/components/schemas/SendSmsTool","sendEmail":"#/components/schemas/SendEmailTool"}},"description":"A tool is a function the agent can call during a conversation. Four types are available:\n\n- `custom` — POST the arguments the agent collected to your own HTTPS endpoint (OpenAI function calling: `config.parameters` is the JSON Schema of the arguments).\n- `query` — let the agent search the content of one or more web pages to answer a question.\n- `sendSms` — send a templated SMS during the call (to a fixed number, or to the caller when `config.to` is omitted).\n- `sendEmail` — send a templated email during the call; the agent's notes are passed as the `notes` argument.\n\nTransferring the call to a phone number, handing over to another agent and ending the call are **not tools**: they are nodes of the agent diagram (`forwardCall`, `forwardAgent`, `endCall` in `GET /v1/agents/{agentId}`). MCP servers, code execution and transfer cancellation are not available.\n\nA tool is attached to an agent by referencing it in a `knowHow` node prompt of the agent diagram (see `AgentDiagram`)."},"ToolListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Tool"}}},"required":["data"]},"CreateCustomToolBody":{"type":"object","properties":{"type":{"type":"string","enum":["custom"]},"name":{"type":"string","minLength":1,"maxLength":40,"description":"Name shown in the dashboard. Its camelCase form is the function name the agent calls, so keep it unique per tenant. Agent prompts reference a tool by that function name: renaming a tool detaches it from the agents that use it until their `<tool-node functionname>` is updated.","example":"Check order"},"description":{"type":"string","maxLength":1000,"description":"Tells the agent what the tool does and when to use it.","example":"Looks up an order by its number and returns its status."},"config":{"$ref":"#/components/schemas/CustomToolConfig"}},"required":["type","name","config"],"example":{"type":"custom","name":"Check order","description":"Looks up an order by its number and returns its status.","config":{"url":"https://example.com/api/orders/lookup","apiTimeout":10,"parameters":{"type":"object","properties":{"orderNumber":{"type":"string","description":"The order number, e.g. ORD-1234"}},"required":["orderNumber"]},"messages":{"requestStart":{"content":"Let me look that up."}}}}},"CreateQueryToolBody":{"type":"object","properties":{"type":{"type":"string","enum":["query"]},"name":{"type":"string","minLength":1,"maxLength":40,"description":"Name shown in the dashboard. Its camelCase form is the function name the agent calls, so keep it unique per tenant. Agent prompts reference a tool by that function name: renaming a tool detaches it from the agents that use it until their `<tool-node functionname>` is updated.","example":"Check order"},"description":{"type":"string","maxLength":1000,"description":"Tells the agent what the tool does and when to use it.","example":"Looks up an order by its number and returns its status."},"config":{"$ref":"#/components/schemas/QueryToolConfig"}},"required":["type","name","config"],"example":{"type":"query","name":"Search FAQ","description":"Answers questions about opening hours and pricing.","config":{"urls":[{"url":"https://example.com/faq"},{"url":"https://example.com/pricing"}]}}},"CreateSendSmsToolBody":{"type":"object","properties":{"type":{"type":"string","enum":["sendSms"]},"name":{"type":"string","minLength":1,"maxLength":40,"description":"Name shown in the dashboard. Its camelCase form is the function name the agent calls, so keep it unique per tenant. Agent prompts reference a tool by that function name: renaming a tool detaches it from the agents that use it until their `<tool-node functionname>` is updated.","example":"Check order"},"description":{"type":"string","maxLength":1000,"description":"Tells the agent what the tool does and when to use it.","example":"Looks up an order by its number and returns its status."},"config":{"$ref":"#/components/schemas/SendSmsToolConfig"}},"required":["type","name","config"],"example":{"type":"sendSms","name":"Send confirmation","description":"Sends the caller a confirmation SMS once booked.","config":{"body":"Thanks for calling! Your appointment is confirmed.","async":true}}},"CreateSendEmailToolBody":{"type":"object","properties":{"type":{"type":"string","enum":["sendEmail"]},"name":{"type":"string","minLength":1,"maxLength":40,"description":"Name shown in the dashboard. Its camelCase form is the function name the agent calls, so keep it unique per tenant. Agent prompts reference a tool by that function name: renaming a tool detaches it from the agents that use it until their `<tool-node functionname>` is updated.","example":"Check order"},"description":{"type":"string","maxLength":1000,"description":"Tells the agent what the tool does and when to use it.","example":"Looks up an order by its number and returns its status."},"config":{"$ref":"#/components/schemas/SendEmailToolConfig"}},"required":["type","name","config"],"example":{"type":"sendEmail","name":"Email call summary","description":"Emails the sales team a summary of the call.","config":{"subject":"New lead from a call","body":"<p>Notes: <email-placeholder-node variablename=\"notes\">notes</email-placeholder-node></p>","to":["sales@example.com"],"notesInstructions":"Summarise the caller's need and the best time to call back."}}},"CreateToolBody":{"oneOf":[{"$ref":"#/components/schemas/CreateCustomToolBody"},{"$ref":"#/components/schemas/CreateQueryToolBody"},{"$ref":"#/components/schemas/CreateSendSmsToolBody"},{"$ref":"#/components/schemas/CreateSendEmailToolBody"}],"discriminator":{"propertyName":"type","mapping":{"custom":"#/components/schemas/CreateCustomToolBody","query":"#/components/schemas/CreateQueryToolBody","sendSms":"#/components/schemas/CreateSendSmsToolBody","sendEmail":"#/components/schemas/CreateSendEmailToolBody"}}},"PatchToolBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":40,"description":"Name shown in the dashboard. Its camelCase form is the function name the agent calls, so keep it unique per tenant. Agent prompts reference a tool by that function name: renaming a tool detaches it from the agents that use it until their `<tool-node functionname>` is updated.","example":"Check order"},"description":{"type":"string","nullable":true,"maxLength":1000,"description":"Tells the agent what the tool does and when to use it.","example":"Looks up an order by its number and returns its status."},"config":{"type":"object","additionalProperties":{"nullable":true},"description":"Top-level fields to change in the tool's config, each replacing the stored value as a whole (`null` clears it). They are merged over the stored config and the result is validated against the schema of the tool's type (`CustomToolConfig`, `QueryToolConfig`, `SendSmsToolConfig` or `SendEmailToolConfig`). The type itself cannot change: delete the tool and create a new one.","example":{"url":"https://example.com/api/v2/orders/lookup"}}}},"ToolInUseResponse":{"type":"object","properties":{"error":{"type":"string","enum":["Tool is attached to agents"]},"agents":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":["id","name"]}}},"required":["error","agents"],"example":{"error":"Tool is attached to agents","agents":[{"id":"550e8400-e29b-41d4-a716-446655440000","name":"Alice"}]}},"EntityUsage":{"type":"object","properties":{"agents":{"type":"integer","example":3},"phoneNumbers":{"type":"integer","example":2},"webhooks":{"type":"integer","example":1}},"required":["agents","phoneNumbers","webhooks"],"description":"What the entity holds. Deleted agents and numbers are not counted."},"Entity":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"name":{"type":"string","minLength":1,"maxLength":255,"example":"Lyon Part-Dieu"},"externalId":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"description":"Your own identifier for the entity, unique within the account.","example":"club-42"},"createdAt":{"type":"string","example":"2026-01-01T00:00:00.000Z"},"updatedAt":{"type":"string","example":"2026-01-01T00:00:00.000Z"}},"required":["id","name","externalId","createdAt","updatedAt"]},"EntityListItem":{"allOf":[{"$ref":"#/components/schemas/Entity"},{"type":"object","properties":{"usage":{"$ref":"#/components/schemas/EntityUsage"}},"required":["usage"]}]},"EntityListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EntityListItem"}},"pageCount":{"type":"number","example":3}},"required":["data","pageCount"]},"EntityConflictResponse":{"type":"object","properties":{"error":{"type":"string"},"existingEntityId":{"type":"string","format":"uuid","description":"Set when the external id is taken: the entity that holds it, so a retried provisioning can adopt it.","example":"550e8400-e29b-41d4-a716-446655440000"}},"required":["error"]},"CreateEntityRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"example":"Lyon Part-Dieu"},"externalId":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"description":"Your own identifier for the entity, unique within the account.","example":"club-42"}},"required":["name"]},"UpdateEntityRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"example":"Lyon Part-Dieu"},"externalId":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"description":"`null` removes the external id.","example":"club-42"}}},"EntityInUseResponse":{"type":"object","properties":{"error":{"type":"string"},"usage":{"$ref":"#/components/schemas/EntityUsage"}},"required":["error","usage"]},"MoveEntityItemsResponse":{"type":"object","properties":{"moved":{"$ref":"#/components/schemas/EntityUsage"}},"required":["moved"]},"MoveEntityItemsRequest":{"type":"object","properties":{"entityId":{"type":"string","nullable":true,"format":"uuid","description":"The entity to move the items to, or `null` to make them shared. Send this or `entityExternalId`.","example":"550e8400-e29b-41d4-a716-446655440000"},"entityExternalId":{"type":"string","nullable":true,"minLength":1,"maxLength":255,"description":"Your external id of the entity to move the items to, or `null` to make them shared. Send this or `entityId`.","example":"club-42"}}},"Invoice":{"type":"object","properties":{"id":{"type":"string","example":"in_1QaBcDeFgHiJkLmN"},"type":{"type":"string","enum":["subscription","credit_purchase","auto_recharge","other"],"description":"What the invoice is for: the plan (`subscription`), credits bought from the billing page (`credit_purchase`), an automatic recharge of the wallet (`auto_recharge`), or anything else Callshift invoiced (`other`).","example":"subscription"},"number":{"type":"string","nullable":true,"description":"The number printed on the invoice. Null while the invoice is a draft.","example":"3A66EC3B-0253"},"createdAt":{"type":"string","format":"date-time","example":"2026-03-02T09:00:00.000Z"},"paidAt":{"type":"string","nullable":true,"format":"date-time","description":"When the invoice was paid. Null until it is.","example":"2026-03-02T09:00:05.000Z"},"totalCents":{"type":"integer","description":"Total of the invoice, tax included, in euro cents: the figure printed on it.","example":6000},"amountPaidCents":{"type":"integer","description":"What has been paid on the invoice, in euro cents.","example":6000},"status":{"type":"string","enum":["draft","open","paid","uncollectible","void"],"description":"`draft` (not issued yet), `open` (awaiting payment), `paid`, `uncollectible` (payment abandoned), or `void` (cancelled, nothing is owed — e.g. a declined automatic recharge).","example":"paid"},"description":{"type":"string","nullable":true,"example":null},"invoiceUrl":{"type":"string","nullable":true,"description":"Hosted page of the invoice, with its PDF.","example":"https://invoice.stripe.com/i/acct_123/test_456"}},"required":["id","type","number","createdAt","paidAt","totalCents","amountPaidCents","status","description","invoiceUrl"]},"ListInvoicesResponse":{"type":"object","properties":{"tenantName":{"type":"string","nullable":true,"description":"Name of the tenant the API key belongs to, as shown in the dashboard.","example":"Lyon Part-Dieu"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Invoice"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass it as `cursor` for the next, older page. Null on the last page.","example":"in_1QaBcDeFgHiJkLmN"}},"required":["tenantName","data","nextCursor"]}},"parameters":{}},"paths":{"/health":{"get":{"tags":["Health"],"summary":"Health check","description":"Returns the health status of the API including database connectivity.","responses":{"200":{"description":"API is healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"503":{"description":"API is unhealthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/v1/agents":{"get":{"tags":["Agents"],"summary":"List agents","description":"List the agents of the authenticated tenant with pagination, optionally only those of one entity.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"default":1,"example":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"example":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Return only the items of this entity. Send this or `entityExternalId`, not both.","example":"550e8400-e29b-41d4-a716-446655440000"},"required":false,"name":"entityId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":255,"description":"Return only the items of the entity with this external id. Send this or `entityId`, not both.","example":"club-42"},"required":false,"name":"entityExternalId","in":"query"}],"responses":{"200":{"description":"Agents listed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentListResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Agents"],"summary":"Create a new agent","description":"Create a new agent from scratch for the authenticated tenant.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAgentBody"}}}},"responses":{"201":{"description":"Agent created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAgentResponse"}}}},"400":{"description":"Invalid request payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"The diagram references a tool that does not exist, or names a looked-up forwardCall node like another tool","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/agents/{agentId}":{"get":{"tags":["Agents"],"summary":"Get agent details","description":"Retrieve detailed information about a specific agent by ID.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"agentId","in":"path"}],"responses":{"200":{"description":"Agent details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Agent not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["Agents"],"summary":"Partially update an agent's settings","description":"Apply updates to the agent's fields, such as name, language, model, temperature, summary/evaluation prompts, information to collect, and diagram.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"agentId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchAgentBody"}}}},"responses":{"200":{"description":"Agent updated successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchAgentResponse"}}}},"400":{"description":"Invalid request parameters or payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Agent or entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The change would link items of two different entities. The error names them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"The diagram references a tool that does not exist, or names a looked-up forwardCall node like another tool","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Agents"],"summary":"Delete an agent","description":"Soft-delete an agent by ID and release its assigned phone numbers.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"agentId","in":"path"}],"responses":{"204":{"description":"Agent deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Agent not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/agents/{agentId}/duplicate":{"post":{"tags":["Agents"],"summary":"Duplicate agent","description":"Duplicate an existing agent for the authenticated tenant. The copy stays in the source agent's entity unless the body names another one, or `null` for shared. A copy into another entity is refused while the source sends its after-call data to a webhook of its entity.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"agentId","in":"path"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DuplicateAgentBody"}}}},"responses":{"201":{"description":"Agent duplicated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DuplicateAgentResponse"}}}},"400":{"description":"Invalid request payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Agent or entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The change would link items of two different entities. The error names them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/agents/{agentId}/webhook":{"put":{"tags":["Agents"],"summary":"Assign an after-call webhook to an agent","description":"Enable the agent's after-call automation webhook and point it at one of the tenant's webhooks, or disable it. A webhook of another entity than the agent's is refused. Other notification settings (SMS, Slack) are left untouched.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"agentId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetAgentWebhookRequest"}}}},"responses":{"200":{"description":"Agent webhook settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetAgentWebhookResponse"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Agent or webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The change would link items of two different entities. The error names them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/contact/{contactId}":{"patch":{"tags":["Contacts"],"summary":"Update a contact","description":"Update contact properties by contact ID.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"contactId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchContactBody"}}}},"responses":{"200":{"description":"Contact updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Invalid request parameters or body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Contact not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/contact-opted-out":{"post":{"tags":["Contacts"],"summary":"Mark contact as opted out","description":"Mark a contact as opted out by phone number.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactOptedOutBody"}}}},"responses":{"200":{"description":"Contact marked as opted out","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Contact not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/calls":{"get":{"tags":["Calls"],"summary":"List calls","description":"List all calls for the authenticated tenant with pagination, most recently started first. Filter by `campaignId` to list the calls of a given campaign, by `customerPhoneNumber` to list the calls exchanged with a given customer, or by outcome (`endedReason`, `minDuration`, `isReached`, `isSignificant`, `isSuccessful`, `isSilent`) to classify results.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"default":1,"example":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"example":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":false,"name":"agentId","in":"query"},{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":false,"name":"campaignId","in":"query"},{"schema":{"type":"string","description":"Customer phone number in international format. Returns the calls placed to (outbound) or received from (inbound) that number.","example":"+33612345678"},"required":false,"name":"customerPhoneNumber","in":"query"},{"schema":{"type":"string","enum":["COMPLETED","ERROR","FORWARDED","IN_PROGRESS","READY","REJECTED","SCHEDULED"],"example":"COMPLETED"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","enum":["inbound","outbound","webcall"],"example":"inbound"},"required":false,"name":"type","in":"query"},{"schema":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"required":false,"name":"from","in":"query"},{"schema":{"type":"string","format":"date-time","example":"2024-12-31T23:59:59Z"},"required":false,"name":"to","in":"query"},{"schema":{"type":"string","description":"Exact match on `endedReason`.","example":"voicemail"},"required":false,"name":"endedReason","in":"query"},{"schema":{"type":"integer","nullable":true,"minimum":0,"description":"Only calls with `billingSeconds` greater than or equal to this value.","example":30},"required":false,"name":"minDuration","in":"query"},{"schema":{"type":"string","enum":["true","false"],"example":"true"},"required":false,"name":"isReached","in":"query"},{"schema":{"type":"string","enum":["true","false"],"example":"true"},"required":false,"name":"isSignificant","in":"query"},{"schema":{"type":"string","enum":["true","false"],"example":"true"},"required":false,"name":"isSuccessful","in":"query"},{"schema":{"type":"string","enum":["true","false"],"example":"true"},"required":false,"name":"isSilent","in":"query"}],"responses":{"200":{"description":"Calls listed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallListResponse"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/calls/{callId}":{"get":{"tags":["Calls"],"summary":"Get call details","description":"Retrieve detailed information about a specific call by ID.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"callId","in":"path"}],"responses":{"200":{"description":"Call details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Call not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/phones":{"get":{"tags":["Phones"],"summary":"List phone numbers","description":"List every phone number of the authenticated tenant, whatever the way it reached the account: a connected SIP trunk, or a number imported from a vendor such as Twilio or Telnyx. Use GET /phones/sip to list only the SIP ones. Filter on an entity to get only its numbers.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"default":1,"example":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"example":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Return only the items of this entity. Send this or `entityExternalId`, not both.","example":"550e8400-e29b-41d4-a716-446655440000"},"required":false,"name":"entityId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":255,"description":"Return only the items of the entity with this external id. Send this or `entityId`, not both.","example":"club-42"},"required":false,"name":"entityExternalId","in":"query"}],"responses":{"200":{"description":"Phones listed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListPhonesResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/phones/{phoneId}":{"patch":{"tags":["Phones"],"security":[{"bearerAuth":[]}],"summary":"Update a phone number","description":"Set (or clear, with null) the agent that answers inbound calls on this number, and the entity it belongs to, whatever its provider: SIP, Twilio or Telnyx. Use GET /phones to find the phone id.","parameters":[{"schema":{"type":"string","format":"uuid","example":"0d3a7e6b-2b8e-4c5b-9c4e-5f4b9d2a1c8e"},"required":true,"name":"phoneId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePhoneBody"}}}},"responses":{"200":{"description":"Phone updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Invalid payload, or agent not found in this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Phone or entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The change would link items of two different entities. The error names them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/phones/sip/{phoneId}":{"patch":{"tags":["Phones"],"security":[{"bearerAuth":[]}],"summary":"Update a SIP phone number","description":"Same as `PATCH /v1/phones/{phoneId}`, which works for every provider. Calls-per-second is a property of the SIP trunk, see `GET /v1/trunks`.","deprecated":true,"parameters":[{"schema":{"type":"string","format":"uuid","example":"0d3a7e6b-2b8e-4c5b-9c4e-5f4b9d2a1c8e"},"required":true,"name":"phoneId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePhoneBody"}}}},"responses":{"200":{"description":"Phone updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Invalid payload, or agent not found in this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Phone or entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The change would link items of two different entities. The error names them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Phones"],"summary":"Delete a SIP phone number","description":"Delete a SIP phone number and detach it from its outbound SIP trunk.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"0d3a7e6b-2b8e-4c5b-9c4e-5f4b9d2a1c8e"},"required":true,"name":"phoneId","in":"path"}],"responses":{"204":{"description":"SIP phone deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Phone not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/phones/sip":{"get":{"tags":["Phones"],"summary":"List SIP phone numbers","description":"List all SIP phone numbers for the authenticated tenant, optionally only those of one entity.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"default":1,"example":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"example":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid","description":"Return only the items of this entity. Send this or `entityExternalId`, not both.","example":"550e8400-e29b-41d4-a716-446655440000"},"required":false,"name":"entityId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":255,"description":"Return only the items of the entity with this external id. Send this or `entityId`, not both.","example":"club-42"},"required":false,"name":"entityExternalId","in":"query"}],"responses":{"200":{"description":"SIP phones listed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSipPhonesResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Phones"],"summary":"Create a SIP phone number","description":"Connect a SIP trunk and register the phone number for the authenticated tenant.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectSipTrunkBody"}}}},"responses":{"201":{"description":"SIP phone created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSipPhoneResponse"}}}},"400":{"description":"Invalid agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"SIP trunk or entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Phone number already exists, or the agent belongs to another entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/trunks":{"get":{"tags":["Trunks"],"summary":"List SIP trunks","description":"Lists the tenant's SIP trunks. Calls per second is a trunk-level limit shared by every number on the trunk. Filtered on an entity, it returns the trunks carrying at least one of that entity's numbers.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Return only the items of this entity. Send this or `entityExternalId`, not both.","example":"550e8400-e29b-41d4-a716-446655440000"},"required":false,"name":"entityId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":255,"description":"Return only the items of the entity with this external id. Send this or `entityId`, not both.","example":"club-42"},"required":false,"name":"entityExternalId","in":"query"}],"responses":{"200":{"description":"SIP trunks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTrunksResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/campaigns":{"get":{"tags":["Campaigns"],"summary":"List campaigns","description":"List all campaigns for the authenticated tenant with pagination and optional filtering.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"default":1,"example":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"example":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","example":"Q2 Outreach"},"required":false,"name":"name","in":"query"},{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":false,"name":"agentId","in":"query"}],"responses":{"200":{"description":"Campaigns listed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Campaigns"],"summary":"Create a campaign","description":"Create a new outbound campaign for the authenticated tenant. The campaign is inactive unless `isActive` is set to true.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCampaignBody"}}}},"responses":{"201":{"description":"Campaign created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCampaignResponse"}}}},"400":{"description":"Invalid agent or phone, or a phone not allowed to place outbound calls","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"declinedStopRatio is an advanced setting that is not enabled on the account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The change would link items of two different entities. The error names them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/campaigns/{campaignId}":{"patch":{"tags":["Campaigns"],"summary":"Update a campaign","description":"Partially update a campaign: rename it, change its agent or phone, start/stop it by setting the active state, or change the declined-call ratio it stops at.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"campaignId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchCampaignBody"}}}},"responses":{"200":{"description":"Campaign updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Invalid agent or phone, or a phone not allowed to place outbound calls","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"declinedStopRatio is an advanced setting that is not enabled on the account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Campaign not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The change would link items of two different entities. The error names them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"tags":["Campaigns"],"summary":"Get campaign details","description":"Retrieve a campaign by ID along with its call metrics (total calls, reached, and completed).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"campaignId","in":"path"}],"responses":{"200":{"description":"Campaign details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Campaign not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Campaigns"],"summary":"Delete a campaign","description":"Soft-delete a campaign by ID.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"campaignId","in":"path"}],"responses":{"204":{"description":"Campaign deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Campaign not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/campaigns/{campaignId}/contacts":{"post":{"tags":["Campaigns"],"summary":"Add contacts to a campaign","description":"Add contacts to a campaign. Contacts are created or updated in the CRM (matched by phone number) and a call is queued for each one. If the campaign is active, the new calls are dispatched immediately.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"campaignId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddCampaignContactsBody"}}}},"responses":{"200":{"description":"Contacts added to the campaign successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Invalid payload. `error.issues[].path` locates the offending contact, e.g. [\"contacts\", 0, \"email\"].","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Campaign not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/campaigns/{campaignId}/calls":{"delete":{"tags":["Campaigns"],"summary":"Delete a campaign's queued calls","description":"Delete the calls queued for this campaign — those waiting to be dialed. `status` is required and must be `READY`; calls already dispatched, in progress, or completed are never affected, including on a campaign that is currently running. Send a body with `phoneNumbers` to delete only the calls queued for those numbers, or send no body at all to delete every queued call of the campaign. Nothing queued for the requested numbers returns `{ \"deleted\": 0 }`; a `404` means the campaign itself was not found. Campaign statistics are computed from the remaining calls, so deleting queued calls lowers the campaign's total and moves its completion ratio toward 100%. This is irreversible: re-add the contacts through POST /v1/campaigns/{campaignId}/contacts to dial them again.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"campaignId","in":"path"},{"schema":{"type":"string","enum":["READY"],"description":"Must be READY. Required so that a request can never mean 'delete every call of this campaign'.","example":"READY"},"required":true,"name":"status","in":"query"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteCampaignCallsBody"}}}},"responses":{"200":{"description":"Queued calls deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteCampaignCallsResponse"}}}},"400":{"description":"`status` is missing or is not READY, or `phoneNumbers` holds an invalid number","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Campaign not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/campaigns/{campaignId}/retry":{"post":{"tags":["Campaigns"],"summary":"Create a retry campaign","description":"Create a new campaign that re-dials the contacts the source campaign did not reach and who never called back. The new campaign reuses the source campaign's agent, phone and `declinedStopRatio`, and is named after it with a ` | retry` suffix unless a name is given. It is created inactive: start it with PATCH /campaigns/{campaignId} once you are ready to dial.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"campaignId","in":"path"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryCampaignBody"}}}},"responses":{"201":{"description":"Retry campaign created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryCampaignResponse"}}}},"400":{"description":"The campaign has no calls to retry, its agent or phone no longer exists, or its phone is not allowed to place outbound calls","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Campaign not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The change would link items of two different entities. The error names them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhooks","description":"List all after-call automation webhooks for the authenticated tenant. Filter on an entity to get only its webhooks.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Return only the items of this entity. Send this or `entityExternalId`, not both.","example":"550e8400-e29b-41d4-a716-446655440000"},"required":false,"name":"entityId","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":255,"description":"Return only the items of the entity with this external id. Send this or `entityId`, not both.","example":"club-42"},"required":false,"name":"entityExternalId","in":"query"}],"responses":{"200":{"description":"Webhooks listed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookListResponse"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Webhooks"],"summary":"Create a webhook","description":"Create an after-call automation webhook, in an entity or shared. Assign it to an agent to receive end-of-call events.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequest"}}}},"responses":{"201":{"description":"Webhook created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/webhooks/{webhookId}":{"get":{"tags":["Webhooks"],"summary":"Get a webhook","description":"Get a single after-call automation webhook by id.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"webhookId","in":"path"}],"responses":{"200":{"description":"Webhook retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["Webhooks"],"summary":"Update a webhook","description":"Update the name, endpoint URL or entity of a webhook. Moving it to an entity is refused while an agent of another entity sends to it.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"webhookId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequest"}}}},"responses":{"200":{"description":"Webhook updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Webhook or entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The change would link items of two different entities. The error names them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","description":"Delete a webhook. Agents still referencing it will stop receiving end-of-call events.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"webhookId","in":"path"}],"responses":{"204":{"description":"Webhook deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/tools":{"get":{"tags":["Tools"],"summary":"List tools","description":"List every tool of the account, sorted by name.\n\nA tool is a function the agent can call during a conversation. Four types are available:\n\n- `custom` — POST the arguments the agent collected to your own HTTPS endpoint (OpenAI function calling: `config.parameters` is the JSON Schema of the arguments).\n- `query` — let the agent search the content of one or more web pages to answer a question.\n- `sendSms` — send a templated SMS during the call (to a fixed number, or to the caller when `config.to` is omitted).\n- `sendEmail` — send a templated email during the call; the agent's notes are passed as the `notes` argument.\n\nTransferring the call to a phone number, handing over to another agent and ending the call are **not tools**: they are nodes of the agent diagram (`forwardCall`, `forwardAgent`, `endCall` in `GET /v1/agents/{agentId}`). MCP servers, code execution and transfer cancellation are not available.\n\nA tool is attached to an agent by referencing it in a `knowHow` node prompt of the agent diagram (see `AgentDiagram`).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Tools retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Tools"],"summary":"Create a tool","description":"Create a tool of one of the four types. The body is discriminated by `type`; each variant documents a complete example.\n\nA tool is a function the agent can call during a conversation. Four types are available:\n\n- `custom` — POST the arguments the agent collected to your own HTTPS endpoint (OpenAI function calling: `config.parameters` is the JSON Schema of the arguments).\n- `query` — let the agent search the content of one or more web pages to answer a question.\n- `sendSms` — send a templated SMS during the call (to a fixed number, or to the caller when `config.to` is omitted).\n- `sendEmail` — send a templated email during the call; the agent's notes are passed as the `notes` argument.\n\nTransferring the call to a phone number, handing over to another agent and ending the call are **not tools**: they are nodes of the agent diagram (`forwardCall`, `forwardAgent`, `endCall` in `GET /v1/agents/{agentId}`). MCP servers, code execution and transfer cancellation are not available.\n\nA tool is attached to an agent by referencing it in a `knowHow` node prompt of the agent diagram (see `AgentDiagram`).","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateToolBody"}}}},"responses":{"201":{"description":"Tool created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tool"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/tools/{toolId}":{"get":{"tags":["Tools"],"summary":"Get a tool","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"toolId","in":"path"}],"responses":{"200":{"description":"Tool retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tool"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Tool not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["Tools"],"summary":"Update a tool","description":"Change the name, the description or part of the config. Each top-level config field sent replaces the stored one as a whole (send all of `messages` or `parameters` to change one entry), omitted fields keep their value, and `null` clears an optional field. The resulting config is validated against the tool's type.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"toolId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchToolBody"}}}},"responses":{"200":{"description":"Tool updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tool"}}}},"400":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Tool not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Tools"],"summary":"Delete a tool","description":"Delete a tool. Refused with a 409 while an agent prompt still references it, unless `force=true`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"toolId","in":"path"},{"schema":{"type":"string","enum":["true","false"],"default":"false","description":"Delete the tool even if agents still reference it. Their prompts keep the reference, which is skipped when the agent is built.","example":"false"},"required":false,"name":"force","in":"query"}],"responses":{"204":{"description":"Tool deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Tool not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The tool is referenced by at least one agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolInUseResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/entities":{"get":{"tags":["Entities"],"summary":"List entities","description":"An entity is a subdivision of your account — a club of a franchise, a client of a call center, a practice — that groups agents, phone numbers and webhooks. Items that belong to no entity are **shared** and usable by every entity. An entity is not a security boundary: every API key sees the whole account.\n\nEntities are sorted by name, each with the number of agents, phone numbers and webhooks it holds.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"default":1,"example":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"example":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":255,"description":"Return only the entity with this exact external id.","example":"club-42"},"required":false,"name":"externalId","in":"query"}],"responses":{"200":{"description":"Entities listed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityListResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Entities"],"summary":"Create an entity","description":"An entity is a subdivision of your account — a club of a franchise, a client of a call center, a practice — that groups agents, phone numbers and webhooks. Items that belong to no entity are **shared** and usable by every entity. An entity is not a security boundary: every API key sees the whole account.\n\nThe name and the external id must each be unique within the account. When the external id is taken, the 409 carries the id of the entity that holds it, so provisioning can be retried safely.","security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEntityRequest"}}}},"responses":{"201":{"description":"Entity created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Entity"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The name or the external id is already used by another entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityConflictResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/entities/{entityId}":{"get":{"tags":["Entities"],"summary":"Get an entity","description":"Get a single entity by id. To look one up by your own identifier, list entities with the `externalId` filter.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"entityId","in":"path"}],"responses":{"200":{"description":"Entity retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Entity"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["Entities"],"summary":"Update an entity","description":"Rename an entity, or change or remove its external id.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"entityId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEntityRequest"}}}},"responses":{"200":{"description":"Entity updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Entity"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The name or the external id is already used by another entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityConflictResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Entities"],"summary":"Delete an entity","description":"Delete an entity that holds nothing. While it still holds agents, phone numbers or webhooks the request is refused with what remains, rather than silently making those items shared.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"entityId","in":"path"}],"responses":{"204":{"description":"Entity deleted successfully"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The entity still holds agents, phone numbers or webhooks. Move them first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityInUseResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/entities/{entityId}/move-items":{"post":{"tags":["Entities"],"summary":"Move everything an entity holds","description":"Move all of the entity's agents, phone numbers and webhooks to another entity, or make them shared, so it can be merged into another or wound down and then deleted. The entity itself is kept, and the calls it made keep it.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"required":true,"name":"entityId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveEntityItemsRequest"}}}},"responses":{"200":{"description":"How many of each item moved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveEntityItemsResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The entity or the target entity was not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/invoices":{"get":{"tags":["Invoices"],"summary":"List invoices","description":"Lists the Callshift invoices of the tenant the API key belongs to, most recent first: the invoices of the billing page. Filter on `status=paid` for the payment history. Each response carries the tenant's name, so invoices fetched with several tenants' API keys can be reconciled against each other. Page back through older invoices by passing `nextCursor` as `cursor`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"example":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","minLength":1,"description":"The `nextCursor` of the previous page. Leave it out for the most recent invoices.","example":"in_1QaBcDeFgHiJkLmN"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"string","enum":["draft","open","paid","uncollectible","void"],"description":"Only the invoices in this status. `paid` gives the payment history.","example":"paid"},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"Invoices listed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListInvoicesResponse"}}}},"400":{"description":"Invalid query parameters, or a cursor that names no invoice","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ValidationErrorResponse"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}