1051 lines
31 KiB
Markdown
1051 lines
31 KiB
Markdown
# 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-v3` for testing. All curl examples in this document use this base URL with `-k` to accept the self-signed certificate.
|
||
|
||
---
|
||
|
||
## Table of Contents
|
||
|
||
1. [Authentication](#authentication)
|
||
2. [Full Pipeline](#1-full-pipeline)
|
||
3. [Manipulation Techniques](#2-manipulation-techniques)
|
||
4. [AI-Tampered Detection](#3-ai-tampered-detection)
|
||
5. [Claims Verification](#4-claims-verification)
|
||
6. [Domain Analysis](#5-domain-analysis)
|
||
7. [Polling & Results](#6-polling--results)
|
||
8. [Browser Extension API](#7-browser-extension-api)
|
||
9. [Error Codes](#error-codes)
|
||
|
||
---
|
||
|
||
## Authentication
|
||
|
||
Pass `user_id` in the request body to identify the user:
|
||
|
||
```bash
|
||
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=true` is set (default in staging), all credit limits are bypassed. Any `user_id` value 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`, or `url`. You can combine them — for example, provide both `text` and `url` to 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 `400` with `code: "ASYNC_REQUIRED"`. Use `POST /api/v3/pipeline/analyze-async` for audio and video content instead.
|
||
|
||
**Example:**
|
||
|
||
```bash
|
||
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):**
|
||
|
||
```json
|
||
{
|
||
"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 containing `youtube.com` or `youtu.be` is classified as a video platform.
|
||
|
||
**Parameters:**
|
||
|
||
| Field | Type | Required | Description |
|
||
|-------|------|----------|-------------|
|
||
| `url` | string | Yes | URL to analyze |
|
||
| `options` | object | No | Analysis options |
|
||
|
||
**Example:**
|
||
|
||
```bash
|
||
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`:
|
||
|
||
```json
|
||
{
|
||
"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](#6-polling--results) 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`, or `url`.
|
||
|
||
**Example:**
|
||
|
||
```bash
|
||
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):**
|
||
|
||
```json
|
||
{
|
||
"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 `200` with `{ "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:**
|
||
|
||
```bash
|
||
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):**
|
||
|
||
```json
|
||
{
|
||
"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:**
|
||
|
||
```bash
|
||
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:**
|
||
|
||
```bash
|
||
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):**
|
||
|
||
```json
|
||
{
|
||
"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:**
|
||
|
||
```bash
|
||
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:**
|
||
|
||
```bash
|
||
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):**
|
||
|
||
```json
|
||
{
|
||
"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:**
|
||
|
||
```bash
|
||
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](#post-apiv3techniquesanalyze-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:**
|
||
|
||
```bash
|
||
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):**
|
||
|
||
```json
|
||
{
|
||
"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:**
|
||
|
||
```bash
|
||
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](#post-apiv3techniquesanalyze-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, `domain` takes precedence.
|
||
|
||
**Example:**
|
||
|
||
```bash
|
||
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):**
|
||
|
||
```json
|
||
{
|
||
"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:**
|
||
|
||
```bash
|
||
curl -sk https://localhost:3000/agent-v3/api/v3/pipeline/a63a72ed-de8e-458b-a708-3e80d38f867c/status \
|
||
```
|
||
|
||
**Response (200):**
|
||
|
||
```json
|
||
{
|
||
"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:**
|
||
|
||
```bash
|
||
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:**
|
||
|
||
```bash
|
||
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:**
|
||
|
||
```bash
|
||
curl -sk https://localhost:3000/agent-v3/api/v3/pipeline/b7f3a1e2-.../queue-status \
|
||
```
|
||
|
||
**Response (200):**
|
||
|
||
```json
|
||
{
|
||
"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`, or `url`.
|
||
|
||
**Example:**
|
||
|
||
```bash
|
||
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 |
|