ScamAI raised $2.6M to combat AI-powered scams
scam.ai

~/docs cat create-detection.md

Create a detection

POST /v1/detections runs a detection on one file or link. The server infers image, video, audio or document, runs the right detectors, and answers with one envelope. Synchronous: every call is one run, and a retried call is a second run and a second charge.

Request (multipart/form-data):

request fields
file        binary   the media. image ≤ 10 MB, video ≤ 100 MB,
                     document ≤ 50 MB, audio ≤ 50 MB
url         string   a link to the media, as an alternative to file
save        string   "true" | "false". persist history + file (default "true")
thumbnails  string   "true" | "false". video only: include a small base64 JPEG
                     of each scored frame as frames[].thumbnail_b64
                     (default "false")
curl
curl -X POST "https://api.scam.ai/v1/detections" \
  -H "x-api-key: <YOUR_API_KEY>" \
  -F "file=@/path/to/media.mp4"
response fields
id             string   detection id, always present
status         string   always "completed"
created_at     string   RFC 3339 timestamp, millisecond precision, Z
media          object   { type: "image" | "video" | "document" | "audio",
                          filename, mime_type, bytes }
model          string   the public model name, "Eva V1.6"
verdict        string   "LIKELY_REAL" | "ALERT" | "LIKELY_AI"
score          float    probability the media is manipulated, 0 to 1.
                        null when nothing scored
summary        string   one sentence a person can read
credits_used   number   what was debited for this run. 0 on a free run, with
                        zero_charge_reason: "sandbox" | "duplicate"

ALERT means we detected some AI-related signals, but the result is not conclusive. It can occur on images, documents and videos. Audio is judged on one line, so it answers LIKELY_REAL or LIKELY_AI.

Video, audio and links add their own fields on top of the base above:

video adds
threshold_used   number   the line the verdict was decided against
frames           array    per-frame, the whole clip:
                          [{ index, timestamp_s, score, cause?, thumbnail_b64? }]
                          score is null, never 0, for a frame that was not
                          scored, and cause says why. thumbnail_b64 is present
                          only when the request sent thumbnails="true"
audio adds
duration_ms   number   clip length. audio is billed by length
segments      array    per-window [{ start_ms, end_ms, value, status }]
                       value = P(synthetic), null for a window with no speech
link adds
source   object   only when the media came from a link:
                  { url, canonical_url, platform, title, uploader,
                    duration_s, truncated, analyzed_duration_s }
                  truncated is true when only a prefix was scored;
                  analyzed_duration_s is the length that was scored

verdict uses the same three words for every media type.