curl --request POST \
--url https://api.spoofsense.ai/v1/deepfake_detection \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"data": "/9j/4AAQSkZJRg…",
"threshold": 0.5
}
'import requests
url = "https://api.spoofsense.ai/v1/deepfake_detection"
payload = {
"data": "/9j/4AAQSkZJRg…",
"threshold": 0.5
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({data: '/9j/4AAQSkZJRg…', threshold: 0.5})
};
fetch('https://api.spoofsense.ai/v1/deepfake_detection', 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.spoofsense.ai/v1/deepfake_detection",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'data' => '/9j/4AAQSkZJRg…',
'threshold' => 0.5
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.spoofsense.ai/v1/deepfake_detection"
payload := strings.NewReader("{\n \"data\": \"/9j/4AAQSkZJRg…\",\n \"threshold\": 0.5\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
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.spoofsense.ai/v1/deepfake_detection")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"data\": \"/9j/4AAQSkZJRg…\",\n \"threshold\": 0.5\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.spoofsense.ai/v1/deepfake_detection")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"data\": \"/9j/4AAQSkZJRg…\",\n \"threshold\": 0.5\n}"
response = http.request(request)
puts response.read_body{
"product": "deepfake",
"decision": "spoof",
"genuine_score": 0.141725,
"threshold": 0.5,
"spoof_type": null,
"latency_ms": 640,
"credits_remaining": 1238,
"session_id": "a1b2c3d4e5f60718293a4b5c6d7e8f90",
"request_id": "0f1e2d3c4b5a69788766554433221100",
"signals": {
"content_credentials": {
"decision": null,
"genuine_score": null,
"status": "not_found"
},
"ai_generated": {
"decision": "real",
"genuine_score": 0.936734
},
"face_manipulation": {
"decision": "spoof",
"genuine_score": 0.141725,
"status": "checked",
"face_box": [
71,
100,
136,
136
]
}
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "Provide 'data' (base64) or 'image_url'"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "Missing, invalid, or revoked API key"
}
}{
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "Insufficient credits"
}
}{
"error": {
"code": "IMAGE_TOO_LARGE",
"message": "Image too large (max 10 MB)"
}
}{
"error": {
"code": "INVALID_IMAGE",
"message": "Invalid or unsupported image"
}
}{
"error": {
"code": "UPSTREAM_ERROR",
"message": "Inference service unavailable"
}
}Deepfake check
Checks whether an image is AI-generated, and whether the face in it has been manipulated (face swap, AI edit, lip-sync, reenactment). C2PA Content Credentials are checked first: a valid credential saying the image was made or edited with AI flags it without running the models. Otherwise both detectors run and are reported in signals; the decision is “real” only if neither flags the image. A face is not required: with no usable face (none found, or under 64 px) only the AI-image check runs. Costs 2 credits. Send the original file — resizing, re-compressing or rotating it first removes some of what the AI-image check reads.
curl --request POST \
--url https://api.spoofsense.ai/v1/deepfake_detection \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"data": "/9j/4AAQSkZJRg…",
"threshold": 0.5
}
'import requests
url = "https://api.spoofsense.ai/v1/deepfake_detection"
payload = {
"data": "/9j/4AAQSkZJRg…",
"threshold": 0.5
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({data: '/9j/4AAQSkZJRg…', threshold: 0.5})
};
fetch('https://api.spoofsense.ai/v1/deepfake_detection', 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.spoofsense.ai/v1/deepfake_detection",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'data' => '/9j/4AAQSkZJRg…',
'threshold' => 0.5
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.spoofsense.ai/v1/deepfake_detection"
payload := strings.NewReader("{\n \"data\": \"/9j/4AAQSkZJRg…\",\n \"threshold\": 0.5\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
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.spoofsense.ai/v1/deepfake_detection")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"data\": \"/9j/4AAQSkZJRg…\",\n \"threshold\": 0.5\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.spoofsense.ai/v1/deepfake_detection")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"data\": \"/9j/4AAQSkZJRg…\",\n \"threshold\": 0.5\n}"
response = http.request(request)
puts response.read_body{
"product": "deepfake",
"decision": "spoof",
"genuine_score": 0.141725,
"threshold": 0.5,
"spoof_type": null,
"latency_ms": 640,
"credits_remaining": 1238,
"session_id": "a1b2c3d4e5f60718293a4b5c6d7e8f90",
"request_id": "0f1e2d3c4b5a69788766554433221100",
"signals": {
"content_credentials": {
"decision": null,
"genuine_score": null,
"status": "not_found"
},
"ai_generated": {
"decision": "real",
"genuine_score": 0.936734
},
"face_manipulation": {
"decision": "spoof",
"genuine_score": 0.141725,
"status": "checked",
"face_box": [
71,
100,
136,
136
]
}
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "Provide 'data' (base64) or 'image_url'"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "Missing, invalid, or revoked API key"
}
}{
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "Insufficient credits"
}
}{
"error": {
"code": "IMAGE_TOO_LARGE",
"message": "Image too large (max 10 MB)"
}
}{
"error": {
"code": "INVALID_IMAGE",
"message": "Invalid or unsupported image"
}
}{
"error": {
"code": "UPSTREAM_ERROR",
"message": "Inference service unavailable"
}
}Authorizations
Your secret key (sk_live_…), server-side only. Also accepted as an x-api-key header.
Body
The image, in any supported form. Max 10 MB. EXIF orientation is applied automatically. The detected face's bounding box must be at least 224×224 pixels, or the call returns 422 FACE_TOO_SMALL — pass min_face_check: false to skip that gate.
Base64-encoded image, or a full data URL. Alias: image.
http(s) URL we fetch server-side (10 s timeout). Alias: url. Provide either data or image_url.
Optional per-request decision threshold. Defaults to your org setting (0.5 unless changed).
0 <= x <= 1Unified only: per-product thresholds, e.g. {"face_liveness": 0.6, "deepfake": 0.4}.
Show child attributes
Show child attributes
Set to false to disable the 224×224 minimum-face-size gate (422 FACE_TOO_SMALL) for this request. Small faces are upscaled before scoring, so accuracy degrades on faces well under 224 px — use only if your capture flow can't guarantee close-up faces. A face must still be detectable.
Response
Scored check
face_liveness, deepfake genuine_score > threshold
real, spoof Calibrated score in [0,1].
The threshold actually applied (request override, org setting, or 0.5).
Always null for current models.
Model inference time.
Balance after this call.
Id of the logged detection session (visible in the console).
Quote this when contacting support.
Deepfake only: what each of the two detectors found.
Show child attributes
Show child attributes