API reference · Private beta

Build with context.

Practical client guide for image, sampled video, text, audio, jobs and review dossiers.

Authentication and environment

All endpoints except health checks use a tenant API key. Evaluation keys are issued manually during private beta.

Local shell setup
export BASE_URL=http://127.0.0.1:8799/v1
export API_KEY='[REPLACE_WITH_TENANT_KEY]'

Send Authorization: Bearer $API_KEY. Read operations accept a valid tenant key; writes require the detect scope. Keys are tenant-scoped, revocable and rate-limited. Never expose one in browser code, URLs or logs.

GET /v1/model-infoReturn active image model, backend, thresholds and warning-only policy. Runtime metadata is not an accuracy certificate.

Request units and response anatomy

LaneUnitsStatus
Image1 per requestCore
Text1 per requestExperimental
Audio4 per requestExperimental
Video1 per submitted frameCore aggregate

Common result semantics

FieldMeaning
statusknown, unknown or processing; jobs add completed/failed.
labelLane-specific warning label. It is not an origin verdict.
score / confidenceRaw model outputs, not calibrated probabilities unless a benchmark says so.
source / cachedWhether the response came from model, cache, store or aggregate.
model / reasonActive version and quality/unknown explanation where supported.

Image/video labels are synthetic_indicators, possible_synthetic_indicators, no_strong_ai_signal and unknown. Text/audio currently use provisional likely_ai, possible_ai, likely_human and unknown. These labels are not interchangeable between lanes.

Image check

POST /v1/assets/check accepts JSON with base64 JPEG or multipart with a JPEG/PNG file.

Multipart
curl "$BASE_URL/assets/check" \
  -H "Authorization: Bearer $API_KEY" \
  -F "[email protected]" \
  -F "client_asset_id=asset-001" \
  -F "sync=true"

JSON shape
{
  "client_asset_id": "asset-001",
  "thumb_jpeg_base64": "<base64 omitted>",
  "sync": true
}

Request fields

FieldTypeRequired / meaning
fileJPEG/PNGMultipart image unless fingerprints resolve
thumb_jpeg_base64stringJSON low-resolution JPEG unless fingerprints resolve
client_asset_idstringOptional caller reference/idempotency identifier
frame_sha256 / frame_phashstringOptional exact / perceptual fingerprints
syncbooleanOptional; true by default, false queues fresh inference

Representative response

200 JSON
{
  "asset_id": "asset_example", "job_id": null, "status": "known",
  "label": "possible_synthetic_indicators", "score": 0.84,
  "confidence": null, "thresholds": {"possible_synthetic_indicators": 0.8},
  "source": "model", "model": "active-model-version",
  "cached": false, "ttl_seconds": 86400
}

Identifiers and numbers illustrate the schema; they are not benchmark results or guaranteed outputs.

Sampled video

POST /v1/videos/check-frames accepts up to 8 image request objects plus a stable video_footprint. Use 5–8 representative frames. This is not temporal deepfake analysis.

JSON request
{
  "video_footprint": "stable-footprint",
  "frames": [{"thumb_jpeg_base64": "[BASE64_OMITTED]"}],
  "sync": true
}

FieldTypeConstraint
video_footprintstringStable caller fingerprint; recommended
framesAssetCheckRequest[]0–8 frames; use 5–8 on the first request
syncbooleanDefault true

Representative aggregate response

200 JSON
{
  "status": "known", "label": "possible_synthetic_indicators",
  "score": 0.83, "median_score": 0.83, "mean_score": 0.82,
  "max_score": 0.86, "frame_count": 6, "scored_frame_count": 6,
  "pending_frame_count": 0, "frames": [], "cached": false,
  "source": "video_aggregate"
}

A real response includes per-frame response objects. Repeat with the same footprint and no frames for a cache lookup. A miss returns unknown.

Experimental text

POST /v1/text/check is a warning-only writing-style signal. Samples below 60 words normally return unknown / too_short.

FieldTypeConstraint
textstringRequired; 1–20,000 characters
languagestringOptional language hint
canonical_urlstringOptional source reference
platform_asset_idstringOptional caller reference
JSON request
{"text":"A representative long-form sample...", "language":"en"}

Representative response

200 JSON
{
  "status": "known", "label": "unknown", "score": 0.41,
  "confidence": 0.18, "source": "text_hybrid",
  "model": "text-hybrid-v2-warning-only", "cached": false,
  "text_hash": "illustrative-sha256", "char_count": 310,
  "word_count": 61, "reason": "model-specific diagnostic",
  "policy": "weak_signal_warning_only"
}

Experimental audio

POST /v1/audio/check accepts PCM WAV. Quiet, short or tonal non-speech clips can return unknown before scoring.

FieldTypeConstraint
filePCM WAVMultipart upload
audio_base64stringJSON alternative to file
filenamestringOptional source filename
canonical_url / platform_asset_idstringOptional source references
Multipart request
curl "$BASE_URL/audio/check"   -H "Authorization: Bearer $API_KEY"   -F "[email protected]"

Representative response

200 JSON
{
  "status": "known", "label": "unknown", "score": null,
  "confidence": null, "source": "audio_detector",
  "model": "audio-wav2vec2-v1-warning-only", "cached": false,
  "audio_hash": "illustrative-sha256", "duration_seconds": 4.2,
  "sample_rate": 16000, "reason": "audio_backend_disabled",
  "policy": "weak_signal_warning_only"
}

Jobs and stored assets

Set sync=false for asynchronous image inference. The initial response has status: processing and a job_id.

GET /v1/jobs/{job_id}Poll processing, completed or failed. Completed jobs include result.
GET /v1/assets/{asset_id}Retrieve the tenant-scoped complete result.
Completed job
{"job_id":"job_example","status":"completed","result":{"asset_id":"asset_example","status":"known","label":"possible_synthetic_indicators"}}

Recommended client policy: poll after 1, 2, 4, 8 and then 10 seconds; cap each later delay at 10 seconds and stop after 60 seconds or on completed/failed. The server does not currently guarantee that timeout and exposes no webhook or Retry-After contract.

Human review lifecycle

POST /v1/reviewsMultipart file, required declared_ai_use, optional supplier and notes.
GET /v1/reviewsList tenant dossiers; no pagination contract during beta.
GET /v1/reviews/{review_id}Retrieve one dossier.
POST /v1/reviews/{review_id}/decisionRecord disclose, no_disclosure, reject or recheck.
GET /v1/reviews/{review_id}/exportExport JSON.
DELETE /v1/reviews/{review_id}Delete; success is 204.
Create review
curl "$BASE_URL/reviews"   -H "Authorization: Bearer $API_KEY"   -F "[email protected]"   -F "declared_ai_use=unknown"   -F "supplier=Example supplier"

Decision JSON
{"decision":"disclose","reviewer":"[email protected]","rationale":"Disclosure selected after source and detector review."}

Review responses include review_id, pending/completed status, content hash, filename, declaration, provenance, detector, optional decision, policy and created/updated timestamps. They never automatically reject or publish content.

HTTP status

StatusMeaning
200 / 204Completed or deleted
400Invalid or unsupported input
401 / 403Missing key, invalid key or insufficient scope
404Tenant-scoped resource not found
413Upload exceeds configured maximum
422Typed JSON validation failed
429Per-key rate limit exceeded
503Production dependency or worker not ready

Errors use {"detail":"error_code"}; for example {"detail":"invalid_api_key"}. Every response includes X-Request-ID. The current async image submission still returns the normal endpoint response with status: processing; do not assume HTTP 202.