Vionis Telephony
Detection API.
Detect synthetic or human callers in stereo 8 kHz phone calls using acoustic synthesis artifacts, deep neural voice embeddings, conversational dynamics, and passive semantic probes.
Vionis provides three production model tiers: Flash on Cloudflare Workers, Turbo on CPU with Silero ONNX VAD and 6 evidence families, and Max fusing fine-tuned wav2vec2 XLS-R caller neural embeddings with Turbo. Requests are routed through https://tunnel.vionis.site and the edge gateway at https://flash.vionis.site.
| Model | Inference engine | Primary mechanisms | Default endpoint |
|---|---|---|---|
Turbo (Recommended) | CPU · ONNX Runtime | Silero ONNX VAD, 12 detectors across 6 evidence families (synthesis artifacts, dynamics, echo, semantic probes, physiology, provenance), 3-tier cascade | POST /turbo/detectPOST /turbo/explain |
Max | GPU / CPU · PyTorch | Fine-tuned wav2vec2 XLS-R caller acoustic model (12 speech crops resampled to 16 kHz) fused with Turbo via OR decision rule (FUSION_RULE=or) | POST /max/detectPOST /max/explain |
Flash | Cloudflare Worker (V8) | Zero-dependency JavaScript inference: energy VAD, reply timing/spread, spectral balance wander, silence transients, mouth clicks, degraded-line fallback tree | POST /detectPOST /explain |
Medium | Pass-through | Experimental balanced feature configuration | POST /medium/detectPOST /medium/explain |
Send a stereo call recording
Recordings must be stereo 16-bit PCM WAV at 8 kHz (or odd rates which are internally resampled). Maximum request body size is 25 MB across all formats.
Channel 0 is the Caller under evaluation. Channel 1 is the Agent, used strictly for conversation dynamics, reply latency distribution, and cross-channel echo. Channel 1 is never sent to a caller acoustic classifier because the agent voice is always synthetic and would leak the label.
Endpoints accept audio through any of the following formats:
- Raw binary WAV:
Content-Type: audio/wavwith binary WAV file in request body. - JSON with base64:
Content-Type: application/jsonwith{ "audio_base64": "..." }(also recognizesaudio,wav,b64). - Raw base64 text: Plain base64 string body.
- Multipart form data:
Content-Type: multipart/form-datawith audio inaudioorfilefield.
curl https://vionis.site/turbo/detect \ -H "Content-Type: audio/wav" \ --data-binary @call.wav{ "call_id": "call-001", "audio_base64": "<base64 of the complete stereo PCM WAV>", "sample_rate": 8000, "channels": 2}Server clients can call these routes without an API key. Cross-origin browser requests are restricted to this website; third-party web apps should proxy through their own server backend.
Verdict and diagnostic evidence
1. Verdict Route: POST /detect
Returns the binary caller classification and confidence score. To satisfy hackathon judge contracts where timeouts, non-200 responses, or missing boolean fields count as wrong answers, /detect always returns HTTP 200 with a boolean is_synthetic (falling back to false, 0.5 on unrecoverable error).
{ "is_synthetic": true, "confidence": 0.87}Confidence Semantics: confidence is confidence in the returned class, rather than always probability of synthetic speech (e.g. if is_synthetic: false with p_synthetic: 0.05, confidence is 0.95). Reported confidence is constrained to [0.02, 0.98] because unseen voices and carrier noise never justify absolute certainty.
2. Diagnostic Route: POST /explain
Returns the verdict plus complete model-specific evidence and feature breakdown:
{ "is_synthetic": false, "confidence": 0.95, "p_synthetic": 0.05, "threshold": 0.5, "tier_reached": 2, "latency_ms": 204.5, "families": { "A": { "name": "synthesis artifacts (DSP)", "score": 0.12, "weight": 0.25 }, "C": { "name": "interactional dynamics", "score": 0.08, "weight": 0.3 }, "D": { "name": "cross-channel coupling", "score": 0.05, "weight": 0.1 }, "E": { "name": "semantic probes", "score": 0.02, "weight": 0.15 }, "F": { "name": "physiology", "score": 0.04, "weight": 0.1 }, "G": { "name": "provenance archaeology", "score": 0.06, "weight": 0.1 } }, "notes": [], "evidence": [ "lower-quartile response latency 0.42 s", "12% of replies began faster than human reaction time", "noise floor -48.2 dB" ], "features": { "c1_lat_p25": 0.42, "c2_frac_sub_floor": 0.12, "g1_mulaw_grid_frac": 0.942, "g3_floor_db": -48.2 }}{ "is_synthetic": true, "confidence": 0.89, "p_synthetic": 0.89, "threshold": 0.5, "latency_ms": 312.4, "fusion": { "rule": "or", "components": { "neural": { "is_synthetic": true, "confidence": 0.89, "p_synthetic": 0.89, "p_fake_raw": 0.82, "threshold": 0.76, "windows": 8, "window_scores": [ 0.78, 0.85, 0.81, 0.84 ], "caller_speech_seconds": 14.2, "used": true }, "turbo": { "is_synthetic": false, "score_centred": 0.42, "used": true } } }}| Field | Meaning |
|---|---|
is_synthetic | Boolean classification: true indicates synthetic/AI caller, false indicates human caller. |
confidence | Confidence in the returned class, bounded to [0.02, 0.98] to reflect realistic telephony uncertainty. |
p_synthetic | Continuous calibrated probability that caller speech is synthetic. |
threshold | Model decision threshold (scores at or above threshold are classified as synthetic). |
tier_reached | (Turbo) Compute cascade tier reached: 0 (turn timing & noise floor), 1 (windowed acoustics), 2 (full depth). |
families | (Turbo) Six independent evidence families: A (synthesis artifacts), C (dynamics), D (coupling), E (semantic probes), F (physiology), G (provenance), with score and weight. |
evidence | (Turbo) Plain-language forensic statements of key physical and conversational measurements. |
fusion | (Max) Fusion configuration: rule ('or' default) and breakdown of 'neural' (wav2vec2 XLS-R) and 'turbo' components. |
route / model | (Flash) Line-quality route ('clean' or degraded-line 'fallback') and model version string. |
line | (Flash) Band-edge energy (all_edge_db) and band-edge signal-to-noise ratio (snr_edge_db). |
features | Key-value dictionary of numerical measurements computed by the feature extractor. |
replies_measured | Number of caller responses measured against agent turns. |
latency_ms / wall_ms | Execution time in milliseconds for model inference. |
audio | Duration in seconds, source sample rate, and channel count (must be 2). |
analysis_model | Selected model identifier: 'turbo', 'max', 'flash', or 'medium'. |
subject_channel / channel_map | Caller is Channel 0; Agent is Channel 1. |
request_id | Unique UUID for logging, tracing, and audit inspection. |
A human prediction does not verify caller identity. Very noisy audio, mono files, or callers who deliberately simulate human hesitation can impact accuracy.
Resilience and error codes
The /detect endpoint returns HTTP 200 with { "is_synthetic": false, "confidence": 0.5 } and an x-{model}-error header when an error occurs, ensuring compliance with automated judge harnesses. The /explain routes return authentic HTTP error status codes with structured JSON error details for development and debugging:
{ "error": { "code": "INVALID_AUDIO", "message": "audio_base64 must contain base64-encoded WAV bytes." }, "request_id": "7f4c9b3a-..."}INVALID_JSON / INVALID_MULTIPART / INVALID_MODELMalformed JSON syntax, missing audio field, or unsupported model parameter.
CROSS_ORIGIN_REQUESTBrowser requests must originate from this website; server-to-server integrations require no origin header.
AUDIO_TOO_LARGERequest body exceeds the 25 MB payload limit.
UNSUPPORTED_MEDIA_TYPEContent-Type must be audio/wav, application/json, or multipart/form-data.
INVALID_AUDIO / INVALID_REQUEST / {MODEL}_AUDIO_REJECTEDAudio is not a valid 16-bit PCM stereo WAV, or declared sample_rate/channels conflict with header.
{MODEL}_UNAVAILABLE / INVALID_{MODEL}_RESPONSEUpstream model backend is offline, unreachable, or returned malformed data.
SERVICE_UNAVAILABLEModel service is warming up or temporarily degraded.
{MODEL}_TIMEOUTInference did not complete within the 60-second execution deadline.
GET /health checks live model backend status across all inference services, returning HTTP 200 when ready and HTTP 503 when degraded or unreachable.
Test your audio
Submit a recording to any Vionis endpoint and inspect the live JSON response.
Choose a WAV recording or supply its base64 bytes.