Injection Detection
curl --request POST \
--url https://api.deepidv.com/v1/igaming/injectionimport requests
url = "https://api.deepidv.com/v1/igaming/injection"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.deepidv.com/v1/igaming/injection', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.deepidv.com/v1/igaming/injection",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.deepidv.com/v1/igaming/injection"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.deepidv.com/v1/igaming/injection")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.deepidv.com/v1/igaming/injection")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_body{
"verdict": "HIT",
"action": "block",
"confidence": 12,
"escalation": null
}
{
"verdict": "CLEAR",
"action": "allow",
"confidence": 91,
"escalation": null
}
{
"verdict": "UNAVAILABLE",
"action": "allow",
"confidence": null,
"escalation": null
}
iGaming Checks
Injection Detection
Detect virtual cameras, emulators, and injected media during liveness capture
POST
/
v1
/
igaming
/
injection
Injection Detection
curl --request POST \
--url https://api.deepidv.com/v1/igaming/injectionimport requests
url = "https://api.deepidv.com/v1/igaming/injection"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.deepidv.com/v1/igaming/injection', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.deepidv.com/v1/igaming/injection",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.deepidv.com/v1/igaming/injection"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.deepidv.com/v1/igaming/injection")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.deepidv.com/v1/igaming/injection")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_body{
"verdict": "HIT",
"action": "block",
"confidence": 12,
"escalation": null
}
{
"verdict": "CLEAR",
"action": "allow",
"confidence": 91,
"escalation": null
}
{
"verdict": "UNAVAILABLE",
"action": "allow",
"confidence": null,
"escalation": null
}
POST /v1/igaming/injection
injection-detection step configuration and persists its result to the session.
This check fails soft. If an internal error occurs, or neither
device_integrity nor media_source is supplied, it returns 200 with
verdict: "UNAVAILABLE" and action: "allow" rather than blocking or
erroring. (frame_timing on its own does not count as a signal.)Unlike the other iGaming checks, this endpoint does not skip when the
session’s workflow has no
INJECTION_DETECTION step. It scores the supplied
signals with the default config (action_on_detection: block,
automation_handling: block, confidence_threshold: 70) and can fail the
session. Only call it on sessions whose workflow includes the step.Request
Headers
| Header | Required | Description |
|---|---|---|
x-api-key | Yes | Your API key |
Content-Type | Yes | application/json |
Body parameters
Bodies use snake_case field names — there are no camelCase aliases.| Parameter | Type | Required | Description |
|---|---|---|---|
session_id | string | Yes | The session to score |
device_integrity | object | No | Injection signal group — see below |
media_source | object | No | Injection signal group — see below |
frame_timing | object | No | Injection signal group — see below |
| Field | Type | Description |
|---|---|---|
pass | boolean | Whether this signal group passed on the client. false is a hard hit (see below) |
score | number | Trust score for this group, 0–100 — higher means cleaner. A missing score counts as 50 (neutral) |
signals | string[] | Named indicators observed (empty array if none). Non-empty device_integrity.signals with pass: true still produces a HIT |
How the score is resolved
- Hard hits.
media_source.pass: falseresolves to the step’saction_on_detection;device_integrity.pass: falseresolves toautomation_handling(ignore→allow). If both fire, the more severe action wins.confidencein the response is that group’sscore. - Soft score. Otherwise
confidence = round(0.6 × media_source.score + 0.4 × frame_timing.score). If it is belowconfidence_threshold(default70), the verdict isHITwithaction_on_detection.device_integrity.scoredoes not enter this average. - Automation soft signals. If
device_integrity.signalsis non-empty (even withpass: true) andautomation_handlingisn’tignore, the verdict becomesHITand the action is raised toautomation_handlingwhen that is more severe. - A
step-upaction is downgraded toflagunless the step configures anescalation_type.
90–100). Sending score: 8 for a clean capture yields confidence: 25 and a block under the default threshold.
Collecting the signals
The server scores what your client reports; how you derivepass, score, and signals is up to your capture code. Typical sources:
| Group | What clients usually measure |
|---|---|
device_integrity | Automation and emulator markers — navigator.webdriver, headless user agents, missing plugins/languages, rooted or emulated devices |
media_source | Whether the active camera is a physical device — virtual-camera labels (OBS, ManyCam, etc.), injected MediaStream tracks, screen-capture sources |
frame_timing | Regularity of frame delivery — implausibly uniform or implausibly fast cadence suggests a synthetic stream |
Example request
curl -X POST https://api.deepidv.com/v1/igaming/injection \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"session_id": "b8991ba9-2566-4fe5-b758-66f387c3e28b",
"device_integrity": { "pass": true, "score": 95, "signals": [] },
"media_source": { "pass": false, "score": 12, "signals": ["virtual-camera:OBS Virtual Camera"] },
"frame_timing": { "pass": true, "score": 88, "signals": [] }
}'
const response = await fetch("https://api.deepidv.com/v1/igaming/injection", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": "YOUR_API_KEY",
},
body: JSON.stringify({
session_id: "b8991ba9-2566-4fe5-b758-66f387c3e28b",
device_integrity: { pass: true, score: 95, signals: [] },
media_source: { pass: false, score: 12, signals: ["virtual-camera:OBS Virtual Camera"] },
frame_timing: { pass: true, score: 88, signals: [] },
}),
});
const data = await response.json();
import requests
response = requests.post(
"https://api.deepidv.com/v1/igaming/injection",
headers={
"Content-Type": "application/json",
"x-api-key": "YOUR_API_KEY",
},
json={
"session_id": "b8991ba9-2566-4fe5-b758-66f387c3e28b",
"device_integrity": {"pass": True, "score": 95, "signals": []},
"media_source": {"pass": False, "score": 12, "signals": ["virtual-camera:OBS Virtual Camera"]},
"frame_timing": {"pass": True, "score": 88, "signals": []},
},
)
Response
200 — Success
| Field | Type | Description |
|---|---|---|
verdict | string | HIT, CLEAR, or UNAVAILABLE |
action | string | allow, flag, step-up, or block |
confidence | number | null | Trust confidence 0–100 (higher is cleaner) — the weighted soft score, or the failing group’s score on a hard hit; null when UNAVAILABLE |
escalation | object | null | { type: string, check: "injection-detection" } — present only when action is step-up and the workflow configures an escalation. If a step-up would resolve with no escalation configured, the check downgrades it to flag |
Verdicts
| Verdict | Meaning |
|---|---|
HIT | A hard hit (pass: false), a soft score below confidence_threshold, or automation signals were present |
CLEAR | Signals passed and the soft score met the threshold — no injection detected |
UNAVAILABLE | Neither device_integrity nor media_source was supplied — fails soft to allow |
Error responses
| Status | Description |
|---|---|
400 Bad Request | Invalid request body — check required fields and signal group shape |
401 Unauthorized | Invalid or revoked API key |
403 Forbidden | x-api-key header missing |
404 Not Found | Session not found, or not in your org |
{
"verdict": "HIT",
"action": "block",
"confidence": 12,
"escalation": null
}
{
"verdict": "CLEAR",
"action": "allow",
"confidence": 91,
"escalation": null
}
{
"verdict": "UNAVAILABLE",
"action": "allow",
"confidence": null,
"escalation": null
}