Media Detail
curl --request GET \
--url https://api.prd.realitydefender.xyz/api/media/users/{requestId} \
--header 'x-api-key: <api-key>'import requests
url = "https://api.prd.realitydefender.xyz/api/media/users/{requestId}"
headers = {"x-api-key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-api-key': '<api-key>'}};
fetch('https://api.prd.realitydefender.xyz/api/media/users/{requestId}', 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.prd.realitydefender.xyz/api/media/users/{requestId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: <api-key>"
],
]);
$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.prd.realitydefender.xyz/api/media/users/{requestId}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.prd.realitydefender.xyz/api/media/users/{requestId}")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.prd.realitydefender.xyz/api/media/users/{requestId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_bodyEndpoint Examples
Media Detail
GET
api
/
media
/
users
/
{requestId}
Media Detail
curl --request GET \
--url https://api.prd.realitydefender.xyz/api/media/users/{requestId} \
--header 'x-api-key: <api-key>'import requests
url = "https://api.prd.realitydefender.xyz/api/media/users/{requestId}"
headers = {"x-api-key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-api-key': '<api-key>'}};
fetch('https://api.prd.realitydefender.xyz/api/media/users/{requestId}', 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.prd.realitydefender.xyz/api/media/users/{requestId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: <api-key>"
],
]);
$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.prd.realitydefender.xyz/api/media/users/{requestId}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.prd.realitydefender.xyz/api/media/users/{requestId}")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.prd.realitydefender.xyz/api/media/users/{requestId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_bodystring
Returns deepfake detection result for specified requestId.
requestId. You can also find your requestId in the URL path when you access the upload in the web application.
Authorization
To fetch media detail, you must include thex-api-key in your request headers. This key is essential for authenticating your request and ensuring secure access to the API.
Sample Code Snippet
Here’s an example of how you can fetch the results for an uploaded file or social media URL.REQUEST_ID="your-requestId"
API_KEY="your-api-key"
curl -X GET \
"https://api.prd.realitydefender.xyz/api/media/users/${REQUEST_ID}" \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json"
import requests
requestId = "your-request-id"
url = f"https://api.prd.realitydefender.xyz/api/media/users/{requestId}"
headers = {
"X-API-KEY": "your-api-key",
"Content-Type": "application/json"
}
response = requests.get(url, headers=headers).json()
print(response.get('filename','N/A'))
print(response.get('overallStatus','N/A'))
Sample Response
{
"filename": "rd-file-name",
"originalFileName": "original-file-name",
"requestId": "request-id",
"uploadedDate": "uploaded-date",
"mediaType": "media-type", // AUDIO, VIDEO, TEXT, IMAGE
"socialLink": "social-link", // populated for social media submissions
"socialLinkDownloaded": true, // populated for social media submissions
"socialLinkDownloadFailed": false, // populated for social media submissions
"showAudioResult": "show-audio-result", // True, False
"audioRequestId": "audio-request-id", // populated if showAudioResult is True
"userId": "user-id",
"institutionId": "institution-id",
"releaseVersion": "2.3.1",
"overallStatus": "status", // AUTHENTIC, FAKE, SUSPICIOUS, NOT_APPLICABLE, UNABLE_TO_EVALUATE
"resultsSummary": {
"status": "status", // AUTHENTIC, FAKE, SUSPICIOUS, NOT_APPLICABLE, UNABLE_TO_EVALUATE
"metadata": {
"languages": ["language"], // detected languages include english, spanish, and portuguese
"finalScore": score // when present, typically > 0 and < 100 (clamped like model finalScore)
}
},
"models": [
{
"name": "model-name", // see Possible models; names can change over time
"data": {
"score": 0.99,
"decision": "ARTIFICIAL", // or AUTHENTIC
"raw_score": 0.99
},
"status": "FAKE", // AUTHENTIC, FAKE, SUSPICIOUS, NOT_APPLICABLE, UNABLE_TO_EVALUATE, ANALYZING
"predictionNumber": 0.99, // raw model score (typically 0–1); may be null
"normalizedPredictionNumber": 99, // > 0 and < 100 when available; else null
"rollingAvgNumber": null,
"finalScore": 99, // > 0 and < 100 when available; else null
"code": null // e.g. "not_applicable" when status is NOT_APPLICABLE
}
// additional model results...
],
"storageLocation": "https://...presigned...",
"thumbnail": "https://...presigned...", // may be "" when unavailable
"aggregationResultUrl": "institution-id/request-id.ext/aggregation.json",
"modelMetadataUrl": "https://...presigned.../aggregation.json",
"audioModelMetadataUrl": "https://...presigned.../aggregation.json", // combined video+audio only; else ""
"heatmaps": {
"model-name": "https://...presigned.../heatmaps/model-name/heatmap.png"
},
"explainabilityUrl": "" // text: pre-signed HTML URL; otherwise typically ""
}
Response Schema
Core fields
| Field | Type | Description |
|---|---|---|
filename | string | Display / upload filename |
originalFileName | string | Original uploaded filename |
requestId | string | ID used to fetch this result |
uploadedDate | string | Upload timestamp (ISO 8601) |
mediaType | string | IMAGE, VIDEO, AUDIO, or TEXT |
overallStatus | string | Overall media status (see statuses below) |
userId | string | Uploading user ID |
institutionId | string | null | Organization ID |
releaseVersion | string | Platform release version for the scan |
resultsSummary | object | Ensemble status, score, and optional reasons/errors |
models | array | Per-model detection results (see below) |
models[] object
Each entry in models has the following fields:
| Field | Type | Description |
|---|---|---|
name | string | Model slug (see Possible models). Model names can change in the future as detectors are added, renamed, or retired. |
status | string | Model status (FAKE, AUTHENTIC, SUSPICIOUS, NOT_APPLICABLE, UNABLE_TO_EVALUATE, ANALYZING, …) |
predictionNumber | number | null | Raw model score when available (typically 0–1). Not clamped; can be exactly 0 or 1. |
normalizedPredictionNumber | number | null | Normalized score when available; always > 0 and < 100 (never exactly 0 or 100) |
rollingAvgNumber | number | null | Rolling average when applicable (same 0–100 normalization/clamping as normalizedPredictionNumber when present) |
finalScore | number | null | Final model score when available; always > 0 and < 100 (never exactly 0 or 100) |
data | object | null | Model-specific payload (for example decision, score, raw_score; shape varies by model) |
error | object | string | null | Error details when the model failed |
code | string | null | Machine-readable code (for example not_applicable) |
status: "ANALYZING" and null scores. Models that do not apply to the media type typically return status: "NOT_APPLICABLE" with code: "not_applicable" and data: null.
Explainability and visualization fields
These fields power the same visualization experience as the Reality Defender UI.| Field | Type | Media types | Description |
|---|---|---|---|
heatmaps | object | Image (meaningful) | Map of model name → pre-signed PNG URL. Usable heatmaps are only for artificial image models that are not ensemble (models[].status = FAKE / decision ARTIFICIAL). The API may still return entries for non-artificial image models, ensemble models, or other media types, but those links are invalid. |
explainabilityUrl | string | Text (populated) | Pre-signed URL to HTML explainability output (for example explainability-rd-llm-txt.html). Empty string ("") for image/video/audio in typical responses. |
thumbnail | string | Video (common), Image (when available) | Pre-signed thumbnail URL, or "" when unavailable |
storageLocation | string | All | Pre-signed URL to the original uploaded media (may be empty if originals were deleted by retention policy) |
aggregationResultUrl | string | All | Raw S3 object key for aggregation.json (not a downloadable URL) |
modelMetadataUrl | string | All | Pre-signed URL for the same aggregation.json referenced by aggregationResultUrl. Fetch this to build UI-like visualizations. |
audioModelMetadataUrl | string | Combined video+audio | Pre-signed URL for the extracted-audio aggregation JSON when showAudioResult is true; otherwise "" |
aggregationResultUrl / modelMetadataUrl and UI visualization
aggregationResultUrlis the storage key, typically shaped like:{institutionId}/{requestId}{extension}/aggregation.json(for example.mp4,.png,.txt, or an audio extension)modelMetadataUrlis the browser-readable, pre-signed URL for that file.- For combined video+audio scans,
audioModelMetadataUrlpoints at the extracted-audio aggregation JSON (a separate key/path from the video aggregation). - The Reality Defender UI loads this JSON to render report detail (bounding boxes, timelines/scenes, audio chunks, text conclusions, and related metadata).
- Approximate contents by media type:
- Image:
bboxes,conclusions, optionalcontextResult - Video: frame/timeline fields (for example scenes, frames, tubes),
models,ensembles,conclusions, optionalcontextResult - Audio:
chunks,languages,conclusions,models,ensembles, plus audio metadata - Text:
models,ensembles,conclusions
- Image:
modelMetadataUrl / audioModelMetadataUrl (not aggregationResultUrl) when downloading aggregation artifacts from a client.
Pre-signed URL expiry
heatmaps, thumbnail, storageLocation, modelMetadataUrl, audioModelMetadataUrl, and explainabilityUrl are pre-signed URLs that expire after 15 minutes (X-Amz-Expires=900).
If a URL returns access denied / expired:
- Call this media detail endpoint again for the same
requestId. - Use the newly returned pre-signed URLs.
Possible models
models[].name values you may see (depending on media type and release version):
Model names are not a stable contract. Detectors can be added, renamed, or removed over time. Treat the list below as illustrative examples, and always read
models[].name from the live response rather than hard-coding specific model slugs.rd-cedar-img, rd-elm-img, rd-oak-img, rd-pine-img, rd-img-ensemble, rd-context-img
Video: rd-erie-vid, rd-tahoe-vid, rd-dynamics-vid, rd-vid-ensemble, rd-context-vid
Audio: rd-slim-aud, rd-everest-aud, rd-aud-ensemble
Text: rd-llm-txt
The exact set returned for a scan depends on your plan, institution settings, and releaseVersion.
Response Details
NOT_APPLICABLE
Reality Defender will return NOT_APPLICABLE as a status if the file contains certain characteristics that are known to impact accuracy. The reason behind the NOT_APPLICABLE response will be returned as a list in themetadata field.
For example, see below for a resultsSummary returned for an image that was not applicable.
"resultsSummary": {
"status": "NOT_APPLICABLE",
"metadata": {
"reasons": [
{
"code": "relevance",
"message": "no faces detected/faces too small"
}
]
}
}
Possible reasons returned for
NOT_APPLICABLE are:
- code: relevance
- message: no faces detected/faces too small
Currently, our video files do not output reasons. For video visualization (timeline / scene detail), use
modelMetadataUrl instead.
Audio Reasons Possible reasons returned for
NOT_APPLICABLE are:
- code: duration
- message: audio too short (<1.5s)
- code: detected
- message: dialtone and/or music
- code: cross-talk
- message: more than one speaker detected
- code: quality
- audio too noisy
- code: language
- audio is more likely in language
UNABLE_TO_EVALUATE Response
Reality Defender will return UNABLE_TO_EVALUATE if an error occurred while processing the file. This is typically caused by timeouts. You can try again, or upload a smaller file. Here is an example of theresultsSummary returned for an image that is unable to be evaluated.
"resultsSummary": {
"status": "UNABLE_TO_EVALUATE",
"metadata": {},
"error": {
"code": "model-error",
"message": "An error occurred while processing the file. Please try uploading the file again."
}
}