How it works
- You enable
deepfake_detectionwhen dialing or answering a call. - Telnyx streams the remote party’s audio to the detection service.
- The service analyzes audio frames and returns a result within the configured timeout.
- You receive a
call.deepfake_detection.resultwebhook with the classification, or acall.deepfake_detection.errorwebhook if something went wrong.
Configuration parameters
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
enabled | boolean | false | — | Whether deepfake detection is enabled. |
timeout | integer | 15 | 5–60 | Maximum seconds to wait for a detection result before timing out. |
rtp_timeout | integer | 30 | 5–120 | Maximum seconds to wait for RTP audio. If no audio arrives within this window, detection stops with an error. |
Enabling on an outbound call
Include thedeepfake_detection object when creating an outbound call via the Dial command:
curl -X POST https://api.telnyx.com/v2/calls \
-H "Authorization: Bearer $TELNYX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"connection_id": "7267xxxxxxxxxxxxxx",
"from": "+18005550101",
"to": "+18005550100",
"deepfake_detection": {"enabled": true}
}'
import Telnyx from 'telnyx';
const client = new Telnyx({ apiKey: process.env['TELNYX_API_KEY'] });
const response = await client.calls.dial({
connection_id: '7267xxxxxxxxxxxxxx',
from: '+18005550101',
to: '+18005550100',
deepfake_detection: { enabled: true },
});
console.log(response.data);
from telnyx import Telnyx
client = Telnyx(api_key=os.environ["TELNYX_API_KEY"])
response = client.calls.dial(
connection_id="7267xxxxxxxxxxxxxx",
from_="+18005550101",
to="+18005550100",
deepfake_detection={"enabled": True},
)
print(response.data)
require "telnyx"
client = Telnyx::Client.new(api_key: ENV["TELNYX_API_KEY"])
response = client.calls.dial(
connection_id: "7267xxxxxxxxxxxxxx",
from: "+18005550101",
to: "+18005550100",
deepfake_detection: { enabled: true },
)
puts response.data
import com.telnyx.sdk.*;
import com.telnyx.sdk.api.CallCommandsApi;
import com.telnyx.sdk.model.*;
CallCommandsApi api = new CallCommandsApi(new ApiClient().setApiKey(System.getenv("TELNYX_API_KEY")));
CallRequest req = new CallRequest()
.connectionId("7267xxxxxxxxxxxxxx")
.from("+18005550101")
.to("+18005550100")
.deepfakeDetection(new DeepfakeDetection().enabled(true));
api.dial(req);
import telnyx "github.com/team-telnyx/telnyx-go"
client := telnyx.NewClient(os.Getenv("TELNYX_API_KEY"))
response, _ := client.Calls.Dial(ctx, &telnyx.CallDialParams{
ConnectionID: "7267xxxxxxxxxxxxxx",
From: "+18005550101",
To: "+18005550100",
DeepfakeDetection: &telnyx.DeepfakeDetection{Enabled: true},
})
fmt.Println(response)
$telnyx = new \Telnyx\Client(getenv('TELNYX_API_KEY'));
$response = $telnyx->calls->dial([
'connection_id' => '7267xxxxxxxxxxxxxx',
'from' => '+18005550101',
'to' => '+18005550100',
'deepfake_detection' => ['enabled' => true],
]);
echo $response->data;
Enabling on an inbound call
Adddeepfake_detection to the Answer command when picking up an incoming call:
curl -X POST https://api.telnyx.com/v2/calls/$CALL_CONTROL_ID/actions/answer \
-H "Authorization: Bearer $TELNYX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"deepfake_detection": {"enabled": true}}'
import Telnyx from 'telnyx';
const client = new Telnyx({ apiKey: process.env['TELNYX_API_KEY'] });
const response = await client.calls.answer(callControlId, {
deepfake_detection: { enabled: true },
});
console.log(response.data);
from telnyx import Telnyx
client = Telnyx(api_key=os.environ["TELNYX_API_KEY"])
response = client.calls.answer(
call_control_id,
deepfake_detection={"enabled": True},
)
print(response.data)
require "telnyx"
client = Telnyx::Client.new(api_key: ENV["TELNYX_API_KEY"])
response = client.calls.answer(
call_control_id,
deepfake_detection: { enabled: true },
)
puts response.data
import com.telnyx.sdk.*;
import com.telnyx.sdk.api.CallCommandsApi;
import com.telnyx.sdk.model.*;
CallCommandsApi api = new CallCommandsApi(new ApiClient().setApiKey(System.getenv("TELNYX_API_KEY")));
AnswerRequest req = new AnswerRequest()
.deepfakeDetection(new DeepfakeDetection().enabled(true));
api.answer(callControlId, req);
import telnyx "github.com/team-telnyx/telnyx-go"
client := telnyx.NewClient(os.Getenv("TELNYX_API_KEY"))
response, _ := client.Calls.Answer(ctx, callControlID, &telnyx.CallAnswerParams{
DeepfakeDetection: &telnyx.DeepfakeDetection{Enabled: true},
})
fmt.Println(response)
$telnyx = new \Telnyx\Client(getenv('TELNYX_API_KEY'));
$response = $telnyx->calls->answer($callControlId, [
'deepfake_detection' => ['enabled' => true],
]);
echo $response->data;
Handling the result webhook
When detection completes, you receive acall.deepfake_detection.result webhook:
{
"record_type": "event",
"event_type": "call.deepfake_detection.result",
"id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0",
"occurred_at": "2025-06-15T14:30:27.521992Z",
"payload": {
"call_control_id": "v3:MdI91X4lWFEs7IgbBEOT9M4AigoY08M0WWZFISt1Yw2axZ_IiE4pqg",
"connection_id": "7267xxxxxxxxxxxxxx",
"call_leg_id": "428c31b6-7af4-4bcb-b7f5-5013ef9657c1",
"call_session_id": "428c31b6-7af4-4bcb-b7f5-5013ef9657c1",
"client_state": "aGF2ZSBhIG5pY2UgZGF5ID1d",
"result": "fake",
"score": 0.87,
"consistency": 94.5
}
}
Result fields
| Field | Type | Description |
|---|---|---|
result | string | real — human voice detected. fake — AI-generated voice detected. silence_timeout — no analyzable speech before timeout. |
score | float | null | Probability the audio is AI-generated, from 0.0 (likely real) to 1.0 (likely deepfake). Null for silence_timeout. |
consistency | float | null | Percentage (0–100) indicating how consistently the model classified the audio across frames. Values above 90% indicate high confidence. Null for silence_timeout. |
Handling errors
If detection fails, you receive acall.deepfake_detection.error webhook:
{
"record_type": "event",
"event_type": "call.deepfake_detection.error",
"id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0",
"occurred_at": "2025-06-15T14:30:27.521992Z",
"payload": {
"call_control_id": "v3:MdI91X4lWFEs7IgbBEOT9M4AigoY08M0WWZFISt1Yw2axZ_IiE4pqg",
"connection_id": "7267xxxxxxxxxxxxxx",
"call_leg_id": "428c31b6-7af4-4bcb-b7f5-5013ef9657c1",
"call_session_id": "428c31b6-7af4-4bcb-b7f5-5013ef9657c1",
"client_state": "aGF2ZSBhIG5pY2UgZGF5ID1d",
"error_message": "detection_timeout"
}
}
Error types
| Error | Description |
|---|---|
detection_timeout | No detection result received within the configured timeout. |
rtp_timeout | No RTP audio received within the configured rtp_timeout. |
dfd_connection_error | Could not connect to the detection service. |
dfd_stream_error | Audio stream to the detection service failed. |
Example: screening inbound calls
This example webhook server answers inbound calls with deepfake detection enabled and takes action based on the result.const express = require("express");
const Telnyx = require("telnyx");
const app = express();
app.use(express.json());
const client = new Telnyx({
apiKey: process.env.TELNYX_API_KEY,
});
// Answer incoming calls with deepfake detection enabled
app.post("/webhooks/call-initiated", async (req, res) => {
const { call_control_id } = req.body.payload;
await client.calls.actions.answer(call_control_id, {
deepfake_detection: {
enabled: true,
timeout: 15,
rtp_timeout: 30,
},
});
res.sendStatus(200);
});
// Handle deepfake detection results
app.post("/webhooks/deepfake-result", async (req, res) => {
const { call_control_id, result, score, consistency } =
req.body.payload;
console.log(
`Detection result: ${result}, score: ${score}, consistency: ${consistency}%`
);
if (result === "fake" && score > 0.8) {
// High-confidence deepfake — hang up or route to fraud queue
await client.calls.actions.hangup(call_control_id, {});
console.log("Deepfake detected — call terminated.");
} else if (result === "real") {
// Human caller — proceed normally
console.log("Human caller verified.");
}
// silence_timeout — caller didn't speak; handle as needed
res.sendStatus(200);
});
// Handle detection errors gracefully
app.post("/webhooks/deepfake-error", async (req, res) => {
const { call_control_id, error_message } = req.body.payload;
console.log(`Deepfake detection error: ${error_message}`);
// Continue the call normally if detection fails
res.sendStatus(200);
});
app.listen(3000, () => console.log("Webhook server running on port 3000"));
import os
from flask import Flask, request
from telnyx import Telnyx
app = Flask(__name__)
client = Telnyx(api_key=os.environ["TELNYX_API_KEY"])
@app.route("/webhooks/call-initiated", methods=["POST"])
def call_initiated():
call_control_id = request.json["payload"]["call_control_id"]
client.calls.actions.answer(
call_control_id,
deepfake_detection={
"enabled": True,
"timeout": 15,
"rtp_timeout": 30,
},
)
return "", 200
@app.route("/webhooks/deepfake-result", methods=["POST"])
def deepfake_result():
payload = request.json["payload"]
call_control_id = payload["call_control_id"]
result = payload["result"]
score = payload.get("score")
consistency = payload.get("consistency")
print(f"Detection result: {result}, score: {score}, consistency: {consistency}%")
if result == "fake" and score is not None and score > 0.8:
# High-confidence deepfake — hang up or route to fraud queue
client.calls.actions.hangup(call_control_id)
print("Deepfake detected — call terminated.")
elif result == "real":
# Human caller — proceed normally
print("Human caller verified.")
# silence_timeout — caller didn't speak; handle as needed
return "", 200
@app.route("/webhooks/deepfake-error", methods=["POST"])
def deepfake_error():
payload = request.json["payload"]
error_message = payload["error_message"]
print(f"Deepfake detection error: {error_message}")
# Continue the call normally if detection fails
return "", 200
if __name__ == "__main__":
app.run(port=3000)
require "sinatra"
require "json"
require "telnyx"
client = Telnyx::Client.new(api_key: ENV["TELNYX_API_KEY"])
# Answer incoming calls with deepfake detection enabled
post "/webhooks/call-initiated" do
payload = JSON.parse(request.body.read)["payload"]
call_control_id = payload["call_control_id"]
client.calls.actions.answer(
call_control_id,
deepfake_detection: { enabled: true, timeout: 15, rtp_timeout: 30 },
)
status 200
end
# Handle deepfake detection results
post "/webhooks/deepfake-result" do
payload = JSON.parse(request.body.read)["payload"]
call_control_id = payload["call_control_id"]
result = payload["result"]
score = payload["score"]
consistency = payload["consistency"]
puts "Detection result: #{result}, score: #{score}, consistency: #{consistency}%"
if result == "fake" && score && score > 0.8
# High-confidence deepfake — hang up or route to fraud queue
client.calls.actions.hangup(call_control_id)
puts "Deepfake detected — call terminated."
elsif result == "real"
# Human caller — proceed normally
puts "Human caller verified."
end
# silence_timeout — caller didn't speak; handle as needed
status 200
end
# Handle detection errors gracefully
post "/webhooks/deepfake-error" do
payload = JSON.parse(request.body.read)["payload"]
error_message = payload["error_message"]
puts "Deepfake detection error: #{error_message}"
# Continue the call normally if detection fails
status 200
end
package main
import (
"context"
"encoding/json"
"log"
"net/http"
telnyx "github.com/team-telnyx/telnyx-go/v4"
"github.com/team-telnyx/telnyx-go/v4/option"
)
var client = telnyx.NewClient(option.WithAPIKeyFromEnv())
type webhookRequest struct {
Payload map[string]any `json:"payload"`
}
func callInitiated(w http.ResponseWriter, r *http.Request) {
var req webhookRequest
json.NewDecoder(r.Body).Decode(&req)
callControlID := req.Payload["call_control_id"].(string)
// Answer incoming call with deepfake detection enabled
client.Calls.Actions.Answer(context.TODO(), callControlID, telnyx.CallActionAnswerParams{
DeepfakeDetection: telnyx.F(telnyx.CallActionAnswerParamsDeepfakeDetection{
Enabled: telnyx.F(true),
Timeout: telnyx.F(int64(15)),
RTPTimeout: telnyx.F(int64(30)),
}),
})
w.WriteHeader(http.StatusOK)
}
func deepfakeResult(w http.ResponseWriter, r *http.Request) {
var req webhookRequest
json.NewDecoder(r.Body).Decode(&req)
p := req.Payload
callControlID := p["call_control_id"].(string)
result := p["result"].(string)
score, _ := p["score"].(float64)
consistency, _ := p["consistency"].(float64)
log.Printf("Detection result: %s, score: %.2f, consistency: %.1f%%", result, score, consistency)
if result == "fake" && score > 0.8 {
// High-confidence deepfake — hang up or route to fraud queue
client.Calls.Actions.Hangup(context.TODO(), callControlID, telnyx.CallActionHangupParams{})
log.Println("Deepfake detected — call terminated.")
} else if result == "real" {
// Human caller — proceed normally
log.Println("Human caller verified.")
}
// silence_timeout — caller didn't speak; handle as needed
w.WriteHeader(http.StatusOK)
}
func deepfakeError(w http.ResponseWriter, r *http.Request) {
var req webhookRequest
json.NewDecoder(r.Body).Decode(&req)
errorMessage := req.Payload["error_message"].(string)
log.Printf("Deepfake detection error: %s", errorMessage)
// Continue the call normally if detection fails
w.WriteHeader(http.StatusOK)
}
func main() {
http.HandleFunc("/webhooks/call-initiated", callInitiated)
http.HandleFunc("/webhooks/deepfake-result", deepfakeResult)
http.HandleFunc("/webhooks/deepfake-error", deepfakeError)
log.Println("Webhook server running on port 3000")
log.Fatal(http.ListenAndServe(":3000", nil))
}
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpExchange;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.telnyx.sdk.client.TelnyxClient;
import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient;
import com.telnyx.sdk.models.calls.CallActionAnswerParams;
import com.telnyx.sdk.models.calls.CallActionHangupParams;
import java.io.*;
import java.net.InetSocketAddress;
public class DeepfakeScreening {
static final TelnyxClient client = TelnyxOkHttpClient.fromEnv();
static final Gson gson = new Gson();
static JsonObject parsePayload(HttpExchange exchange) throws IOException {
String body = new String(exchange.getRequestBody().readAllBytes());
return gson.fromJson(body, JsonObject.class).getAsJsonObject("payload");
}
static void respond(HttpExchange exchange, int code) throws IOException {
exchange.sendResponseHeaders(code, -1);
exchange.close();
}
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress(3000), 0);
// Answer incoming calls with deepfake detection enabled
server.createContext("/webhooks/call-initiated", exchange -> {
JsonObject payload = parsePayload(exchange);
String callControlId = payload.get("call_control_id").getAsString();
client.calls().actions().answer(
callControlId,
CallActionAnswerParams.builder()
.deepfakeDetection(CallActionAnswerParams.DeepfakeDetection.builder()
.enabled(true)
.timeout(15L)
.rtpTimeout(30L)
.build())
.build());
respond(exchange, 200);
});
// Handle deepfake detection results
server.createContext("/webhooks/deepfake-result", exchange -> {
JsonObject payload = parsePayload(exchange);
String callControlId = payload.get("call_control_id").getAsString();
String result = payload.get("result").getAsString();
double score = payload.has("score") && !payload.get("score").isJsonNull()
? payload.get("score").getAsDouble() : 0;
double consistency = payload.has("consistency") && !payload.get("consistency").isJsonNull()
? payload.get("consistency").getAsDouble() : 0;
System.out.printf("Detection result: %s, score: %.2f, consistency: %.1f%%%n",
result, score, consistency);
if ("fake".equals(result) && score > 0.8) {
// High-confidence deepfake — hang up or route to fraud queue
client.calls().actions().hangup(
callControlId,
CallActionHangupParams.builder().build());
System.out.println("Deepfake detected — call terminated.");
} else if ("real".equals(result)) {
// Human caller — proceed normally
System.out.println("Human caller verified.");
}
// silence_timeout — caller didn't speak; handle as needed
respond(exchange, 200);
});
// Handle detection errors gracefully
server.createContext("/webhooks/deepfake-error", exchange -> {
JsonObject payload = parsePayload(exchange);
String errorMessage = payload.get("error_message").getAsString();
System.out.println("Deepfake detection error: " + errorMessage);
// Continue the call normally if detection fails
respond(exchange, 200);
});
server.start();
System.out.println("Webhook server running on port 3000");
}
}
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Telnyx\Client;
$client = new Client(apiKey: getenv('TELNYX_API_KEY'));
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$payload = json_decode(file_get_contents('php://input'), true)['payload'] ?? [];
$callControlId = $payload['call_control_id'] ?? '';
switch ($uri) {
// Answer incoming calls with deepfake detection enabled
case '/webhooks/call-initiated':
$client->calls->actions->answer(
callControlID: $callControlId,
deepfakeDetection: [
'enabled' => true,
'timeout' => 15,
'rtp_timeout' => 30,
],
);
break;
// Handle deepfake detection results
case '/webhooks/deepfake-result':
$result = $payload['result'];
$score = $payload['score'] ?? null;
$consistency = $payload['consistency'] ?? null;
error_log("Detection result: {$result}, score: {$score}, consistency: {$consistency}%");
if ($result === 'fake' && $score !== null && $score > 0.8) {
// High-confidence deepfake — hang up or route to fraud queue
$client->calls->actions->hangup(callControlID: $callControlId);
error_log('Deepfake detected — call terminated.');
} elseif ($result === 'real') {
// Human caller — proceed normally
error_log('Human caller verified.');
}
// silence_timeout — caller didn't speak; handle as needed
break;
// Handle detection errors gracefully
case '/webhooks/deepfake-error':
$errorMessage = $payload['error_message'] ?? 'unknown';
error_log("Deepfake detection error: {$errorMessage}");
// Continue the call normally if detection fails
break;
}
http_response_code(200);
Best practices
- Set appropriate timeouts. The default 15-second detection timeout works well for most calls. Increase it if callers may take longer to start speaking (e.g., IVR prompts on the remote end).
- Use
scoreandconsistencytogether. A high score with high consistency is a strong signal. A high score with low consistency may warrant additional verification rather than an immediate hangup. - Handle errors gracefully. Detection errors should not block the call. Design your application to fall through to normal call handling when detection is unavailable.