FactiveAPI Documentation
The FactiveAPI lets you verify any content for factual accuracy. Submit text, URLs, PDFs, videos, or images and receive structured results with individual claims, verdicts, and source citations.
Quickstart
Get from zero to your first verified claim in under 2 minutes.
1. Get your API key
Create an account at factivelabs.com/register and generate an API key from your dashboard under Account → API Access.
2. Install the Python SDK (optional)
pip install factivelabs
3. Verify your first claim
from factivelabs import FactiveLabs
client = FactiveLabs(api_key="YOUR_API_KEY")
result = client.verify(
content="The Great Wall of China is visible from space.",
mode="text"
)
for claim in result.claims:
print(f"{claim.verdict}: {claim.text}")
print(f" Explanation: {claim.explanation}")
for source in claim.sources:
print(f" Source: {source.url}")
Or use cURL directly:
curl -X POST https://api.factivelabs.com/api/v1/verify \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"content": "The Great Wall of China is visible from space.", "mode": "text"}'
Authentication
All API requests require a Bearer token in the Authorization header:
Authorization: Bearer fctv_live_sk_abc123...
API keys are prefixed with fctv_live_sk_ for live keys and fctv_test_sk_ for test keys. Keys are hashed (SHA-256) before storage — we never store your key in plaintext.
Generate and manage keys from Account → API Access in your dashboard.
Base URL
https://api.factivelabs.com
All endpoints are versioned under /api/v1/. The current version is v1.
Verify Content
The primary endpoint is POST /api/v1/verify. Send content in the request body and receive structured verification results.
Request Body
{
"content": "Text to verify, or a URL",
"mode": "text", // "text", "url", "youtube", "tiktok", "pdf", "docx", "image"
"stream": false, // Enable SSE streaming
"async": false, // Enable async job mode
"filter_tables": true // Skip granular table/statistical claims (default: true)
}
Response
{
"id": "ver_abc123",
"status": "completed",
"claims": [
{
"text": "The Great Wall of China is visible from space",
"verdict": "disputed",
"explanation": "This is a common misconception. The Great Wall is not visible to the unaided eye from low Earth orbit...",
"sources": [
{
"title": "NASA - Great Wall of China",
"url": "https://www.nasa.gov/...",
"snippet": "The Great Wall can barely be seen from the shuttle..."
}
],
"offset": { "start": 0, "end": 49 }
}
],
"usage": {
"claims_extracted": 1,
"claims_verified": 1,
"content_length": 49
}
}
Response Modes
Synchronous (default)
The request blocks until all claims are extracted and verified. Returns the complete result in a single JSON response. Best for short content (under 5,000 characters).
Streaming (SSE)
Set "stream": true to receive Server-Sent Events. Each event contains one claim as it's verified. This is ideal for building real-time UIs that show results progressively.
event: claim
data: {"text": "...", "verdict": "confirmed", ...}
event: claim
data: {"text": "...", "verdict": "disputed", ...}
event: done
data: {"claims_total": 5, "usage": {...}}
Asynchronous (polling)
Set "async": true to immediately receive a job ID. Poll GET /api/v1/jobs/{id} to check status. Best for large documents and batch processing.
// Submit
POST /api/v1/verify {"content": "...", "async": true}
// Response: {"job_id": "job_xyz789", "status": "processing"}
// Poll
GET /api/v1/jobs/job_xyz789
// Response: {"status": "completed", "claims": [...], "usage": {...}}
Verdicts Explained
Every verified claim receives one of three verdicts:
- confirmed — The claim is factually supported by evidence from multiple reliable sources.
- disputed — The claim contradicts evidence. The explanation details what's wrong and what the evidence actually says.
- inconclusive — Evidence is insufficient, conflicting, or the claim is too subjective to verify definitively.
Each verdict comes with a plain-English explanation and one or more source citations with URLs.
Input Formats
The mode parameter determines how content is processed:
text— Raw text. Send the content you want verified directly.url— Web page URL. We'll extract the article text and verify it.youtube— YouTube video URL. We extract the transcript and verify claims.tiktok— TikTok video URL. Transcript extraction and verification.pdf— Pass a URL to a PDF file. We extract text (with OCR for scanned documents) and verify.docx— Pass a URL to a DOCX file. We extract text and verify.image— Pass a URL to an image. We run OCR to extract text, then verify claims found.
Claim Extraction
The POST /api/v1/extract endpoint runs ProRata's claim extraction engine without the verification step. It decomposes text into individual, atomic claims — each one a self-contained verifiable statement.
This is significantly faster and cheaper than full verification ($0.002/claim vs $0.01/claim), making it ideal for high-volume content decomposition, pre-processing for your own pipeline, or AI agent reasoning.
Request
POST /api/v1/extract
{
"content": "Einstein failed math. The Great Wall is visible from space.",
"content_type": "text",
"max_claims": 100
}
Response
{
"id": "ex_abc123",
"status": "complete",
"claims": [
{
"text": "Einstein failed math",
"sentence": "Einstein failed math.",
"start_offset": 0,
"end_offset": 20,
"filtered": false
},
{
"text": "The Great Wall is visible from space",
"sentence": "The Great Wall is visible from space.",
"start_offset": 22,
"end_offset": 58,
"filtered": false
}
],
"claims_count": 2,
"usage": {
"claims_extracted": 2,
"claims_filtered": 0,
"content_length": 58,
"cost_usd": 0.004
}
}
Extract vs Verify
Choose the right endpoint for your use case:
- Extract (
/api/v1/extract) — Returns claims only. No verdicts, no sources, no verification. ~2-5x faster, ~5x cheaper. Use when you need to decompose content into claims for your own downstream processing. - Verify (
/api/v1/verify) — Returns claims with verdicts (confirmed/disputed/inconclusive), explanations, and source citations. Use when you need end-to-end fact-checking.
Batch Processing
Submit up to 100 documents in a single request using POST /api/v1/verify/batch:
{
"items": [
{"content": "Claim one to verify", "mode": "text"},
{"content": "https://example.com/article", "mode": "url"},
{"content": "Another claim to check", "mode": "text"}
]
}
Each item is processed independently. Results are returned as an array in the same order. Batch limits vary by plan (Free: 5, Pro: 50, Enterprise: 100).
Async Jobs
When you set "async": true, the API returns a job ID immediately. Use this to process large documents without holding a connection open.
GET /api/v1/jobs/{job_id}
// Pending:
{"job_id": "job_xyz789", "status": "processing", "progress": 0.45}
// Complete:
{"job_id": "job_xyz789", "status": "completed", "claims": [...], "usage": {...}}
// Failed:
{"job_id": "job_xyz789", "status": "failed", "error": "Content too large"}
Poll every 2-5 seconds. Jobs expire after 24 hours.
Error Handling
The API uses standard HTTP status codes. Error responses include a JSON body with details:
{
"error": {
"code": "rate_limit_exceeded",
"message": "You have exceeded the rate limit of 10 requests per minute.",
"retry_after": 45
}
}
400— Bad request (invalid parameters, missing content)401— Unauthorized (missing or invalid API key)403— Forbidden (plan limit exceeded, account disabled)404— Not found (invalid job ID)413— Content too large (exceeds plan's character limit)429— Rate limit exceeded (checkRetry-Afterheader)500— Internal server error
Rate Limits
Rate limits are applied per API key. The current limits by plan:
- Free: 10 requests/minute, 10,000 character limit per request
- Pro: 60 requests/minute, 50,000 character limit per request
- Enterprise: 300 requests/minute, 100,000 character limit per request
Rate limit information is included in response headers:
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 7
X-RateLimit-Reset: 1711843200
Python SDK
The official Python SDK provides a typed, convenient wrapper around the REST API.
pip install factivelabs
Sync client
from factivelabs import FactiveLabs
client = FactiveLabs(api_key="YOUR_API_KEY")
# Verify text
result = client.verify(content="Some claim to check", mode="text")
# Verify a URL
result = client.verify(content="https://example.com/article", mode="url")
# Access results
for claim in result.claims:
print(claim.verdict, claim.text, claim.explanation)
Async client
from factivelabs import AsyncFactiveLabs
client = AsyncFactiveLabs(api_key="YOUR_API_KEY")
result = await client.verify(content="Some claim", mode="text")
Batch verification
results = client.batch_verify(items=[
{"content": "Claim 1", "mode": "text"},
{"content": "Claim 2", "mode": "text"},
])