Docs / API / Streaming guide

AMD Detection WebSocket Streaming Protocol

The AMDY.IO detection backend accepts real-time audio over WebSocket and returns answer machine classification results as frames arrive. This guide documents the verified streaming protocol: endpoint, authentication, audio format, chunking strategy, config frames, and response structure. Integrate this protocol to stream live call audio and receive HUMAN or MACHINE classifications within seconds.

Installing a dialer integration? The Asterisk install guide and FreeSWITCH guide wrap this protocol with prebuilt scripts. This page documents the protocol itself for custom integrations.

What is the WebSocket endpoint?

The detection endpoint is:

ws://api.amdy.io:2700

This is a plain WebSocket (ws) endpoint on port 2700. Connections are accepted only from IP addresses registered to your AMDY account. The registration happens automatically when you run any install script, or you can call POST /api/v1/ips/register directly (see API reference).

TLS / wss endpoint: Only the plain ws:// endpoint is documented in verified sources. If you require a TLS-secured WebSocket (wss), contact support for integration access.

How do I authenticate?

Send your API key in the X-API-Key header on the WebSocket upgrade request:

X-API-Key: amd_live_<your-key-here>

The key is stored on your detection server at /etc/amdy/api-key (mode 600). API keys always start with amd_live_ followed by 24 or 32 hex characters.

FreeSWITCH exception: The mod_audio_fork module cannot send custom HTTP headers on the WebSocket upgrade. FreeSWITCH connections carry no X-API-Key header and are authorized by IP allowlist only. See the FreeSWITCH install guide.

What audio format is required?

The detection backend expects:

ParameterValue
Sample rate8000 Hz
Bit depth16-bit
Channelsmono
Encodingraw PCM (signed little-endian)

8000 samples at 16-bit mono equals 16,000 bytes per second. Resample higher-rate audio before streaming. The browser-based test client in the filesearch app resamples to 8 kHz and scales float samples to Int16 range (multiply by 32767, clamp to int16 bounds).

What is the config frame?

Send a JSON text frame immediately after the WebSocket connection opens, before any audio:

{"config": {"sample_rate": 8000, "VID": "<caller-id-or-unknown>"}}

The VID field identifies the call. Set it to the caller ID name, call unique ID, or any identifier you want to appear in detection logs. If empty or omitted, AMDY records it as Unknown. The sample_rate field is required in the canonical form.

Optional config fields (documented but not code-verified in this repo): phone, country_code or cc, caller_id or callerid, max_detection_time (0.5 to 10 seconds, default 8), immediate_detection, stage_results. Contact support for details on optional fields.

How do I send audio chunks?

Send audio as binary WebSocket frames. The verified chunking strategy from the Python detection client:

Elapsed timeAction
0.7sSend buffered audio
1.0sSend buffered audio
2.0sSend buffered audio
3.0sSend buffered audio
After 3.0sSend when buffer reaches 8000 bytes (size-based fallback)
5.0sGlobal timeout. Send EOF, expect final result.

At 8000 bytes per chunk after 3 seconds, you send roughly one chunk per second (8000 samples = 1 second of audio at 8 kHz 16-bit mono). The Python client reads from EAGI file descriptor 3 in 9500-byte blocks and buffers until the time or size threshold triggers a send.

EOF frame: Send a JSON text frame {"eof": 1} to signal end-of-stream and force a final classification result. The detection backend responds once per sent chunk, then sends a final result after EOF.

What does the response look like?

The backend sends one text frame per received audio chunk. Each response has the format:

CLASSIFICATION-DURATION-CONFIDENCE

Example: HUMAN-4.50-0.9950 means classification is HUMAN, detection took 4.50 seconds, confidence is 99.50%.

Primary classifications:

  • HUMAN — live person answered
  • AMD or MACHINE — answer machine detected
  • Empty or unrecognized — keep streaming, no final result yet

The detection server supports 42+ classification tokens (including WELCOMEVMAMD, PLVMSAMD, SILENCEAMD, and others from the v4.2 taxonomy). The full taxonomy is documented in the API reference but not code-verified in this repo. On any error, the Python client defaults to HUMAN for call safety.

How do channel variables get set?

After the detection completes, the Python AGI script sets three channel variables in Asterisk:

VariableValuesMeaning
AMDSTATUSHUMAN, MACHINE, HANGUP, NOTSUREOverall result
AMDCAUSEHUMAN, MACHINE, CONNECTION_ERROR, PROCESSING_ERROR, NO_AUDIO, AUDIO_TIMEOUT, NO_AUDIO_TIMEOUT, FATAL_ERRORReason for the result
AMDSTATS(raw response string)Full detection backend response

FreeSWITCH sets amdy_result, amdy_cause, and amdy_stats with equivalent values. On any connection or processing error, the result defaults to HUMAN to avoid dropping live calls.

Frequently asked questions

Can I use wss:// instead of ws://?

Only the plain ws://api.amdy.io:2700 endpoint is documented in verified sources. If your integration requires TLS-secured WebSocket (wss), contact support for access.

How do I authenticate from FreeSWITCH?

The mod_audio_fork module cannot send custom headers. FreeSWITCH connections are authorized by IP allowlist only. Your API key is used for the one-time IP registration call, then the IP itself authorizes the WebSocket.

What if I need to resample audio?

Resample to 8 kHz, 16-bit mono PCM before streaming. The browser test client uses the Web Audio API OfflineAudioContext to resample, then scales float samples to Int16 (multiply by 32767, clamp to int16 range).

What happens on timeout or error?

The Python client sets AMDSTATUS=NOTSURE with AMDCAUSE indicating the error (CONNECTION_ERROR, PROCESSING_ERROR, NO_AUDIO, AUDIO_TIMEOUT, etc.). For call safety, the default is to treat errors as HUMAN so the call reaches an agent.

Can I get more details on the 42+ classification tokens?

The full v4.2 taxonomy (WELCOMEVMAMD, PLVMSAMD, SILENCEAMD, etc.) is documented in the API reference. The detection server source is not in this repository. Contact support for the complete classification guide.

Ready to integrate?

Test your integration in the AMDY portal. Generate an API key, register your server IP, and stream test audio to the detection endpoint.

Open AMDY Portal

Support

Questions about the streaming protocol? Email [email protected] with your integration details (audio format, chunking strategy, error logs).