{"openapi":"3.1.0","info":{"title":"Kleva Integrations API","version":"1.0.0","summary":"Public customer integration API of Kleva: voice agents, collection campaigns, contact ingestion, exports, call recordings and outbound webhooks.","description":"REST API for Kleva customers. Every request is authenticated with the company API key in the `x-api-key` header; the key is issued by Kleva and identifies your company, so you can only operate on your own campaigns, contacts and agents. Treat the key as a secret.\n\nSide effects: write operations create or change campaigns, load contacts, generate exports or change calling state; some start or resume real outbound calls (`launchCampaign`, `resumeCampaign`) and cancellation (`cancelCampaign`) is irreversible. Pausing and end-date changes are reversible but still change live campaign behavior. Every non-GET operation is flagged `x-kleva-requires-confirmation: true`, and clients should require deliberate confirmation before invoking it. `x-kleva-safety` is `read` only for operations that do not change anything (all GET), `mutating` for writes, and `dangerous` for writes that place calls or cannot be undone.\n\nWebhooks (`call.ended`, `campaign.ended`) are requests Kleva sends to your endpoints; they are described under the `webhooks` key and are not callable paths.\n\nExample identifiers and values in this document are synthetic.","contact":{"name":"Kleva","url":"https://www.kleva.co"},"x-source":{"repository":"klevaco/kleva-docs","commit":"5ec0595b46ce1b7748c74a1a0d1e807d1490275e","files":["api-reference/introduccion.mdx","api-reference/agentes/consultar-esquema.mdx","api-reference/campanas/consultar-estado.mdx","api-reference/campanas/lanzar-campana.mdx","api-reference/campanas/pausar.mdx","api-reference/campanas/reanudar.mdx","api-reference/campanas/cancelar.mdx","api-reference/campanas/modificar-fecha-fin.mdx","api-reference/ingestion/crear-inline.mdx","api-reference/ingestion/consultar-job.mdx","api-reference/ingestion/confirmar-job.mdx","api-reference/exportaciones/crear-csv.mdx","api-reference/exportaciones/consultar-csv.mdx","api-reference/exportaciones/crear-zip.mdx","api-reference/exportaciones/consultar-zip.mdx","api-reference/llamadas/obtener-grabacion.mdx","api-reference/webhooks/call-ended.mdx","api-reference/webhooks/campaign-ended.mdx"],"note":"Derived from the Kleva API reference MDX pages at the commit above."}},"servers":[{"url":"https://integrations.kleva.co","description":"Kleva Integrations API"}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"Agents","description":"Read agent input/output schemas."},{"name":"Campaigns","description":"Inspect and control campaigns. Several operations affect live calling."},{"name":"Ingestion","description":"Create campaigns and load contacts asynchronously."},{"name":"Exports","description":"Asynchronous CSV and recordings ZIP exports."},{"name":"Calls","description":"Call recordings."},{"name":"Webhooks","description":"Events Kleva sends to your endpoints."}],"paths":{"/agents/schemas":{"get":{"tags":["Agents"],"operationId":"getAgentSchemas","summary":"Get agent input/output schemas","description":"Returns the input schema (fields each contact must include) and output schema (what the agent returns after each call) for one or more agents. Query before loading contacts to ensure compatibility. Read-only.","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"None.","x-kleva-safety":"read","parameters":[{"name":"agentIds","in":"query","required":true,"description":"Comma-separated agent UUIDs.","schema":{"type":"string"},"example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d,b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e"},{"name":"type","in":"query","required":false,"description":"Which schemas to return.","schema":{"type":"string","enum":["input","output","both"],"default":"both"}}],"responses":{"200":{"description":"Schemas found plus UUIDs not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSchemasResponse"},"example":{"success":true,"data":{"schemas":{"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d":{"agent_id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","retell_agent_id":"retell_agent_abc123","input":{"schema":{"type":"object","required":[],"properties":{}},"updated_at":"2026-08-01T10:00:00.000Z"},"output":{"schema":{"type":"object","required":[],"properties":{}},"updated_at":"2026-08-01T10:00:00.000Z"}}},"notFound":["b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e"]}}}}},"400":{"description":"Bad Request: the request failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":400,"timestamp":"2026-08-19T14:22:31.184Z","path":"/agents/schemas","method":"GET","message":"each value in agentIds must be a UUID","error":"Bad Request"}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/agents/schemas","method":"GET","message":"Invalid API key","error":"Unauthorized"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/agents/schemas","method":"GET","message":"Internal server error","error":"Internal Server Error"}}}}}}},"/operations/campaigns/status":{"get":{"tags":["Campaigns"],"operationId":"getCampaignStatuses","summary":"Get campaign statuses","description":"Returns lifecycle `status` and `paused` for each requested campaign. Only existing campaigns of your organization are returned. Values that are not valid UUIDs are discarded and identifiers beyond the first 50 are ignored. Read-only.","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"None.","x-kleva-safety":"read","parameters":[{"name":"ids","in":"query","required":true,"description":"Comma-separated campaign UUIDs, no spaces. Max 50 honored.","schema":{"type":"string"},"example":"c5d6e7f8-1234-4abc-89de-fedcba012345,a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"}],"responses":{"200":{"description":"Status of each found campaign.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignStatusResponse"},"example":{"data":[{"id":"c5d6e7f8-1234-4abc-89de-fedcba012345","status":"running","paused":false},{"id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","status":"waiting","paused":true}]}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/status","method":"GET","message":"Invalid API key","error":"Unauthorized"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/status","method":"GET","message":"Internal server error","error":"Internal Server Error"}}}}}}},"/calls/dispatcher/batch-calls":{"post":{"tags":["Campaigns"],"operationId":"launchCampaign","summary":"Launch a manual-strategy campaign","description":"DANGEROUS: starts real outbound phone calls. Takes the campaign's pending contacts and enqueues them for the agent to dial. Each request executes one attempt; call again to retry. Applies only to campaigns with manual strategy (automatic strategies run on their configured schedule). Returns 200 when nothing was done (duplicate request or no eligible contacts) and 202 when the launch was accepted or deferred (dispatched, paused, deferred by schedule, or another launch in progress). Not idempotent beyond the server-side deduplication window; do not retry automatically.","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"Places real outbound calls to campaign contacts through the agent, consuming paid call minutes.","x-kleva-safety":"dangerous","x-kleva-requires-confirmation":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LaunchCampaignRequest"},"example":{"campaign_id":"c5d6e7f8-1234-4abc-89de-fedcba012345"}}}},"responses":{"200":{"description":"Nothing to do: duplicate recent request or no eligible contacts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LaunchCampaignResponse"},"example":{"campaign_id":"c5d6e7f8-1234-4abc-89de-fedcba012345","agent_id":"a1b2c3d4-5678-4abc-89de-fedcba012345","dispatched":false,"skipped":true,"reason":"duplicate_recent_batch"}}}},"202":{"description":"Accepted or deferred: dispatched, paused, scheduled or locked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LaunchCampaignResponse"},"example":{"campaign_id":"c5d6e7f8-1234-4abc-89de-fedcba012345","agent_id":"a1b2c3d4-5678-4abc-89de-fedcba012345","dispatched":true,"processed":1250}}}},"400":{"description":"Bad Request: the request failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":400,"timestamp":"2026-08-19T14:22:31.184Z","path":"/calls/dispatcher/batch-calls","method":"POST","message":"campaign_id must be a UUID","error":"Bad Request"}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/calls/dispatcher/batch-calls","method":"POST","message":"Invalid API key","error":"Unauthorized"}}}},"404":{"description":"Not Found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":404,"timestamp":"2026-08-19T14:22:31.184Z","path":"/calls/dispatcher/batch-calls","method":"POST","message":"Campaign not found","error":"Not Found"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/calls/dispatcher/batch-calls","method":"POST","message":"Internal server error","error":"Internal Server Error"}}}}}}},"/operations/campaigns/{id}/pause":{"post":{"tags":["Campaigns"],"operationId":"pauseCampaign","summary":"Pause a campaign","description":"Marks the campaign as paused (`paused: true`) and stops dialing its contacts. Idempotent. Returns 404 both when the campaign does not exist and when it is not associated with any agent (message `Campaign has no agent slug to signal`).","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"Stops dialing contacts of the campaign until resumed. Does not change `status`.","x-kleva-safety":"mutating","x-kleva-requires-confirmation":true,"parameters":[{"name":"id","in":"path","required":true,"description":"Campaign UUID to pause.","schema":{"type":"string","format":"uuid"},"example":"c5d6e7f8-1234-4abc-89de-fedcba012345"}],"responses":{"200":{"description":"Resulting pause state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignPauseResumeResponse"},"example":{"campaignId":"c5d6e7f8-1234-4abc-89de-fedcba012345","paused":true}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345/pause","method":"POST","message":"Invalid API key","error":"Unauthorized"}}}},"404":{"description":"Not Found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":404,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345/pause","method":"POST","message":"Campaign not found","error":"Not Found"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345/pause","method":"POST","message":"Internal server error","error":"Internal Server Error"}}}},"502":{"description":"Bad Gateway: a downstream service could not be notified.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":502,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345/pause","method":"POST","message":"Failed to notify downstream worker","error":"Bad Gateway"}}}}}}},"/operations/campaigns/{id}/resume":{"post":{"tags":["Campaigns"],"operationId":"resumeCampaign","summary":"Resume a campaign","description":"DANGEROUS: marks the campaign as not paused (`paused: false`) and resumes dialing its contacts, which places real calls. Idempotent. Returns 404 both when the campaign does not exist and when it is not associated with any agent (message `Campaign has no agent slug to signal`).","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"Re-enables dialing: the agent resumes placing real calls to pending contacts. Does not change `status`.","x-kleva-safety":"dangerous","x-kleva-requires-confirmation":true,"parameters":[{"name":"id","in":"path","required":true,"description":"Campaign UUID to resume.","schema":{"type":"string","format":"uuid"},"example":"c5d6e7f8-1234-4abc-89de-fedcba012345"}],"responses":{"200":{"description":"Resulting pause state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignPauseResumeResponse"},"example":{"campaignId":"c5d6e7f8-1234-4abc-89de-fedcba012345","paused":false}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345/resume","method":"POST","message":"Invalid API key","error":"Unauthorized"}}}},"404":{"description":"Not Found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":404,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345/resume","method":"POST","message":"Campaign not found","error":"Not Found"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345/resume","method":"POST","message":"Internal server error","error":"Internal Server Error"}}}},"502":{"description":"Bad Gateway: a downstream service could not be notified.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":502,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345/resume","method":"POST","message":"Failed to notify downstream worker","error":"Bad Gateway"}}}}}}},"/operations/campaigns/{id}/cancel":{"post":{"tags":["Campaigns"],"operationId":"cancelCampaign","summary":"Cancel a campaign","description":"DANGEROUS and IRREVERSIBLE: cancels the campaign. If running, stops dialing and discards queued contacts. The campaign ends in `cancelled` and never dials again; to contact those cases again, clone the campaign. Only campaigns in status `running`, `draft`, `waiting` or `completed_for_today` can be cancelled.","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"Irreversibly stops the campaign and discards queued contacts.","x-kleva-safety":"dangerous","x-kleva-requires-confirmation":true,"parameters":[{"name":"id","in":"path","required":true,"description":"Campaign UUID to cancel.","schema":{"type":"string","format":"uuid"},"example":"c5d6e7f8-1234-4abc-89de-fedcba012345"}],"responses":{"200":{"description":"Campaign cancelled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelCampaignResponse"},"example":{"campaignId":"c5d6e7f8-1234-4abc-89de-fedcba012345","status":"cancelled"}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345/cancel","method":"POST","message":"Invalid API key","error":"Unauthorized"}}}},"404":{"description":"Not Found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":404,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345/cancel","method":"POST","message":"Campaign not found","error":"Not Found"}}}},"409":{"description":"Conflict: the resource is in a state that does not allow this operation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":409,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345/cancel","method":"POST","message":"Campaign is in status \"completed\" and cannot be cancelled","error":"Conflict"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345/cancel","method":"POST","message":"Internal server error","error":"Internal Server Error"}}}},"502":{"description":"Bad Gateway: cancellation could not be completed downstream.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":502,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345/cancel","method":"POST","message":"Failed to cancel campaign via kleva-api","error":"Bad Gateway"}}}}}}},"/operations/campaigns/{id}":{"patch":{"tags":["Campaigns"],"operationId":"updateCampaignEndDate","summary":"Set or remove a campaign end date","description":"Sets or removes the campaign's `end_date`, the last day (inclusive) on which it may place calls. A date sets or extends validity; `null` removes the end date so the campaign ends naturally when retries are exhausted. A past date finishes the campaign at the next automatic evaluation. Not allowed for campaigns in a terminal status (`completed` or `cancelled`).","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"Changes when the campaign stops calling; a past date effectively ends the campaign.","x-kleva-safety":"mutating","x-kleva-requires-confirmation":true,"parameters":[{"name":"id","in":"path","required":true,"description":"Campaign UUID to modify.","schema":{"type":"string","format":"uuid"},"example":"c5d6e7f8-1234-4abc-89de-fedcba012345"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCampaignEndDateRequest"},"example":{"end_date":"2026-08-31"}}}},"responses":{"200":{"description":"Resulting end date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCampaignEndDateResponse"},"example":{"campaignId":"c5d6e7f8-1234-4abc-89de-fedcba012345","end_date":"2026-08-31T00:00:00.000Z"}}}},"400":{"description":"Bad Request: invalid body or end_date earlier than start_date.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":400,"message":"end_date cannot be earlier than start_date","error":"Bad Request"}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345","method":"PATCH","message":"Invalid API key","error":"Unauthorized"}}}},"404":{"description":"Not Found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":404,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345","method":"PATCH","message":"Campaign not found","error":"Not Found"}}}},"409":{"description":"Conflict: the resource is in a state that does not allow this operation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":409,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345","method":"PATCH","message":"Campaign is already closed — clone it to call again","error":"Conflict"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/operations/campaigns/c5d6e7f8-1234-4abc-89de-fedcba012345","method":"PATCH","message":"Internal server error","error":"Internal Server Error"}}}}}}},"/ingestion-jobs/inline":{"post":{"tags":["Ingestion"],"operationId":"createIngestionJob","summary":"Create a campaign and load contacts","description":"Creates a campaign (or adds contacts to an existing one via `campaign_id`) and loads its contacts in one call. Responds immediately with a `job_id`; processing runs in the background — poll getIngestionJob. With `error_policy: require_confirmation` the job stops in `awaiting_confirmation` when rows are invalid; then call confirmIngestionJob. On `completed` the job returns the campaign id. This operation uploads contact data (personal data) to Kleva and creates a campaign; it does not by itself launch calls for manual-strategy campaigns, but automatic strategies run on their configured schedule.","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"Creates a campaign and stores contact personal data; automatic-strategy campaigns may begin calling per their schedule.","x-kleva-safety":"mutating","x-kleva-requires-confirmation":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIngestionJobRequest"},"example":{"agent_id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","campaign_name":"Cobranza mora temprana - agosto 2026","error_policy":"skip_invalid","contacts":[{"phone":"+5491133497765","name":"Juan Pérez","amount":"5000.00","due_date":"2026-08-15"},{"phone":"+5491145678901","name":"María López","amount":"3200.00","due_date":"2026-07-20"}]}}}},"responses":{"202":{"description":"Job accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIngestionJobResponse"},"example":{"job_id":"f1e2d3c4-b5a6-4789-8012-3456789abcde","status":"pending"}}}},"400":{"description":"Bad Request: the request failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":400,"timestamp":"2026-08-19T14:22:31.184Z","path":"/ingestion-jobs/inline","method":"POST","message":"contacts must contain at least 1 elements","error":"Bad Request"}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/ingestion-jobs/inline","method":"POST","message":"Invalid API key","error":"Unauthorized"}}}},"403":{"description":"Forbidden: the resource does not belong to your company.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":403,"timestamp":"2026-08-19T14:22:31.184Z","path":"/ingestion-jobs/inline","method":"POST","message":"Agent does not belong to your company","error":"Forbidden"}}}},"413":{"description":"Payload Too Large.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":413,"timestamp":"2026-08-19T14:22:31.184Z","path":"/ingestion-jobs/inline","method":"POST","message":"Payload Too Large","error":"Payload Too Large"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/ingestion-jobs/inline","method":"POST","message":"Internal server error","error":"Internal Server Error"}}}}}}},"/ingestion-jobs/{id}":{"get":{"tags":["Ingestion"],"operationId":"getIngestionJob","summary":"Get ingestion job status","description":"Returns the status and progress of a contact load. Poll about once per minute until it finishes or needs confirmation. Read-only.","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"None.","x-kleva-safety":"read","parameters":[{"name":"id","in":"path","required":true,"description":"Ingestion job UUID returned by createIngestionJob.","schema":{"type":"string","format":"uuid"},"example":"c5d6e7f8-1234-4abc-89de-fedcba012345"}],"responses":{"200":{"description":"Job state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestionJob"},"examples":{"completed":{"value":{"id":"f1e2d3c4-b5a6-4789-8012-3456789abcde","status":"completed","error_policy":"skip_invalid","campaign_id":"c5d6e7f8-1234-4abc-89de-fedcba012345","agent_id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","campaign_name":"Cobranza mora temprana - agosto 2026","total_rows":1000,"valid_rows":987,"invalid_rows":13,"processed_count":987,"progress_pct":100,"progress_rate_pct_per_sec":0,"errors_sample":[{"row":42,"field":"phone","message":"Invalid phone number"}],"error_detail":null,"execution_date":null,"end_date":null,"created_at":"2026-08-26T14:22:31.184Z","started_at":"2026-08-26T14:22:32.001Z","finished_at":"2026-08-26T14:22:45.873Z"}},"awaiting_confirmation":{"value":{"id":"f1e2d3c4-b5a6-4789-8012-3456789abcde","status":"awaiting_confirmation","error_policy":"require_confirmation","campaign_id":null,"agent_id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","campaign_name":"Cobranza mora temprana - agosto 2026","total_rows":1000,"valid_rows":987,"invalid_rows":13,"processed_count":1000,"progress_pct":100,"progress_rate_pct_per_sec":0,"errors_sample":[{"row":42,"field":"phone","message":"Invalid phone number"}],"error_detail":null,"execution_date":null,"end_date":null,"created_at":"2026-08-26T14:22:31.184Z","started_at":"2026-08-26T14:22:32.001Z","finished_at":null}},"failed":{"value":{"id":"f1e2d3c4-b5a6-4789-8012-3456789abcde","status":"failed","error_policy":"abort_on_errors","campaign_id":null,"agent_id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","campaign_name":"Cobranza mora temprana - agosto 2026","total_rows":1000,"valid_rows":987,"invalid_rows":13,"processed_count":1000,"progress_pct":100,"progress_rate_pct_per_sec":0,"errors_sample":[{"row":42,"field":"phone","message":"Invalid phone number"}],"error_detail":{"reason":"abort_on_errors","invalid_rows":13},"execution_date":null,"end_date":null,"created_at":"2026-08-26T14:22:31.184Z","started_at":"2026-08-26T14:22:32.001Z","finished_at":"2026-08-26T14:22:44.210Z"}}}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/ingestion-jobs/f1e2d3c4-b5a6-4789-8012-3456789abcde","method":"GET","message":"Invalid API key","error":"Unauthorized"}}}},"403":{"description":"Forbidden: the resource does not belong to your company.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":403,"timestamp":"2026-08-19T14:22:31.184Z","path":"/ingestion-jobs/f1e2d3c4-b5a6-4789-8012-3456789abcde","method":"GET","message":"Job does not belong to your company","error":"Forbidden"}}}},"404":{"description":"Not Found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":404,"timestamp":"2026-08-19T14:22:31.184Z","path":"/ingestion-jobs/f1e2d3c4-b5a6-4789-8012-3456789abcde","method":"GET","message":"Job not found","error":"Not Found"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/ingestion-jobs/f1e2d3c4-b5a6-4789-8012-3456789abcde","method":"GET","message":"Internal server error","error":"Internal Server Error"}}}}}}},"/ingestion-jobs/{id}/confirm":{"post":{"tags":["Ingestion"],"operationId":"confirmIngestionJob","summary":"Confirm an ingestion job with errors","description":"Authorizes inserting the valid rows of a job in `awaiting_confirmation` (error_policy `require_confirmation`), discarding invalid rows. Other states return an error. The job then advances to `inserting`.","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"Inserts the valid contacts into the campaign and discards invalid rows.","x-kleva-safety":"mutating","x-kleva-requires-confirmation":true,"parameters":[{"name":"id","in":"path","required":true,"description":"Ingestion job UUID to confirm.","schema":{"type":"string","format":"uuid"},"example":"c5d6e7f8-1234-4abc-89de-fedcba012345"}],"responses":{"201":{"description":"Confirmed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmIngestionJobResponse"},"example":{"status":"confirmed"}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/ingestion-jobs/f1e2d3c4-b5a6-4789-8012-3456789abcde/confirm","method":"POST","message":"Invalid API key","error":"Unauthorized"}}}},"403":{"description":"Forbidden: the resource does not belong to your company.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":403,"timestamp":"2026-08-19T14:22:31.184Z","path":"/ingestion-jobs/f1e2d3c4-b5a6-4789-8012-3456789abcde/confirm","method":"POST","message":"Job does not belong to your company","error":"Forbidden"}}}},"404":{"description":"Not Found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":404,"timestamp":"2026-08-19T14:22:31.184Z","path":"/ingestion-jobs/f1e2d3c4-b5a6-4789-8012-3456789abcde/confirm","method":"POST","message":"Job not found","error":"Not Found"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/ingestion-jobs/f1e2d3c4-b5a6-4789-8012-3456789abcde/confirm","method":"POST","message":"Internal server error","error":"Internal Server Error"}}}}}}},"/csv-exports":{"post":{"tags":["Exports"],"operationId":"createCsvExport","summary":"Export campaign calls to CSV","description":"Queues asynchronous generation of a CSV with a campaign's calls (same data as the dashboard: disconnection reason, sentiment, payment promise, amount and post-call analysis fields). Responds immediately with a `job_id`; poll getCsvExport. Creates a server-side export job only; no calls are made.","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"Creates an export job; no calls or campaign changes.","x-kleva-safety":"mutating","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCsvExportRequest"},"example":{"campaign_id":"c5d6e7f8-1234-4abc-89de-fedcba012345","locale":"es","filters":{"dateFrom":"2026-08-01","dateTo":"2026-08-15","callAnswered":true}}}}},"responses":{"200":{"description":"Job queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCsvExportResponse"},"example":{"job_id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"}}}},"400":{"description":"Bad Request: the request failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":400,"timestamp":"2026-08-19T14:22:31.184Z","path":"/csv-exports","method":"POST","message":"campaign_id must be a UUID","error":"Bad Request"}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/csv-exports","method":"POST","message":"Invalid API key","error":"Unauthorized"}}}},"403":{"description":"Forbidden: the resource does not belong to your company.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":403,"timestamp":"2026-08-19T14:22:31.184Z","path":"/csv-exports","method":"POST","message":"Access denied","error":"Forbidden"}}}},"404":{"description":"Not Found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":404,"timestamp":"2026-08-19T14:22:31.184Z","path":"/csv-exports","method":"POST","message":"Campaign not found","error":"Not Found"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/csv-exports","method":"POST","message":"Internal server error","error":"Internal Server Error"}}}}},"x-kleva-requires-confirmation":true}},"/csv-exports/{id}":{"get":{"tags":["Exports"],"operationId":"getCsvExport","summary":"Get CSV export status","description":"Returns the state of a CSV export job. Keep polling until `completed` or `failed`. When completed, `download_url` is a signed S3 URL valid for 3600 seconds; do not store it — request this endpoint again for a fresh URL. Read-only.","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"None.","x-kleva-safety":"read","parameters":[{"name":"id","in":"path","required":true,"description":"Export job UUID returned by createCsvExport.","schema":{"type":"string","format":"uuid"},"example":"c5d6e7f8-1234-4abc-89de-fedcba012345"}],"responses":{"200":{"description":"Export job state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CsvExport"},"examples":{"processing":{"value":{"id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","campaign_id":"c5d6e7f8-1234-4abc-89de-fedcba012345","created_at":"2026-08-19T14:20:11.000Z","status":"processing","row_count":null,"row_count_excluded_contacts":null,"error":null,"updated_at":"2026-08-19T14:20:15.000Z"}},"completed":{"value":{"id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","campaign_id":"c5d6e7f8-1234-4abc-89de-fedcba012345","created_at":"2026-08-19T14:20:11.000Z","status":"completed","row_count":3452,"row_count_excluded_contacts":128,"error":null,"updated_at":"2026-08-19T14:21:02.000Z","download_url":"https://kleva-csv-exports.s3.amazonaws.com/example","excluded_contacts_download_url":"https://kleva-csv-exports.s3.amazonaws.com/example-excluded"}},"failed":{"value":{"id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","campaign_id":"c5d6e7f8-1234-4abc-89de-fedcba012345","created_at":"2026-08-19T14:20:11.000Z","status":"failed","row_count":null,"row_count_excluded_contacts":null,"error":"Timed out reading campaign calls","updated_at":"2026-08-19T14:22:31.000Z"}}}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/csv-exports/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","method":"GET","message":"Invalid API key","error":"Unauthorized"}}}},"403":{"description":"Forbidden: the resource does not belong to your company.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":403,"timestamp":"2026-08-19T14:22:31.184Z","path":"/csv-exports/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","method":"GET","message":"Access denied","error":"Forbidden"}}}},"404":{"description":"Not Found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":404,"timestamp":"2026-08-19T14:22:31.184Z","path":"/csv-exports/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","method":"GET","message":"CSV job not found","error":"Not Found"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/csv-exports/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","method":"GET","message":"Internal server error","error":"Internal Server Error"}}}}}}},"/recording-exports":{"post":{"tags":["Exports"],"operationId":"createRecordingExport","summary":"Export campaign recordings to ZIP","description":"Queues asynchronous generation of a `.zip` with the recordings of all calls of a campaign. Responds immediately with an `export_id`; poll getRecordingExport. No email is sent when requested via API key. Creates an export job only; no calls are made.","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"Creates an export job; no calls or campaign changes.","x-kleva-safety":"mutating","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRecordingExportRequest"},"example":{"campaign_id":"c5d6e7f8-1234-4abc-89de-fedcba012345"}}}},"responses":{"200":{"description":"Job queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRecordingExportResponse"},"example":{"export_id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"}}}},"400":{"description":"Bad Request: the request failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":400,"timestamp":"2026-08-19T14:22:31.184Z","path":"/recording-exports","method":"POST","message":"campaign_id must be a UUID","error":"Bad Request"}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/recording-exports","method":"POST","message":"Invalid API key","error":"Unauthorized"}}}},"403":{"description":"Forbidden: the resource does not belong to your company.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":403,"timestamp":"2026-08-19T14:22:31.184Z","path":"/recording-exports","method":"POST","message":"Access denied","error":"Forbidden"}}}},"404":{"description":"Not Found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":404,"timestamp":"2026-08-19T14:22:31.184Z","path":"/recording-exports","method":"POST","message":"Campaign not found","error":"Not Found"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/recording-exports","method":"POST","message":"Internal server error","error":"Internal Server Error"}}}}},"x-kleva-requires-confirmation":true}},"/recording-exports/{id}":{"get":{"tags":["Exports"],"operationId":"getRecordingExport","summary":"Get recordings ZIP export status","description":"Returns the state of a recordings export job. Keep polling until `completed` or `failed`. When completed, `download_url` is a signed S3 URL valid for 3600 seconds; do not store it. Read-only.","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"None.","x-kleva-safety":"read","parameters":[{"name":"id","in":"path","required":true,"description":"Export job UUID returned by createRecordingExport.","schema":{"type":"string","format":"uuid"},"example":"c5d6e7f8-1234-4abc-89de-fedcba012345"}],"responses":{"200":{"description":"Export job state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordingExport"},"examples":{"processing":{"value":{"id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","campaign_id":"c5d6e7f8-1234-4abc-89de-fedcba012345","created_at":"2026-08-19T14:20:11.000Z","status":"processing","error":null,"updated_at":"2026-08-19T14:20:15.000Z"}},"completed":{"value":{"id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","campaign_id":"c5d6e7f8-1234-4abc-89de-fedcba012345","created_at":"2026-08-19T14:20:11.000Z","status":"completed","error":null,"updated_at":"2026-08-19T14:25:42.000Z","download_url":"https://kleva-zip-exports.s3.amazonaws.com/example"}},"failed":{"value":{"id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","campaign_id":"c5d6e7f8-1234-4abc-89de-fedcba012345","created_at":"2026-08-19T14:20:11.000Z","status":"failed","error":"dispatch failed: connection refused","updated_at":"2026-08-19T14:20:12.000Z"}}}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/recording-exports/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","method":"GET","message":"Invalid API key","error":"Unauthorized"}}}},"403":{"description":"Forbidden: the resource does not belong to your company.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":403,"timestamp":"2026-08-19T14:22:31.184Z","path":"/recording-exports/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","method":"GET","message":"Access denied","error":"Forbidden"}}}},"404":{"description":"Not Found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":404,"timestamp":"2026-08-19T14:22:31.184Z","path":"/recording-exports/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","method":"GET","message":"Job not found","error":"Not Found"}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/recording-exports/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","method":"GET","message":"Internal server error","error":"Internal Server Error"}}}}}}},"/calls/recordings/{callId}":{"get":{"tags":["Calls"],"operationId":"getCallRecording","summary":"Get a call recording URL","description":"Returns a short-lived signed URL (default 900 s; effective value in `expires_in`) for a call's audio. Do not store it. For recently ended calls wait at least 60 seconds; if the endpoint returns 409 with `code: RECORDING_NOT_READY`, retry after the time in the `Retry-After` header. Read-only.","security":[{"ApiKeyAuth":[]}],"x-kleva-side-effects":"None.","x-kleva-safety":"read","parameters":[{"name":"callId","in":"path","required":true,"description":"Call UUID, the same id received in the post-call webhook event.","schema":{"type":"string","format":"uuid"},"example":"c5d6e7f8-1234-4abc-89de-fedcba012345"}],"responses":{"200":{"description":"Signed recording URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallRecording"},"example":{"url":"https://kleva-call-recordings.s3.amazonaws.com/example","expires_in":900}}}},"401":{"description":"Unauthorized: missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":401,"timestamp":"2026-08-19T14:22:31.184Z","path":"/calls/recordings/c5d6e7f8-1234-4abc-89de-fedcba012345","method":"GET","message":"Invalid API key","error":"Unauthorized"}}}},"404":{"description":"Call not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":404,"timestamp":"2026-08-19T14:22:31.184Z","path":"/calls/recordings/c5d6e7f8-1234-4abc-89de-fedcba012345","method":"GET","message":"Call not found","error":"Not Found","code":"CALL_NOT_FOUND"}}}},"409":{"description":"Recording not replicated yet; retry after `Retry-After`.","headers":{"Retry-After":{"description":"Time to wait before retrying.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":409,"timestamp":"2026-08-19T14:22:31.184Z","path":"/calls/recordings/c5d6e7f8-1234-4abc-89de-fedcba012345","method":"GET","message":"Recording not replicated yet","error":"Conflict","code":"RECORDING_NOT_READY","details":{"recording_migration_status":"in_progress"}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"statusCode":500,"timestamp":"2026-08-19T14:22:31.184Z","path":"/calls/recordings/c5d6e7f8-1234-4abc-89de-fedcba012345","method":"GET","message":"Internal server error","error":"Internal Server Error"}}}}}}}},"webhooks":{"callEnded":{"post":{"tags":["Webhooks"],"operationId":"receiveCallEndedWebhook","summary":"Call ended event","description":"Sent when a call managed by Kleva ends, with call, agent, campaign, contact, debt, outcome and your custom fields.\n\nKleva sends a POST with `Content-Type: application/json` and `User-Agent: kleva-post-call-dispatcher/1` to every active webhook URL of your organization. Authentication headers depend on the webhook's configured method: `none` (none), `bearer` (`Authorization: Bearer <secret>`), `api_key` (`<configured name>: <secret>`), `hmac` (`X-Kleva-Timestamp: <epoch seconds>` and `X-Kleva-Signature: sha256=<hex signature>`). Respond 2xx to acknowledge. 5xx, 408 and 429 are retried automatically; other 4xx are permanent failures and not retried.","x-kleva-safety":"incoming","x-kleva-side-effects":"None on Kleva; this describes a request sent by Kleva to your endpoint.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallEndedEvent"},"example":{"call":{"id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","direction":"outbound","from_number":"+5491112345678","to_number":"+5491198765432","started_at":"2026-09-11T14:00:00.000Z","ended_at":"2026-09-11T14:02:35.000Z","duration_seconds":155,"disconnection_reason":"agent_hangup","connected":true,"answered":true,"recording_url":"https://api.kleva.co/recordings/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","transcript":null,"transcript_turns":null,"call_summary":"El contacto acordó pagar el día 15 de septiembre el monto total adeudado.","agent_version":"v2"},"agent":{"id":"b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e","slug":"cobros-arg","country":"AR","timezone":"America/Argentina/Buenos_Aires"},"campaign":{"id":"c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f","name":"Recupero Septiembre 2026"},"contact":{"id":"d4e5f6a7-b8c9-4d0e-1f2a-3b4c5d6e7f8a","external_id":"CL-00123","phone":"+5491198765432","name":"Carlos","lastname":"Gómez"},"debt":{"id":"e5f6a7b8-c9d0-4e1f-2a3b-4c5d6e7f8a9b","amount":15000,"currency":"ARS","due_date":"2026-08-01","days_late":41},"outcome":{"reach_status":"reached","user_sentiment":"neutral","promise_to_pay":"will_pay","promise_date":"2026-09-15","promise_amount":15000},"custom_fields":{"zona":"norte","segmento":"b2c"}}}}},"responses":{"200":{"description":"Acknowledge receipt with any 2xx status."}}}},"campaignEnded":{"post":{"tags":["Webhooks"],"operationId":"receiveCampaignEndedWebhook","summary":"Campaign ended event","description":"Sent when a campaign managed by Kleva finishes, with a campaign summary and per-channel aggregate metrics.\n\nKleva sends a POST with `Content-Type: application/json` and `User-Agent: kleva-post-call-dispatcher/1` to every active webhook URL of your organization. Authentication headers depend on the webhook's configured method: `none` (none), `bearer` (`Authorization: Bearer <secret>`), `api_key` (`<configured name>: <secret>`), `hmac` (`X-Kleva-Timestamp: <epoch seconds>` and `X-Kleva-Signature: sha256=<hex signature>`). Respond 2xx to acknowledge. 5xx, 408 and 429 are retried automatically; other 4xx are permanent failures and not retried.","x-kleva-safety":"incoming","x-kleva-side-effects":"None on Kleva; this describes a request sent by Kleva to your endpoint.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignEndedEvent"},"example":{"campaign":{"id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","name":"Recupero Septiembre 2026","status":"completed","start_date":"2026-09-01T00:00:00.000Z","end_date":"2026-09-15T00:00:00.000Z","agent_id":"c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f","company_id":"b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e","contacts":3500,"debts":3800,"channels":["voice"]},"channels":{"voice":{"total":3500,"connected":2100,"answered":1890,"total_minutes":4725,"total_cost":94.5,"payment_promises":378,"connectivity_rate":0.6,"payment_promise_rate":0.2,"total_promised_amount":5670000,"avg_promised_amount":15000}}}}}},"responses":{"200":{"description":"Acknowledge receipt with any 2xx status."}}}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Company API key issued by Kleva. Never log it, embed it in frontend code or commit it. Provide it via an environment variable or secret manager."}},"schemas":{"ErrorResponse":{"type":"object","description":"Standard error body.","required":["statusCode","message","error"],"properties":{"statusCode":{"type":"integer"},"timestamp":{"type":"string","format":"date-time"},"path":{"type":"string"},"method":{"type":"string"},"message":{"type":"string"},"error":{"type":"string"},"code":{"type":"string","description":"Machine-readable code; documented for recording lookups: `CALL_NOT_FOUND`, `RECORDING_NOT_READY`."},"details":{"type":"object","additionalProperties":true,"description":"Extra details, e.g. `recording_migration_status` on `RECORDING_NOT_READY`.","properties":{"recording_migration_status":{"type":"string"}}}}},"AgentSchemaEntry":{"type":"object","required":["schema","updated_at"],"properties":{"schema":{"type":"object","description":"JSON Schema document.","additionalProperties":true},"updated_at":{"type":["string","null"],"format":"date-time","description":"Last update, ISO 8601."}}},"AgentSchemas":{"type":"object","required":["agent_id","retell_agent_id","input","output"],"properties":{"agent_id":{"type":"string","format":"uuid","description":"Agent UUID.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"retell_agent_id":{"type":"string","description":"Internal agent identifier at the voice provider (legacy wire key)."},"input":{"description":"Input schema; null if none configured or if `type` is `output`.","oneOf":[{"$ref":"#/components/schemas/AgentSchemaEntry"},{"type":"null"}]},"output":{"description":"Output schema; null if none configured or if `type` is `input`.","oneOf":[{"$ref":"#/components/schemas/AgentSchemaEntry"},{"type":"null"}]}}},"AgentSchemasResponse":{"type":"object","required":["data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["schemas","notFound"],"properties":{"schemas":{"type":"object","description":"One entry per found agent, keyed by agent UUID.","additionalProperties":{"$ref":"#/components/schemas/AgentSchemas"}},"notFound":{"type":"array","items":{"type":"string"},"description":"UUIDs not found or not belonging to your organization."}}}}},"CampaignStatus":{"type":"string","enum":["draft","waiting","running","completed_for_today","completed","cancelled"],"description":"Lifecycle state. draft: created, not started; waiting: attempt finished, awaiting next; running: calling; completed_for_today: daily calls exhausted, resumes next cycle; completed: all retries done or end date/time reached; cancelled: cancelled manually, irreversible."},"CampaignStatusResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object","required":["id","status","paused"],"properties":{"id":{"type":"string","format":"uuid","description":"Campaign UUID.","example":"c5d6e7f8-1234-4abc-89de-fedcba012345"},"status":{"description":"Current lifecycle state; null if none assigned yet.","oneOf":[{"$ref":"#/components/schemas/CampaignStatus"},{"type":"null"}]},"paused":{"type":"boolean","description":"True if execution is temporarily paused. Pausing/resuming does not change `status`."}}}}}},"LaunchCampaignRequest":{"type":"object","required":["campaign_id"],"properties":{"campaign_id":{"type":"string","format":"uuid","description":"UUID of the manual-strategy campaign to launch.","example":"c5d6e7f8-1234-4abc-89de-fedcba012345"}}},"LaunchCampaignResponse":{"type":"object","required":["campaign_id","agent_id","dispatched"],"properties":{"campaign_id":{"type":"string","format":"uuid","description":"Campaign UUID the operation applied to.","example":"c5d6e7f8-1234-4abc-89de-fedcba012345"},"agent_id":{"type":"string","format":"uuid","description":"Agent UUID that executes the calls.","example":"a1b2c3d4-5678-4abc-89de-fedcba012345"},"dispatched":{"type":"boolean","description":"True only when contacts were actually enqueued in this attempt."},"reason":{"type":"string","enum":["duplicate_recent_batch","outside_calling_window","reset_in_progress"],"description":"Why the attempt was discarded or deferred."},"skipped":{"type":"boolean","description":"Present when discarded as a recent duplicate."},"completed":{"type":"boolean","description":"Present when the campaign has no eligible contacts left."},"paused":{"type":"boolean","description":"Present when the campaign is paused; nothing is enqueued until resumed."},"scheduled":{"type":"boolean","description":"Present when deferred by a future start_date or calling window."},"locked":{"type":"boolean","description":"Present when another launch of the same campaign is in progress."},"processed":{"type":"integer","description":"Contacts prepared for calling in this attempt. Present only when `dispatched` is true."}}},"CampaignPauseResumeResponse":{"type":"object","required":["campaignId","paused"],"properties":{"campaignId":{"type":"string","format":"uuid","description":"Campaign UUID.","example":"c5d6e7f8-1234-4abc-89de-fedcba012345"},"paused":{"type":"boolean","description":"Resulting state: true after pause, false after resume."}}},"CancelCampaignResponse":{"type":"object","required":["campaignId","status"],"properties":{"campaignId":{"type":"string","format":"uuid","description":"Cancelled campaign UUID.","example":"c5d6e7f8-1234-4abc-89de-fedcba012345"},"status":{"type":"string","enum":["cancelled"]}}},"UpdateCampaignEndDateRequest":{"type":"object","required":["end_date"],"properties":{"end_date":{"type":["string","null"],"format":"date","description":"Inclusive end date `YYYY-MM-DD`; `null` removes the end date. A past date finishes the campaign at the next automatic evaluation. Earlier than start_date is rejected with 400."}}},"UpdateCampaignEndDateResponse":{"type":"object","required":["campaignId","end_date"],"properties":{"campaignId":{"type":"string","format":"uuid","description":"Campaign UUID.","example":"c5d6e7f8-1234-4abc-89de-fedcba012345"},"end_date":{"type":["string","null"],"format":"date-time","description":"Resulting end date (ISO 8601 with time); null if none."}}},"ErrorPolicy":{"type":"string","enum":["skip_invalid","require_confirmation","abort_on_errors"],"description":"skip_invalid: insert only valid rows, silently discard invalid ones; require_confirmation: pause in `awaiting_confirmation` if invalid rows exist; abort_on_errors: fail the whole job on any invalid row, inserting nothing."},"IngestionContact":{"type":"object","description":"Contact conforming to the agent input schema (see getAgentSchemas). Any additional fields defined by that schema may be included.","properties":{"phone":{"type":"string","description":"E.164 phone number, e.g. `+5491133497765`."},"name":{"type":"string","description":"Contact name used in the conversation."}},"additionalProperties":true},"CreateIngestionJobRequest":{"type":"object","required":["agent_id","contacts","error_policy"],"properties":{"agent_id":{"type":"string","format":"uuid","description":"Agent UUID that will place the calls.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"contacts":{"type":"array","minItems":1,"maxItems":30000,"items":{"$ref":"#/components/schemas/IngestionContact"},"description":"Contacts to load; 1 to 30,000."},"error_policy":{"$ref":"#/components/schemas/ErrorPolicy"},"campaign_name":{"type":"string","description":"Campaign name; generated from agent slug and date if omitted."},"campaign_id":{"type":"string","format":"uuid","description":"Existing campaign UUID; contacts are added to it instead of creating a new campaign.","example":"c5d6e7f8-1234-4abc-89de-fedcba012345"},"execution_date":{"type":"string","format":"date","description":"Campaign start date `YYYY-MM-DD`; defaults to the creation day."},"end_date":{"type":"string","format":"date","description":"Inclusive end date `YYYY-MM-DD`; retry cycle repeats daily between execution_date and end_date. Without it the campaign ends after the last attempt of the start day."},"custom_attempts":{"type":"array","description":"Custom attempt schedule; defaults to the agent's retry strategy.","items":{"type":"object","required":["number","hour"],"properties":{"number":{"type":"integer","minimum":1,"description":"Attempt number, 1-based."},"hour":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$","description":"Local attempt time `HH:MM`."}}}}}},"CreateIngestionJobResponse":{"type":"object","required":["job_id","status"],"properties":{"job_id":{"type":"string","format":"uuid","description":"Ingestion job UUID.","example":"f1e2d3c4-b5a6-4789-8012-3456789abcde"},"status":{"type":"string","enum":["pending"]}}},"IngestionJobStatus":{"type":"string","enum":["pending","validating","awaiting_confirmation","inserting","completed","failed","cancelled"],"description":"pending: waiting to start; validating; awaiting_confirmation: invalid rows need confirmation; inserting; completed: campaign_id available; failed: see error_detail; cancelled."},"IngestionJob":{"type":"object","required":["id","status","error_policy","processed_count","progress_pct","progress_rate_pct_per_sec","created_at"],"properties":{"id":{"type":"string","format":"uuid","description":"Job UUID.","example":"f1e2d3c4-b5a6-4789-8012-3456789abcde"},"status":{"$ref":"#/components/schemas/IngestionJobStatus"},"error_policy":{"$ref":"#/components/schemas/ErrorPolicy"},"campaign_id":{"type":["string","null"],"format":"uuid","description":"Created or used campaign; null until the job reaches `inserting`."},"agent_id":{"type":["string","null"],"format":"uuid","description":"Associated agent."},"campaign_name":{"type":["string","null"],"description":"Campaign name."},"total_rows":{"type":["integer","null"],"description":"Rows detected; available after `validating`."},"valid_rows":{"type":["integer","null"],"description":"Rows that passed validation."},"invalid_rows":{"type":["integer","null"],"description":"Rows that failed validation."},"processed_count":{"type":"integer","description":"Rows processed so far in the active phase."},"progress_pct":{"type":"number","minimum":0,"maximum":100,"description":"Progress of the active phase, 0-100."},"progress_rate_pct_per_sec":{"type":"number","description":"Progress speed in percentage points per second; interpolate with min(100, progress_pct + rate × seconds)."},"errors_sample":{"type":["array","null"],"description":"Sample of validation errors, present when invalid rows exist after validation.","items":{"type":"object","additionalProperties":true,"properties":{"row":{"type":"integer"},"field":{"type":"string"},"message":{"type":"string"}}}},"error_detail":{"type":["object","null"],"description":"Fatal error detail when status is `failed`.","required":["reason"],"additionalProperties":true,"properties":{"reason":{"type":"string"},"invalid_rows":{"type":"integer"}}},"execution_date":{"type":["string","null"],"description":"Campaign start date, ISO 8601."},"end_date":{"type":["string","null"],"description":"Campaign end date, ISO 8601."},"created_at":{"type":"string","format":"date-time"},"started_at":{"type":["string","null"],"format":"date-time","description":"Null while pending."},"finished_at":{"type":["string","null"],"format":"date-time","description":"Null until finished or failed."}}},"ConfirmIngestionJobResponse":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["confirmed"]}}},"CreateCsvExportRequest":{"type":"object","required":["campaign_id"],"properties":{"campaign_id":{"type":"string","format":"uuid","description":"Campaign UUID to export.","example":"c5d6e7f8-1234-4abc-89de-fedcba012345"},"locale":{"type":"string","enum":["es","en"],"default":"es","description":"CSV language (headers and translatable values)."},"timezone":{"type":"string","description":"IANA timezone for dates; defaults to your company's timezone.","examples":["America/Argentina/Buenos_Aires"]},"filters":{"type":"object","description":"Narrow exported calls; omit or `{}` for all calls.","properties":{"dateFrom":{"type":"string","format":"date","description":"Inclusive start date, filters call created_at."},"dateTo":{"type":"string","format":"date","description":"Inclusive end date, filters call created_at."},"callAnswered":{"type":"boolean"},"callConnected":{"type":"boolean"},"promiseToPay":{"type":"string","description":"e.g. `will_pay`, `no_answer`."},"sentiment":{"type":"string"},"disconnectionReason":{"type":"string","description":"e.g. `voicemail_reached`."},"durationMin":{"type":"number","description":"Minimum duration, seconds."},"durationMax":{"type":"number","description":"Maximum duration, seconds."},"attempt":{"type":"integer","description":"Attempt number."}}}}},"CreateCsvExportResponse":{"type":"object","required":["job_id"],"properties":{"job_id":{"type":"string","format":"uuid","description":"Export job UUID; poll with getCsvExport.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"}}},"ExportStatus":{"type":"string","enum":["pending","processing","completed","failed"]},"CsvExport":{"type":"object","required":["id","campaign_id","status","error","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","description":"Export job UUID.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"campaign_id":{"type":"string","format":"uuid","description":"Campaign UUID.","example":"c5d6e7f8-1234-4abc-89de-fedcba012345"},"status":{"$ref":"#/components/schemas/ExportStatus"},"row_count":{"type":["integer","null"],"description":"Calls in the CSV; available when completed."},"row_count_excluded_contacts":{"type":["integer","null"],"description":"Excluded contacts exported; when completed and the agent has the excluded CSV enabled."},"error":{"type":["string","null"],"description":"Failure message when `failed`; null otherwise."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"download_url":{"type":"string","format":"uri","description":"Signed S3 URL, present only when `completed`; valid 3600 s. Do not store."},"excluded_contacts_download_url":{"type":"string","format":"uri","description":"Signed S3 URL for the excluded-contacts CSV; only when completed and enabled for the agent."}}},"CreateRecordingExportRequest":{"type":"object","required":["campaign_id"],"properties":{"campaign_id":{"type":"string","format":"uuid","description":"Campaign UUID whose recordings to download.","example":"c5d6e7f8-1234-4abc-89de-fedcba012345"}}},"CreateRecordingExportResponse":{"type":"object","required":["export_id"],"properties":{"export_id":{"type":"string","format":"uuid","description":"Export job UUID; poll with getRecordingExport.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"}}},"RecordingExport":{"type":"object","required":["id","campaign_id","status","error","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","description":"Export job UUID.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"campaign_id":{"type":"string","format":"uuid","description":"Campaign UUID.","example":"c5d6e7f8-1234-4abc-89de-fedcba012345"},"status":{"$ref":"#/components/schemas/ExportStatus"},"error":{"type":["string","null"],"description":"Failure message when `failed`; null otherwise."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"download_url":{"type":"string","format":"uri","description":"Signed S3 URL, present only when `completed`; valid 3600 s. Do not store."}}},"CallRecording":{"type":"object","required":["url","expires_in"],"properties":{"url":{"type":"string","format":"uri","description":"Signed S3 URL, playable or downloadable with a standard GET."},"expires_in":{"type":"integer","description":"Seconds until the URL stops working (default 900)."}}},"CallEndedEvent":{"type":"object","required":["call","agent","campaign","contact","debt","outcome","custom_fields"],"properties":{"call":{"type":"object","required":["id","recording_url"],"properties":{"id":{"type":"string","format":"uuid","description":"Kleva call UUID.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"direction":{"type":["string","null"],"description":"Typically `outbound` or `inbound`."},"from_number":{"type":["string","null"],"description":"E.164 origin."},"to_number":{"type":["string","null"],"description":"E.164 destination."},"started_at":{"type":["string","null"],"format":"date-time"},"ended_at":{"type":["string","null"],"format":"date-time"},"duration_seconds":{"type":["number","null"],"description":"Call duration in seconds."},"disconnection_reason":{"type":["string","null"],"description":"Why the call ended."},"connected":{"type":["boolean","null"],"description":"True if connected."},"answered":{"type":["boolean","null"],"description":"True if answered by a person."},"recording_url":{"type":"string","description":"Kleva-provided recording access URL. Always present."},"transcript":{"type":["string","null"],"description":"Plain-text transcript; only when the webhook has `include_transcript` enabled."},"transcript_turns":{"type":["array","null"],"description":"Structured transcript; only when `include_transcript` is enabled.","items":{"type":"object","required":["role","content"],"properties":{"role":{"type":"string","enum":["agent","user"]},"content":{"type":"string"}}}},"call_summary":{"type":["string","null"],"description":"Summary generated at call end."},"agent_version":{"type":["string","null"],"description":"Agent version used."}}},"agent":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid","description":"Agent UUID.","example":"b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e"},"slug":{"type":["string","null"],"description":"Readable agent identifier."},"country":{"type":["string","null"],"description":"ISO 3166-1 alpha-2 country."},"timezone":{"type":["string","null"],"description":"IANA timezone."}}},"campaign":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid","description":"Campaign UUID.","example":"c5d6e7f8-1234-4abc-89de-fedcba012345"},"name":{"type":["string","null"],"description":"Campaign name."}}},"contact":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid","description":"Kleva contact UUID.","example":"d4e5f6a7-b8c9-4d0e-1f2a-3b4c5d6e7f8a"},"external_id":{"type":["string","null"],"description":"Contact id in your system as loaded."},"phone":{"type":["string","null"],"description":"E.164 phone."},"name":{"type":["string","null"],"description":"First name."},"lastname":{"type":["string","null"],"description":"Last name."}}},"debt":{"type":["object","null"],"description":"Debt linked to the attempt; null if none.","required":["id"],"properties":{"id":{"type":"string","format":"uuid","description":"Debt UUID.","example":"e5f6a7b8-c9d0-4e1f-2a3b-4c5d6e7f8a9b"},"amount":{"type":["number","null"],"description":"Debt amount."},"currency":{"type":["string","null"],"description":"Currency, e.g. `ARS`, `USD`."},"due_date":{"type":["string","null"],"description":"Due date."},"days_late":{"type":["number","null"],"description":"Days late at call time."}}},"outcome":{"type":"object","properties":{"reach_status":{"type":["string","null"],"description":"Whether the contact was effectively reached and the attempt result."},"user_sentiment":{"type":["string","null"],"description":"Detected user sentiment."},"promise_to_pay":{"type":["string","null"],"enum":["will_pay","will_pay_late","will_not_pay","already_paid","no_answer",null],"description":"Payment-intent result."},"promise_date":{"type":["string","null"],"description":"Committed payment date; only for will_pay / will_pay_late."},"promise_amount":{"type":["number","null"],"description":"Committed amount; only for will_pay / will_pay_late."}}},"custom_fields":{"type":"object","additionalProperties":true,"description":"Additional fields your company sent per contact when loading the campaign; no predefined structure."}}},"ChannelMetrics":{"type":"object","required":["total","connected","answered","total_minutes","total_cost","payment_promises","connectivity_rate","payment_promise_rate","total_promised_amount","avg_promised_amount"],"properties":{"total":{"type":"number","description":"Total attempts on this channel."},"connected":{"type":"number"},"answered":{"type":"number"},"total_minutes":{"type":"number","description":"Conversation minutes across connected attempts."},"total_cost":{"type":"number","description":"Accumulated cost in USD."},"payment_promises":{"type":"number"},"connectivity_rate":{"type":"number","minimum":0,"maximum":1},"payment_promise_rate":{"type":"number","minimum":0,"maximum":1},"total_promised_amount":{"type":"number"},"avg_promised_amount":{"type":"number"}}},"CampaignEndedEvent":{"type":"object","required":["campaign","channels"],"properties":{"campaign":{"type":"object","required":["id","status","agent_id","company_id","contacts","debts","channels"],"properties":{"id":{"type":"string","format":"uuid","description":"Campaign UUID.","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"name":{"type":["string","null"],"description":"Campaign name."},"status":{"type":"string","enum":["completed"],"description":"Always `completed` for this event."},"start_date":{"type":["string","null"],"format":"date-time"},"end_date":{"type":["string","null"],"format":"date-time","description":"Null if no explicit end date configured."},"agent_id":{"type":"string","format":"uuid","description":"Voice agent UUID.","example":"c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f"},"company_id":{"type":"string","format":"uuid","description":"Owning organization UUID.","example":"b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e"},"contacts":{"type":"number"},"debts":{"type":"number"},"channels":{"type":"array","items":{"type":"string"},"description":"Channels used, e.g. `[\"voice\"]`."}}},"channels":{"type":"object","description":"Per-channel aggregate metrics keyed by channel name, e.g. `voice`.","additionalProperties":{"$ref":"#/components/schemas/ChannelMetrics"}}}}},"parameters":{},"responses":{}}}