didi-lot2-backend/backend/services/orchestration-layer/agent-v3/API_DOCUMENTATION.md
2026-07-10 03:39:53 -07:00

1051 lines
31 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 25) 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 510 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 510 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 16 (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 16. 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` | 5079% | Mixed signals |
| `POSSIBLY_HUMAN` | 2049% | 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 16. 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 |