API Reference Guide
44 min
overview exotel cqa (conversation quality analysis) provides ai powered quality analysis for contact center interactions the platform ingests interaction data audio recordings, transcripts, and metadata from any source, runs them through configurable quality profiles, and produces detailed quality scores this document covers the public api surface data import api push interactions into cqa via rest (single, batch, or file based) analysis api retrieve detailed quality analysis results file schemas csv format specifications for bulk ingestion base url all endpoints are served under the cqa context path https //{host}/cqa replace {host} with the hostname of your cqa deployment (e g cqa exotel com) authentication all data import and analysis api endpoints authenticate via an api key passed in the x api key header api surface auth method header data import api api key x api key {key} analysis api api key x api key {key} api keys api keys are scoped to a single account and are used for all programmatic ingestion and analysis retrieval api keys can be created and managed through the cqa dashboard rate limits api endpoints are rate limited per tenant (account) requests that exceed the limit receive 429 too many requests with error code rate limit exceeded (see response envelope) too many concurrent file jobs is a separate 429 with code too many jobs endpoint pattern method default tenant limit (typical) /ingress/interactions (ingest) post 100 requests per minute /ingress/ (tracking) get 300 requests per minute response envelope all data import and analysis api endpoints return responses in a common envelope success response { "status" 200, "request id" "d4f5a6b7 c8d9 4e0f a1b2 c3d4e5f6a7b8", "data" { } } error response { "status" 400, "request id" "d4f5a6b7 c8d9 4e0f a1b2 c3d4e5f6a7b8", "message" "descriptive error message", "error" { "code" "validation error" } } field type description status integer http status code mirrored in the body request id string unique request identifier for tracing and support message string human readable detail (present on many errors; may be omitted when redundant) data object response payload (present on success) error object present on failure contains code only error codes code http status description validation error 400 request failed validation (missing required fields, exceeded limits) invalid json 400 request body is not valid json invalid request 400 request contains invalid arguments unauthorized 401 missing or invalid api key not found 404 the requested resource was not found duplicate 409 returned for single ingest conflict responses (see ingest a single interaction) rate limit exceeded 429 tenant or user rate limit exceeded too many jobs 429 too many concurrent file ingestion jobs for this account internal error 500 an unexpected server error occurred data import api the data import api is the primary external integration point for pushing interaction data into cqa it supports three ingestion modes single, batch, and file based base path /api/v1/accounts/{account id}/ingress auth x api key header ingest a single interaction submits one interaction for quality analysis returns immediately with a tracking id post https //{host}/cqa/api/v1/accounts/{account id}/ingress/interactions request parameters (json body) content requirement at least one of audio url, transcript url must be provided parameter name mandatory / optional type description external interaction id mandatory string your unique identifier for this interaction used for deduplication channel type mandatory string interaction channel recognized values voice, chat, email, sms, whatsapp other values are accepted (not rejected) source optional string identifies the originating system (e g my pbx, genesys) language optional string language code (e g en, hi, es) interaction start time optional string (iso 8601) when the interaction started (e g 2026 04 01t10 30 00z) duration seconds optional integer duration of the interaction in seconds audio format optional string audio format hint (e g wav, mp3, ogg) callback url optional string webhook url for status update notifications audio url optional string direct url to the audio recording transcript url optional string direct url to the transcript file pii redacted optional boolean whether pii has already been redacted in the provided content default false metadata optional object arbitrary key value pairs for tagging maximum 50 keys values can be strings, numbers, or booleans example request curl x post "https //{host}/cqa/api/v1/accounts/{account id}/ingress/interactions" \\ h "x api key {your api key}" \\ h "content type application/json" \\ d '{ "external interaction id" "call 2026 04 01 001", "channel type" "voice", "source" "my pbx", "language" "en", "interaction start time" "2026 04 01t10 30 00z", "duration seconds" 300, "audio format" "wav", "audio url" "https //storage example com/recordings/call 001 wav", "pii redacted" false, "callback url" "https //my app example com/webhooks/cqa", "metadata" { "agent id" "agent 42", "campaign" "retention q2", "disposition" "resolved" } }' response 201 created interaction queued successfully { "status" 201, "request id" "req abc 123", "message" "queued for processing", "data" { "interaction id" "550e8400 e29b 41d4 a716 446655440000", "external interaction id" "call 2026 04 01 001", "status" "queued" } } 409 conflict duplicate external interaction id { "status" 409, "request id" "req abc 124", "message" "duplicate interaction with this external interaction id already exists", "error" { "code" "duplicate" } } 400 bad request validation error { "status" 400, "request id" "req abc 125", "message" "metadata must not exceed 50 keys", "error" { "code" "validation error" } } response fields parameter name type description interaction id string (uuid) cqa assigned unique identifier for the interaction external interaction id string your identifier, echoed back status string queued on success message string top level hint on 201 (e g queued) on errors, the detail text is in message, not inside error ingest a batch of interactions submits up to 100 interactions as a single asynchronous job returns an id in data for tracking post https //{host}/cqa/api/v1/accounts/{account id}/ingress/interactions/batch request parameters (json body) parameter name mandatory / optional type description interactions mandatory array list of interaction objects, each following the same schema as the single ingest endpoint minimum 1, maximum 100 skip duplication check optional boolean if true, skip deduplication by external interaction id default false response fields parameter name type description id string unique identifier for the batch job use this with the batch tracking endpoint type string always batch for this endpoint status string pending the job has been accepted and is queued for processing submit a file for ingestion submits a remote csv file url for asynchronous ingestion cqa downloads and processes the file in the background post https //{host}/cqa/api/v1/accounts/{account id}/ingress/interactions/files request parameters (json body) parameter name mandatory / optional type description file url mandatory string url to the file supported schemes https //, http //, s3 // https is strongly recommended; http is accepted but offers no transport encryption private/local addresses (localhost, 127 0 0 1, 10 x, 192 168 x, 172 16 x) are rejected format mandatory string file format csv or ndjson source optional string default source applied to all rows where the row level source is not set pii redacted optional boolean default pii flag applied to all rows callback url optional string default callback url stored per row (same semantics as single ingest; no http callback from ingress) column mapping optional object maps your csv headers to canonical column names keys are your original headers (trimmed, lowercased); values are canonical names ignored for ndjson see csv schema for canonical names metadata optional object default metadata merged into every row after merge, each row should respect the 50 key metadata limit enforced for batch/single ingest; avoid large default maps that push merged rows over the limit skip duplication check optional boolean if true, skip deduplication default false file processing limits limit default value max rows per file job 100,000 max file size 100 mb get interaction by id retrieves the current status and details of an ingested interaction get https //{host}/cqa/api/v1/accounts/{account id}/ingress/interactions/{interaction identifier} path parameters parameter name mandatory / optional description account id mandatory your cqa account id interaction identifier mandatory either the cqa assigned uuid (interaction id) or your external interaction id response fields parameter name type description interaction id string (uuid) cqa assigned unique identifier external interaction id string your identifier batch id string job/batch id if the interaction was part of a batch or file job omitted for single ingestion channel type string channel type as submitted source string originating system status string current status queued, processing, completed, or failed status modified at string (iso 8601) when the status last changed failure reason string reason for failure only present when status is failed; omitted otherwise audio url string resolved audio recording url (same value as submitted audio url / files audio url) transcript url string resolved transcript url pii redacted boolean whether pii was flagged as redacted created at string (iso 8601) when the interaction was ingested metadata object key value metadata analyses array list of analyses triggered for this interaction each contains analysis id, profile id, and status interaction status lifecycle applies to the status field on individual interactions and analyses api status meaning queued interaction accepted, waiting to be processed processing analysis is underway completed all analyses finished successfully failed processing failed (check failure reason) job status lifecycle applies to the status field in the batch/file 202 response and the job status field in the batch tracking response job statuses are distinct from interaction statuses job status meaning pending job accepted and queued returned in the initial 202 response processing a worker has picked up the job and is processing rows completed all rows have been processed (check accepted/rejected for counts) failed the job failed entirely (check error message) track batch / file job retrieves all interactions for a batch or file job, with pagination and job level status get https //{host}/cqa/api/v1/accounts/{account id}/ingress/interactions/batch/{id} path parameters parameter name mandatory / optional description account id mandatory your cqa account id id mandatory the job identifier the id returned in the batch or file 202 response (data id) query parameters parameter name default max description page 0 zero based page index size 20 100 number of interactions per page values above 100 are silently clamped to 100 response fields parameter name type description id string the job identifier (same as data id from the batch or file 202 response) total integer total interactions associated with this job interactions array paginated list of interaction detail objects pagination object contains page, size, total elements, total pages job status string overall job status pending, processing, completed, or failed job type string batch or file total rows integer total rows found in the input (includes accepted + rejected) accepted integer number of rows successfully processed rejected integer number of rows that failed validation errors array up to 100 error entries each has line (row number), reason, and external interaction id error message string top level error message if the entire job failed completed at string (iso 8601) when the job finished processing analysis api retrieve detailed quality analysis results for a completed analysis base path /api/v1/accounts/{account id}/analyses auth x api key header get analysis detail returns the full scoring breakdown for a specific analysis, including categories, subcategories, and individual kpi scores get https //{host}/cqa/api/v1/accounts/{account id}/analyses/{analysis id} path parameters parameter name mandatory / optional description account id mandatory your cqa account id analysis id mandatory the analysis uuid (obtained from the interaction detail's analyses array) response fields parameter name type description analysis id string (uuid) unique analysis identifier interaction id string (uuid) the interaction this analysis belongs to external interaction id string your interaction identifier profile id string quality profile used for scoring profile name string human readable quality profile name status string queued, processing, completed, or failed ai score float ai generated quality score qa score float manual qa score (if a human reviewer overrode) omitted if no manual review has occurred final score float effective score (qa score if present, otherwise ai score) criticality adjusted score float score after applying criticality weights max score float maximum possible score for this profile analysis completed at string (iso 8601) timestamp derived from the interaction's last status change in the account timezone (not a separate analysis completion clock) may not equal a pure "analysis finished" instant in all edge cases failure reason string not populated in the current response (null omitted) use status and support channels when an analysis fails categories array scored categories see category object below metadata object interaction metadata, echoed for convenience category object field type description name string category name (e g "communication skills") ai score float ai score for the category qa score float manual qa score for the category omitted if not set final score float final score for the category criticality adjusted score float criticality adjusted score max score float maximum possible score sub categories array subcategories within this category subcategory object field type description name string subcategory name qa score float manual qa score for the subcategory omitted if not set kpis array individual kpis scored within this subcategory kpi object field type description kpi name string kpi name (e g "proper greeting") ai response string the ai's answer (e g "yes", "no", "partially") ai justification string the ai's reasoning for its score ai suggestion string optional ai suggestion text omitted if not set ai score float ai score for this kpi qa score float manual qa score for this kpi omitted if not set qa justification string qa justification text omitted if not set qa selected kpi option uid string uid of the kpi option selected by qa, if any qa selected kpi option value string label/value of the qa selected kpi option user comment string free text qa/user comment on this kpi final score float final score (may reflect qa override) criticality adjusted score float criticality adjusted score max score float maximum possible score for this kpi file schemas when using the file based ingestion endpoint (post /interactions/files), cqa supports two file formats csv and ndjson csv schema the first row of a csv file must contain column headers headers are trimmed and lowercased before matching against canonical names canonical column names column required type description external interaction id yes string your unique interaction identifier channel type yes string voice, chat, email, sms, whatsapp source no string originating system identifier language no string language code (e g en) interaction start time no iso 8601 string iso 8601 utc format (e g 2026 04 01t10 00 00z) duration seconds no integer interaction duration in seconds audio format no string format hint (e g wav, mp3) callback url no string per row callback url (stored; no http callback from ingress) pii redacted no boolean true or false audio url no string audio file url(s) supports multiple urls separated by ; transcript url no string transcript file url(s) supports multiple urls separated by ; file url no string generic file url used with file type as a fallback when no audio url/transcript url entries exist file type no string file extension for type resolution audio extensions mp3, wav, ogg, flac, m4a, aac, wma, amr transcript extensions txt, pdf, doc, docx, srt, vtt content requirement each row must have at least one of audio url, transcript url extra columns become metadata any column header that is not in the canonical set above is automatically added to the row's metadata map for example, columns named agent, campaign, or disposition become metadata key value pairs without any extra configuration column mapping if your csv uses non standard headers, supply a column mapping object in the file submission request to rename them keys are your original headers (trimmed, lowercased); values are canonical names example given a csv with headers call id,type,recording,agent,campaign { "column mapping" { "call id" "external interaction id", "type" "channel type", "recording" "audio url" } } after mapping, agent and campaign are not canonical, so they automatically become metadata example csv external interaction id,channel type,audio url,transcript url,language,agent,campaign call 001,voice,https //s3 example com/rec 001 wav,https //s3 example com/tr 001 txt,en,agent 42,retention call 002,voice,https //s3 example com/rec 002 wav,,hi,agent 15,support call 003,chat,,,,agent 42,retention note row 3 (call 003) would fail validation because it has no content source (no audio, transcript) request level defaults for file ingestion for both csv and ndjson file submissions, fields set on the post /interactions/files request body are applied as defaults to every row request field behavior source applied to rows where the row level source is null or empty pii redacted applied to rows where the row level value is null callback url applied to rows where the row level value is null metadata merged with each row's metadata row level keys take precedence limits and constraints constraint value max interactions per batch 100 max metadata keys per interaction 50 (enforced on single/batch request bodies; keep merged file row metadata within this bound) max rows per file job 100,000 max file size per file job 100 mb max concurrent file jobs per account 5 (default) batch tracking page size (max) 100 (silently clamped) supported file formats csv, ndjson supported file url schemes https, http, s3 (https recommended) supported channel types voice, chat, email, sms, whatsapp
Have a question?
Our super-smart AI, knowledgeable support team and an awesome community will get you an answer in a flash.
To ask a question or participate in discussions, you'll need to authenticate first.
