Most of the engineering here is about a batch that goes wrong at call three hundred, because that is the one that costs you money.
Above the failure threshold the campaign pauses itself rather than spending the rest of your balance finding out.
Throughput is not free. Upstream models have quotas, and a batch that fires everything at once gets throttled or rejected, usually partway through, leaving a campaign half-finished and expensive to reconcile.
Each campaign carries its own audits-per-minute setting, and the worker paces jobs to it. Slower in theory, faster in practice, and predictable either way.
Every job reports its own progress, so a batch running overnight is legible in the morning rather than being a single spinner.
config.rpm · queue-worker.service.ts
The expensive failure mode in bulk auditing is not a job that breaks. It is a batch where something systemic is wrong: a bad URL pattern, an expired share link, a scorecard pointing at nothing, and the system cheerfully works through all five hundred anyway.
Above a failure threshold, the campaign pauses itself rather than spending the rest of your balance discovering the same problem four hundred more times. You fix it and resume; the jobs that already succeeded are not re-run.
Individual failures retry with exponential backoff first, and a job that exhausts its attempts moves to a dead-letter queue instead of blocking the ones behind it.
The balance is re-checked job by job, not once at the start: a long batch can legitimately run out partway through, and the right response is to stop rather than to fail five hundred times.
config.failureThreshold · auto-pause
max(1, ceil(total ÷ rate)). Charged after the audit is saved: a run that fails costs nothing.
When the primary model returns a quota or capacity error, the request falls back to a second model rather than failing the job.
A response that arrives truncated is repaired where it can be, and salvaged for partial data where it cannot, so a cut-off reply still yields an audit rather than nothing.
Scorecards larger than five parameters are split into batches, scored separately and merged with the weights recomputed, which keeps a thirty-parameter scorecard from running into a response-length ceiling.
A URL that returns a web page rather than audio is caught and rejected : a share link that quietly serves a viewer page would otherwise be transcribed into a fabricated call.
callGeminiRaw · fallback on 503/429
सर, मैं आपकी शिकायत दर्ज कर देता हूँ।
Sir, I will log your complaint.
ஐயா, உங்கள் புகாரைப் பதிவு செய்கிறேன்.
This is the weakest part of the product and the section a serious buyer should read first.
| Criterion | QXAI |
|---|---|
| Upload many files at once | YesYesMulti-select. MP3, WAV, WEBM, M4A, OGG. |
| CSV of recording URLs | YesYesFetched over HTTP, including S3 links your bucket serves. |
| Per-job progress, retry, cancel | YesYesPer campaign and per job. |
| Rate limiting and auto-pause | YesYes |
| Whole-folder upload | NoNoYou select the files. There is no directory picker, so a nested folder tree has to be flattened first. |
| CRM or telephony integration | PartlyPartlyDialers, yes: any that posts a finished call to a URL. Documented setup for Exotel, Ozonetel, MyOperator, Frejun and Tata Smartflo; Knowlarity and iCallMate need the vendor to enable a post-call push. No CRM connectors, no OAuth, no marketplace app. |
| Push calls in via webhook | YesYesOne URL per dialer. Field names are mapped once from a real call; duration, disposition and agent filters, sampling and a daily cap decide what gets audited. |
| Customer-facing API | NoNoNo public API keys. Everything goes through the app today. |
| Scheduled or recurring imports | PartlyPartlyCalls from a dialer can be held and audited hourly or nightly. Uploaded batches are still started by a person. |
| Published throughput figures | Not claimedNot claimedSpeed depends on call length, scorecard size and upstream capacity. We have no benchmark you could check, so we quote no number. |