Building Blocks / Voice
Detection (AMD / Beep / Screening)
Person, machine, or beep, on our dialer or your carrier.
This block is the Detection API. The full product reference is the Detection API reference. This page is the short version: when to use it, one working request, and its limits. There is no widget to embed.
When to use this vs REST
Use Detection when you place calls on your own carrier and need to know whether a person, voicemail, or beep answered. If you dial with Drop Cowboy®, detection is already built in and you do not need this.
Do not rebuild
- Answering machine detection or beep timing.
- Webhook signing and retries.
Drop-in
Open a WebSocket from your server to wss://detect.dropcowboy.com/carrier/ws with your Detection API key, send a welcome, then stream 8 kHz mono audio. Person, voicemail, and beep events come back on the socket and, if you ask, as signed webhooks. If you already dial with Drop Cowboy, detection is built in.
const WebSocket = require('ws');
const ws = new WebSocket('wss://detect.dropcowboy.com/carrier/ws', {
headers: { Authorization: 'Bearer ' + process.env.DETECTION_API_KEY }
});
ws.on('open', () => ws.send(JSON.stringify({
type: 'welcome',
payload: { call_id: 'a9c3e8f1-4b2d-4a7c-8e9b-1c2d3e4f5a6b', audio_encoding: 'pcm16', sample_rate_hz: 8000, strategy: 'standard' }
})));
// After the ready event, send 20 ms binary frames of 8 kHz mono PCM16 audio.
ws.on('message', (data, isBinary) => {
if (isBinary) return;
const ev = JSON.parse(data.toString());
if (ev.event === 'detection') routeOn(ev.payload.type, ev.payload.confidence);
if (ev.event === 'beep') startVoicemailPlayback();
});
With Twilio
Twilio <Stream> cannot send headers, so your Detection API key goes in a <Parameter>. With webhook_url set, events arrive as signed webhooks instead of on the socket. No relay or transcoder on your side.
<Response>
<Start>
<Stream url="wss://detect.dropcowboy.com/carrier/ws/twilio" track="inbound_track">
<Parameter name="api_key" value="YOUR_DETECTION_API_KEY"/>
<Parameter name="webhook_url" value="https://hooks.example.com/detection"/>
<Parameter name="webhook_events" value="beep,detection,close"/>
</Stream>
</Start>
<Dial>+15125550148</Dial>
</Response>
Verify webhooks
Webhooks carry a timestamp and an HMAC-SHA256 signature made with your Detection API key over timestamp.rawBody. Reject anything older than five minutes.
// Mount with express.raw({ type: 'application/json' }) so req.body is the raw bytes.
const crypto = require('crypto');
function verifyDetectionWebhook(req) {
const ts = req.get('X-Timestamp');
const sig = req.get('X-Signature') || '';
if (!ts || Math.abs(Date.now() - Number(ts)) > 5 * 60 * 1000) return false;
const expected = 'v1=hmac-sha256,' + crypto.createHmac('sha256', process.env.DETECTION_API_KEY)
.update(ts + '.' + req.body).digest('hex');
const a = Buffer.from(sig);
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
JS API / HTML tag
No browser widget. The WebSocket protocol:
| Frame | What it does |
|---|---|
{ type: "welcome", payload: { audio_encoding, sample_rate_hz, strategy, webhook } } |
First text frame. audio_encoding is pcm16 or mulaw at 8000 Hz. strategy is standard, beep_only, or live_check. webhook is optional { url, events, headers }. |
binary frame |
Send 20 ms frames of 8 kHz mono audio after the ready event. |
{ event: "detection", payload: { type, confidence, is_final } } |
type is live_person, voicemail, or silence. Refinements can follow the first result. |
{ event: "beep", payload: { timestamp_ms } } |
Voicemail beep heard. Start your message now. |
{ event: "close" } |
Session ended. Send {"command":"stop"} to end it yourself. |
Auth and scopes
Detection API key, server-side only. Send it as Authorization: Bearer on the WebSocket upgrade, or as <Parameter name="api_key"> on a Twilio <Stream>. No site token.
The Detection API key is separate from your x-key/x-secret pair. Drop Cowboy issues it; there is no self-serve screen for it yet. Keep it on your server.
Limits
- Each Detection API key has a concurrent session cap. Past it, the upgrade is refused with 503.
- When the fleet is at capacity the upgrade is refused with 503 at_capacity. Treat it as "no result" and continue the call.
- The edge allows 2000 requests per IP per 5 minutes.
- Do not reconnect mid-call. A new socket starts a new session with no history.
- Audio is 8 kHz mono, pcm16 or mulaw, in 20 ms frames.
- On the Twilio path, results go to your webhook when one is set, not back on the socket.
- The browser monitor script is optional, for showing results in a page. It is not generally available yet; use the carrier WebSocket.
Related REST
- Detection API reference - full protocol reference