Overview Documentation API Reference Playground Pricing
Sign In Get API Key

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"}'
💡
Try the API without signing up in the Playground — no API key required for basic usage.

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 (check Retry-After header)
  • 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"},
])