31 KiB
Agent V3 — API Documentation
DIDI Misinformation Detection Platform — Analysis Engine API
Version: 3.0.0
Base URL
| Access Method | Base URL | Notes |
|---|---|---|
| Internal (via nginx proxy) | https://localhost:3000/agent-v3 |
Through didi-admin nginx container. Self-signed SSL — use curl -k. Strips /agent-v3/ prefix before proxying to agent. |
| Direct (no proxy) | http://localhost:24803 |
Directly to agent-v3 container. No SSL, no prefix stripping. |
| Public domain | https://didi365.eu/agent-v3 |
Currently returns 403 Forbidden. An external reverse proxy at 213.136.83.198 blocks requests before they reach the staging server (10.11.10.12). This needs to be resolved at the infrastructure level. |
| Kong gateway | https://localhost:443 |
Returns 401 Unauthorized — Kong enforces JWT validation on this port. Only works with a valid Keycloak JWT. Kong does not expose /api/v3/* routes — it uses different paths (/api/analyze, /api/pipelines, etc.) that map to the older agent service interface. |
Recommendation: Use
https://localhost:3000/agent-v3for testing. All curl examples in this document use this base URL with-kto accept the self-signed certificate.
Table of Contents
- Authentication
- Full Pipeline
- Manipulation Techniques
- AI-Tampered Detection
- Claims Verification
- Domain Analysis
- Polling & Results
- Browser Extension API
- Error Codes
Authentication
Pass user_id in the request body to identify the user:
curl -sk -X POST https://localhost:3000/agent-v3/api/v3/pipeline/analyze \
-H "Content-Type: application/json" \
-d '{
"text": "Content to analyze",
"media_type": "text",
"user_id": "test-user"
}'
If a JWT Authorization: Bearer header is present (from Keycloak), the user identity is extracted from the token and takes precedence over user_id in the body.
Credit System
Analysis endpoints check and deduct credits based on user_id. If the user's plan has insufficient credits, the API returns 402 Payment Required with the remaining balance and cost.
Staging: When
STAGING_MODE=trueis set (default in staging), all credit limits are bypassed. Anyuser_idvalue works without needing actual credits.
1. Full Pipeline
Runs all detection components sequentially — Techniques → AI-Tampered → Claims → Domain (if URL provided) — then produces an aggregated verdict with an overall risk score.
This is the primary analysis endpoint. Individual component endpoints (sections 2–5) run only their respective component without producing a verdict.
POST /api/v3/pipeline/analyze
Synchronous full analysis. Accepts text, media, or URL input.
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
text |
string | Conditional | Text content to analyze |
media_url |
string | Conditional | URL of uploaded media file (image only for sync — audio/video require async) |
url |
string | Conditional | URL of a webpage to analyze |
media_type |
string | Yes | One of: text, url, image, audio, video |
user_email |
string | No | User email (overridden by JWT if present) |
options |
object | No | { skip_components: string[], scenario: string, topic: string } |
Input rule: Provide at least one of
text,media_url, orurl. You can combine them — for example, provide bothtextandurlto analyze text with domain context.
Audio/video note: Sync analysis of audio and video media is not supported because transcription can take 5–10 minutes. The endpoint returns
400withcode: "ASYNC_REQUIRED". UsePOST /api/v3/pipeline/analyze-asyncfor audio and video content instead.
Example:
curl -sk -X POST https://localhost:3000/agent-v3/api/v3/pipeline/analyze \
-H "Content-Type: application/json" \
-d '{
"text": "Romania'\''s president declared yesterday that the country will leave the European Union by 2025. According to unnamed government sources, this decision was made in secret meetings with Russian officials.",
"media_type": "text",
"user_id": "test-user"
}'
Response (200):
{
"success": true,
"data": {
"session_id": "a63a72ed-de8e-458b-a708-3e80d38f867c",
"user_id": "test-user",
"status": "completed",
"input_type": "text",
"components_run": ["techniques", "ai_tampered", "claims"],
"components_skipped": ["domain"],
"risk_score": 78,
"risk_category": "UNRELIABLE",
"risk_level": "VERY_HIGH",
"confidence": 75,
"confidence_level": "MEDIUM",
"total_duration_ms": 50500,
"techniques": {
"manipulation_score": 35,
"techniques_count": 1,
"dimensions_affected": ["D7"],
"techniques_detected": [
{
"id": 175,
"name": "temporal.embargo_breaking",
"dimension": "D7",
"subdimension": "Event Timing",
"severity": 50,
"confidence": 85,
"evidence": "The announcement was shared widely on social media before any official press conference."
}
],
"llm_screening": "qwen35:Qwen3.5-397B-A17B",
"llm_deep": "qwen35:Qwen3.5-397B-A17B",
"total_duration_ms": 29472
},
"ai_tampered": {
"ai_probability": 83,
"verdict": "LIKELY_AI",
"categories_affected": ["T3", "T4"],
"indicators_count": 7,
"disclosure_detected": false,
"indicators_detected": [
{ "id": "T3.1", "name": "Lack of Personal Anecdotes", "confidence": 95 },
{ "id": "T3.2", "name": "Absence of Specific Details", "confidence": 85 },
{ "id": "T3.3", "name": "No Emotional Depth", "confidence": 90 }
],
"total_duration_ms": 43031
},
"claims": {
"total_claims": 4,
"verified_true": 0,
"verified_false": 0,
"unverified": 4,
"credibility_score": 75,
"claims_verified": [
{
"id": "claim_1",
"text": "Romania's president declared yesterday that the country will leave the EU by 2025.",
"type": "RE",
"type_name": "Recent Event",
"status": "UV",
"status_name": "Neverificat",
"sources": []
}
],
"total_duration_ms": 43495
},
"domain": null,
"verdict": {
"risk_score": 78,
"risk_category": "UNRELIABLE",
"risk_category_color": "red",
"risk_level": "VERY_HIGH",
"severity": "HIGH",
"recommended_action": "ESCALATE",
"confidence": 75,
"score_manipulation": 35,
"score_claims": 25,
"score_ai": 83,
"override_applied": true,
"override_reason": "Undisclosed AI content (+15%)",
"explanation_en": "The content is likely AI-generated without disclosure, and the claims lack any verifiable web traces, indicating complete fabrication.",
"explanation_ro": "Conținutul este generat probabil de inteligența artificială fără dezvăluire, iar afirmațiile nu au nicio sursă verificabilă online.",
"virality_score": 26,
"virality_level": "MODERATE"
}
}
}
POST /api/v3/pipeline/analyze-url
Smart URL analysis. Automatically detects the URL type and processes accordingly:
| Detected Type | Platforms | Processing |
|---|---|---|
| Video platform | YouTube, TikTok, Twitter/X, Instagram, Facebook, Vimeo, Dailymotion, Twitch | Downloads via yt-dlp → transcribes audio → extracts frames → full pipeline |
| Image | Direct links ending in .jpg, .jpeg, .png, .gif, .webp, .bmp |
Downloads image → OCR via vision model → full pipeline |
| Article | All other URLs | Fetches page text (M17 AI extraction with direct fetch fallback) → full pipeline |
Platform detection is based on URL pattern matching in
detectUrlType(). For example, any URL containingyoutube.comoryoutu.beis classified as a video platform.
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
url |
string | Yes | URL to analyze |
options |
object | No | Analysis options |
Example:
curl -sk -X POST https://localhost:3000/agent-v3/api/v3/pipeline/analyze-url \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/news-article",
"user_id": "test-user"
}'
Response (200): Same structure as /analyze, with additional url_metadata:
{
"success": true,
"data": {
"session_id": "...",
"risk_score": 45,
"url_metadata": {
"original_url": "https://example.com/news-article",
"detected_type": "article",
"processed_as": "url"
},
"...": "full pipeline result"
}
}
POST /api/v3/pipeline/analyze-async
Asynchronous analysis via RabbitMQ. Returns immediately with a session ID. Use the polling endpoints to track progress and retrieve results.
This is the required endpoint for audio and video content, since transcription and video processing can take 5–10 minutes.
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
text |
string | Conditional | Text content |
media_url |
string | Conditional | Media file URL |
url |
string | Conditional | URL to analyze |
media_type |
string | Yes | One of: text, url, image, audio, video |
plan_type |
integer | No | Subscription tier 1–6 (affects queue priority). Default: 1 |
options |
object | No | Analysis options |
Provide at least one of
text,media_url, orurl.
Example:
curl -sk -X POST https://localhost:3000/agent-v3/api/v3/pipeline/analyze-async \
-H "Content-Type: application/json" \
-d '{
"media_url": "https://didi365.eu/agent-v3/api/v3/media/file/uploads/user/video.mp4",
"media_type": "video",
"user_id": "test-user",
"plan_type": 2
}'
Response (202 Accepted):
{
"success": true,
"async": true,
"data": {
"session_id": "b7f3a1e2-...",
"status": "processing",
"queued_components": ["techniques", "ai_tampered", "claims"],
"plan_type": 2,
"poll_url": "/api/v3/pipeline/b7f3a1e2-.../queue-status",
"result_url": "/api/v3/pipeline/b7f3a1e2-.../result"
}
}
Graceful fallback: If RabbitMQ is unavailable, the request is processed synchronously and returns
200with{ "async": false, "data": { ... full result ... } }.
2. Manipulation Techniques
Detects manipulation techniques across 166 known patterns in 8 dimensions. Uses a 2-phase LLM approach: fast screening followed by deep analysis on flagged content.
Runs only the techniques component — no verdict is produced.
POST /api/v3/techniques/analyze
Analyze text for manipulation techniques.
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
text |
string | Yes | Text content to analyze |
Example:
curl -sk -X POST https://localhost:3000/agent-v3/api/v3/techniques/analyze \
-H "Content-Type: application/json" \
-d '{
"text": "Romania'\''s president declared yesterday that the country will leave the European Union by 2025. According to unnamed government sources, this decision was made in secret meetings with Russian officials.",
"user_id": "test-user"
}'
Response (200):
{
"success": true,
"data": {
"session_id": "c4d5e6f7-...",
"status": "completed",
"components_run": ["techniques"],
"components_skipped": ["ai_tampered", "claims", "domain", "verdict"],
"total_duration_ms": 23998,
"techniques": {
"manipulation_score": 35,
"total_severity": 50,
"dimensions_affected": ["D7"],
"techniques_count": 1,
"techniques_detected": [
{
"id": 175,
"name": "temporal.embargo_breaking",
"dimension": "D7",
"subdimension": "Event Timing",
"severity": 50,
"confidence": 85,
"intensity": 2,
"evidence": "The announcement was shared widely on social media before any official press conference."
}
],
"coupling_context": {
"for_claims": {
"has_emotional_manipulation": false,
"has_logical_fallacies": false,
"has_source_manipulation": false,
"manipulation_level": "CRITICAL",
"top_techniques": ["temporal.embargo_breaking"]
},
"for_verdict": {
"risk_score": 35,
"dimension_count": 1,
"severe_technique_count": 1,
"needs_override_check": true
}
},
"llm_screening": "qwen35:Qwen3.5-397B-A17B",
"llm_deep": "qwen35:Qwen3.5-397B-A17B",
"screening_duration_ms": 9521,
"deep_analysis_duration_ms": 19942,
"total_duration_ms": 29472,
"fallbacks_screening": 0,
"fallbacks_deep": 0
}
}
}
POST /api/v3/techniques/analyze-media
Analyze media for manipulation techniques. The API extracts text first (OCR for images, transcription for audio/video, page fetch for URLs), then runs the techniques analysis on the extracted text.
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
media_url |
string | Yes | URL of the media file |
media_type |
string | Yes | One of: image, audio, video, url |
Example:
curl -sk -X POST https://localhost:3000/agent-v3/api/v3/techniques/analyze-media \
-H "Content-Type: application/json" \
-d '{
"media_url": "https://didi365.eu/agent-v3/api/v3/media/file/uploads/user/screenshot.png",
"media_type": "image",
"user_id": "test-user"
}'
POST /api/v3/techniques/analyze-async
Queue-based asynchronous techniques analysis. Same async pattern as the full pipeline.
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
text |
string | Conditional | Text content |
media_url |
string | Conditional | Media file URL |
url |
string | Conditional | URL to fetch and analyze |
media_type |
string | No | One of: text, image, audio, video, url (auto-detected if omitted) |
plan_type |
integer | No | Queue priority tier 1–6. Default: 1 |
3. AI-Tampered Detection
Detects AI-generated content. Uses 2-phase LLM analysis for text and a vision model cascade (local Qwen → Gemini → GPT-4o) for images.
POST /api/v3/ai-tampered/analyze
Analyze text for AI-generated content indicators.
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
text |
string | Yes | Text content to analyze |
Example:
curl -sk -X POST https://localhost:3000/agent-v3/api/v3/ai-tampered/analyze \
-H "Content-Type: application/json" \
-d '{
"text": "Romania'\''s president declared yesterday that the country will leave the European Union by 2025. According to unnamed government sources, this decision was made in secret meetings with Russian officials.",
"user_id": "test-user"
}'
Response (200):
{
"success": true,
"data": {
"session_id": "d8e9f0a1-...",
"status": "completed",
"components_run": ["ai_tampered"],
"total_duration_ms": 17920,
"ai_tampered": {
"ai_probability": 86,
"verdict": "LIKELY_AI",
"risk_score": 86,
"categories_affected": ["T3", "T4"],
"indicators_count": 6,
"disclosure_detected": false,
"indicators_detected": [
{
"id": "T3.1",
"category": "T3",
"name": "Lack of Personal Anecdotes",
"confidence": 95,
"evidence": "The text is written entirely in the third person with no first-person narratives."
},
{
"id": "T3.2",
"category": "T3",
"name": "Absence of Specific Details",
"confidence": 90,
"evidence": "Critical verifiable facts are missing — 'unnamed government sources', 'secret meetings' without dates or names."
},
{
"id": "T3.3",
"category": "T3",
"name": "No Emotional Depth",
"confidence": 92,
"evidence": "Tone is purely informational and flat, lacking genuine sentiment."
},
{
"id": "T4.3",
"category": "T4",
"name": "Low Burstiness",
"confidence": 78,
"evidence": "Uniform sentence structure and length, lacking natural variation."
},
{
"id": "T4.4",
"category": "T4",
"name": "Repetitive N-grams",
"confidence": 65,
"evidence": "Repetitive passive constructions: 'was made in', 'was shared widely'."
}
],
"coupling_context": {
"for_verdict": {
"ai_risk_score": 86,
"undisclosed_ai": true,
"confidence_level": "HIGH",
"needs_manual_review": true
}
},
"llm_screening": "qwen35:Qwen3.5-397B-A17B",
"llm_deep": "qwen35:Qwen3.5-397B-A17B",
"total_duration_ms": 17920,
"fallbacks_screening": 0,
"fallbacks_deep": 0,
"content_type": "text"
}
}
}
Verdict scale:
| Verdict | AI Probability | Meaning |
|---|---|---|
LIKELY_AI |
≥ 80% | Strong AI-generation indicators |
UNCERTAIN |
50–79% | Mixed signals |
POSSIBLY_HUMAN |
20–49% | Mostly human-written |
LIKELY_HUMAN |
< 20% | No significant AI indicators |
POST /api/v3/ai-tampered/analyze-media
Analyze media for AI-generated content. Supports image (vision analysis), audio (transcription → text analysis), and video (frames + transcript analysis).
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
media_url |
string | Yes | URL of the media file |
media_type |
string | Yes | One of: image, audio, video |
Example:
curl -sk -X POST https://localhost:3000/agent-v3/api/v3/ai-tampered/analyze-media \
-H "Content-Type: application/json" \
-d '{
"media_url": "https://didi365.eu/agent-v3/api/v3/media/file/uploads/user/photo.jpg",
"media_type": "image",
"user_id": "test-user"
}'
POST /api/v3/ai-tampered/analyze-image
Quick image-only AI detection via vision model cascade. Lighter response format than /analyze-media.
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
image_url |
string | Yes | URL of the image to analyze |
Example:
curl -sk -X POST https://localhost:3000/agent-v3/api/v3/ai-tampered/analyze-image \
-H "Content-Type: application/json" \
-d '{
"image_url": "https://didi365.eu/agent-v3/api/v3/media/file/uploads/user/suspect.jpg",
"user_id": "test-user"
}'
Response (200):
{
"success": true,
"data": {
"ai_probability": 75,
"verdict": "POSSIBLY_AI",
"indicators": ["overly smooth skin texture", "background artifacts"],
"evidence": "Image shows characteristic AI generation patterns in skin rendering and background consistency.",
"model_used": "qwen-vision-local"
}
}
POST /api/v3/ai-tampered/quick
Fast heuristic-only screening — no LLM calls. Returns instantly. Useful for real-time filtering before committing to a full analysis.
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
text |
string | Yes | Text to screen |
Example:
curl -sk -X POST https://localhost:3000/agent-v3/api/v3/ai-tampered/quick \
-H "Content-Type: application/json" \
-d '{"text": "Some text to screen quickly", "user_id": "test-user"}'
POST /api/v3/ai-tampered/analyze-async
Queue-based asynchronous AI detection. Same async pattern as the full pipeline.
Parameters: Same as techniques/analyze-async.
4. Claims Verification
Extracts factual claims from content and verifies them against web sources. Pipeline: LLM extraction → web evidence search → LLM per-claim verification.
POST /api/v3/claims/analyze
Analyze text for factual claims and verify them.
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
text |
string | Yes | Text content to analyze |
Example:
curl -sk -X POST https://localhost:3000/agent-v3/api/v3/claims/analyze \
-H "Content-Type: application/json" \
-d '{
"text": "Romania'\''s president declared yesterday that the country will leave the European Union by 2025. According to unnamed government sources, this decision was made in secret meetings with Russian officials.",
"user_id": "test-user"
}'
Response (200):
{
"success": true,
"data": {
"session_id": "e1f2a3b4-...",
"status": "completed",
"components_run": ["claims"],
"total_duration_ms": 17787,
"claims": {
"total_claims": 5,
"verified_true": 0,
"verified_false": 0,
"unverified": 5,
"opinions": 0,
"credibility_score": 75,
"interpretation": "Substantial agreement",
"claims_by_status": { "UV": 5 },
"claims_by_type": { "RE": 3, "PC": 1, "QA": 1 },
"claims_verified": [
{
"id": "claim_1",
"text": "Romania's president declared yesterday that the country will leave the EU by 2025.",
"type": "RE",
"type_name": "Recent Event",
"priority": "high",
"context": "Asserts a specific recent declaration by a head of state.",
"status": "UV",
"status_name": "Neverificat",
"status_color": "gray",
"confidence": 0,
"agreement_score": 0,
"sources": [],
"reasoning": "No web sources found for verification",
"verification_method": "N/A"
},
{
"id": "claim_2",
"text": "Romania will leave the European Union by 2025.",
"type": "PC",
"type_name": "Predictive Claim",
"priority": "high",
"status": "UV",
"status_name": "Neverificat",
"sources": [],
"reasoning": "No web sources found for verification"
},
{
"id": "claim_3",
"text": "The decision to leave the EU was made in secret meetings with Russian officials.",
"type": "RE",
"type_name": "Recent Event",
"priority": "high",
"status": "UV",
"status_name": "Neverificat",
"sources": [],
"reasoning": "No web sources found for verification"
}
],
"llm_extraction": "qwen35:Qwen3.5-397B-A17B",
"llm_verification": "unknown",
"extraction_duration_ms": 34240,
"verification_duration_ms": 9250,
"total_duration_ms": 17787,
"web_searches_made": 0
}
}
}
Claim types:
| Code | Name | Description |
|---|---|---|
VF |
Verifiable Fact | Objectively checkable statement |
RE |
Recent Event | Assertion about a recent occurrence |
PC |
Predictive Claim | Future prediction |
QA |
Quoted Attribution | Claim attributed to a source |
ST |
Statistical | Numeric/statistical claim |
OP |
Opinion | Subjective statement |
Claim statuses:
| Code | Name | Meaning |
|---|---|---|
VT |
Verified True | Confirmed by web sources |
VF |
Verified False | Contradicted by web sources |
PT |
Partially True | Mixed evidence |
UV |
Unverified | No sources found |
OP |
Opinion | Not verifiable |
POST /api/v3/claims/analyze-media
Analyze media for claims. Extracts text first (OCR, transcription, URL fetch), then runs claims analysis.
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
media_url |
string | Yes | URL of the media file |
media_type |
string | Yes | One of: image, audio, video, url |
Example:
curl -sk -X POST https://localhost:3000/agent-v3/api/v3/claims/analyze-media \
-H "Content-Type: application/json" \
-d '{
"media_url": "https://didi365.eu/agent-v3/api/v3/media/file/uploads/user/recording.mp3",
"media_type": "audio",
"user_id": "test-user"
}'
POST /api/v3/claims/analyze-async
Queue-based asynchronous claims analysis. Same async pattern as the full pipeline.
Parameters: Same as techniques/analyze-async.
5. Domain Analysis
Analyzes domain credibility using WHOIS, DNS, SSL, blacklist, and IP intelligence checks. Does not use LLM — purely infrastructure-based analysis.
POST /api/v3/domain/analyze
Analyze a domain for trustworthiness indicators.
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
domain |
string | Conditional | Domain name (e.g., reuters.com) |
url |
string | Conditional | Full URL — domain is extracted automatically |
Provide at least one. If both are given,
domaintakes precedence.
Example:
curl -sk -X POST https://localhost:3000/agent-v3/api/v3/domain/analyze \
-H "Content-Type: application/json" \
-d '{"url": "https://reuters.com", "user_id": "test-user"}'
Response (200):
{
"success": true,
"data": {
"domain": "reuters.com",
"verdict": "TRUSTED",
"trust_score": 90,
"risk_level": "LOW",
"age": {
"days": 11977,
"category": "WELL_ESTABLISHED",
"created_at": "1993-06-17T00:00:00Z"
},
"blacklist": {
"is_blacklisted": false,
"reputation_score": 100
},
"ssl": {
"has_ssl": true,
"is_valid": true,
"issuer": "CN=Sectigo Public Server Authentication CA OV R40, O=Sectigo Limited, C=GB"
},
"ownership": {
"registrar": "CSC Corporate Domains, Inc.",
"organization": "Thomson Reuters Enterprise Centre GmbH",
"country": "CH"
},
"red_flags": [],
"warnings": [],
"metadata": {
"duration_ms": 8054
}
}
}
Verdict values:
| Verdict | Meaning |
|---|---|
TRUSTED |
Established domain, high reputation, no flags |
NEUTRAL |
No strong signals either way |
SUSPICIOUS |
One red flag or multiple warnings |
UNTRUSTED |
Multiple red flags or blacklisted |
Possible red flags: DOMAIN_VERY_NEW, BLACKLISTED, LOW_REPUTATION, NO_SSL, INVALID_SSL, NO_DNS_RECORDS, SUSPICIOUS_DOMAIN
Possible warnings: DOMAIN_RELATIVELY_NEW, MEDIUM_REPUTATION, SELF_SIGNED_SSL, NO_EMAIL_SECURITY, HOSTED_IN_DATACENTER, WHOIS_PRIVACY_ENABLED
POST /api/v3/domain/analyze-async
Queue-based asynchronous domain analysis.
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
domain |
string | Conditional | Domain name |
url |
string | Conditional | URL (domain extracted) |
plan_type |
integer | No | Queue priority tier 1–6. Default: 1 |
6. Polling & Results
After submitting an async analysis, use these endpoints to track progress and retrieve results.
GET /api/v3/pipeline/:sessionId/status
Poll the status of a running or completed analysis.
Example:
curl -sk https://localhost:3000/agent-v3/api/v3/pipeline/a63a72ed-de8e-458b-a708-3e80d38f867c/status \
Response (200):
{
"success": true,
"data": {
"session_id": "a63a72ed-...",
"status": "completed",
"components": {
"domain": { "status": "skipped" },
"techniques": { "status": "completed" },
"ai_tampered": { "status": "completed" },
"claims": { "status": "completed" },
"verdict": { "status": "completed" }
},
"progress": {
"completed": 4,
"total": 4,
"percentage": 100
}
}
}
Component status values: pending | running | completed | failed | skipped
GET /api/v3/pipeline/:sessionId/result
Get the full result of a completed analysis. Returns the complete AnalysisSession object (same structure as the /analyze response data).
Falls back to PostgreSQL if the session has expired from Redis cache.
Example:
curl -sk https://localhost:3000/agent-v3/api/v3/pipeline/a63a72ed-de8e-458b-a708-3e80d38f867c/result \
GET /api/v3/pipeline/:sessionId/component/:name
Get a single component's result from a completed analysis.
Path parameter: :name — one of: techniques, ai_tampered, claims, domain, verdict
Example:
curl -sk https://localhost:3000/agent-v3/api/v3/pipeline/a63a72ed-.../component/verdict \
GET /api/v3/pipeline/:sessionId/queue-status
Poll progress of an async (RabbitMQ) job. Returns partial results as components complete.
Example:
curl -sk https://localhost:3000/agent-v3/api/v3/pipeline/b7f3a1e2-.../queue-status \
Response (200):
{
"success": true,
"data": {
"session_id": "b7f3a1e2-...",
"status": "running",
"techniques": { "manipulation_score": 35, "..." : "..." },
"ai_tampered": null,
"claims": null,
"_queue": {
"progress": 33,
"total_components": 3,
"completed_components": ["techniques"],
"elapsed_ms": 25000,
"plan_type": 2
}
}
}
7. Browser Extension API
Separate authentication flow using API keys instead of JWT. Designed for the DIDI browser extension.
POST /api/v3/pipeline/extension/analyze
Analyze content using an API key.
Headers:
| Header | Required | Description |
|---|---|---|
X-API-Key |
Yes | Extension API key (obtained from the admin dashboard) |
Content-Type |
Yes | application/json |
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
text |
string | Conditional | Text to analyze |
image_url |
string | Conditional | Image URL to analyze |
url |
string | Conditional | URL to analyze |
options |
object | No | { skip_components: string[] } |
Provide at least one of
text,image_url, orurl.
Example:
curl -sk -X POST https://localhost:3000/agent-v3/api/v3/pipeline/extension/analyze \
-H "Content-Type: application/json" \
-H "X-API-Key: didi_ext_abc123..." \
-d '{"text": "Content to check for misinformation"}'
Response (200): Same structure as /pipeline/analyze, with an additional analysis_type field indicating what was analyzed (text, image, or url).
Error Codes
| HTTP | Code | Description |
|---|---|---|
400 |
INVALID_TEXT_INPUT |
Text validation failed (too short, too long, invalid encoding) |
400 |
ASYNC_REQUIRED |
Audio/video content must use the async endpoint |
401 |
— | Missing or invalid JWT token / API key |
402 |
— | Insufficient credits. Response includes creditsRemained and creditCost |
404 |
— | Session not found |
500 |
— | Internal server error |
Rate Limits
Applied by Kong at the gateway level:
| Window | Limit |
|---|---|
| Per minute | 100 requests |
| Per hour | 2,000 requests |
| Per day | 10,000 requests |
Timeouts
| Endpoint Type | Timeout |
|---|---|
| Full pipeline (text) | 180 seconds |
| Full pipeline (video) | 660 seconds (11 min) |
| Individual component (text) | 180 seconds |
| Individual component (media) | 300 seconds (5 min) |
| Domain analysis | 90 seconds |