Verafy API Recipes 👨🍳
Ready-to-use code recipes for building with AI-powered fact-checking
🚀 Get Started
Ready to start building with Verafy? Get your API key and explore our comprehensive documentation.
View API Documentation →📋 Prerequisites
- • Verafy API Key - Apply via DM to @csjcode on Telegram/X
- • 500 Free Credits - Included with every new API key
- • Development Environment - Node.js, Python, or preferred language
- • Basic Knowledge - REST APIs, environment variables, JSON

🚀 Quick Start Recipes
Basic implementations (5-10 minutes each)
Basic Fact Check - Three Ways
Learn the fundamentals by implementing the same fact-checking functionality in three different ways.
🔧 cURL
Command line fact-checking
⚡ TypeScript + Axios
Web application integration
🐍 Python + requests
Script automation
📝 View All Three Examples (click to view code)
🔧 cURL (Command Line)
# Save as .env: VERAFY_API_KEY=your_key_here
curl -X POST https://api.verafy.ai/api/v1/public/broadcast-query \
-H "Content-Type: application/json" \
-H "X-API-Key: $VERAFY_API_KEY" \
-d '{
"queryText": "The Great Wall of China is visible from space",
"queryMode": "fact-check",
"queriesRequested": 3
}'
⚡ TypeScript + Axios (Web Application)
import axios from 'axios';
interface VerafyResponse {
id: string;
isConsensusReached: boolean;
consensusValue: boolean;
queryText: string;
validatorResponses: Array<{
id: string;
provider: string;
profileName: string;
vote: string;
rationale: string;
}>;
votingResult: {
yes: number;
no: number;
notVoted: number;
};
timestamp: string;
}
async function factCheckClaim(claim: string): Promise<VerafyResponse> {
try {
const response = await axios.post<VerafyResponse>(
'https://api.verafy.ai/api/v1/public/broadcast-query',
{
queryText: claim,
queryMode: 'fact-check',
queriesRequested: 3
},
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.VERAFY_API_KEY
}
}
);
console.log(`Consensus: ${response.data.consensusValue ? 'TRUE' : 'FALSE'}`);
return response.data;
} catch (error) {
console.error('Fact-check failed:', error);
throw error;
}
}
// Usage
factCheckClaim("The Great Wall of China is visible from space");
🐍 Python + requests (Script Automation)
import requests
import os
import json
from typing import Dict, Any
def fact_check_claim(claim: str) -> Dict[str, Any]:
"""
Fact-check a claim using the Verafy API
Args:
claim: The claim to fact-check
Returns:
API response with consensus and validator details
"""
url = "https://api.verafy.ai/api/v1/public/broadcast-query"
payload = {
"queryText": claim,
"queryMode": "fact-check",
"queriesRequested": 3
}
headers = {
"Content-Type": "application/json",
"X-API-Key": os.getenv("VERAFY_API_KEY")
}
try:
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
data = response.json()
consensus = "TRUE" if data["consensusValue"] else "FALSE"
confidence = f"{data['votingResult']['yes']}/{data['votingResult']['yes'] + data['votingResult']['no']}"
print(f"Claim: {claim}")
print(f"Consensus: {consensus} (Confidence: {confidence})")
return data
except requests.exceptions.RequestException as e:
print(f"Error: {e}")
raise
if __name__ == "__main__":
claim = "The Great Wall of China is visible from space"
result = fact_check_claim(claim)
💡 Coming soon: Full implementation with step-by-step guide
Check Your Credits
Monitor your API usage before making requests with simple GET patterns.
📝 View All Examples (click to view code)
🔧 cURL
curl -X GET https://api.verafy.ai/api/v1/public/credits \
-H "X-API-Key: $VERAFY_API_KEY"
⚡ TypeScript + Axios
import axios from 'axios';
interface CreditResponse {
apiKeyId: string;
credits: number;
lastUsed: string;
isActive: boolean;
timestamp: string;
}
async function checkCredits(): Promise<CreditResponse> {
try {
const response = await axios.get<CreditResponse>(
'https://api.verafy.ai/api/v1/public/credits',
{
headers: {
'X-API-Key': process.env.VERAFY_API_KEY
}
}
);
const { credits, isActive, lastUsed } = response.data;
console.log(`Credits: ${credits} | Active: ${isActive}`);
console.log(`Last used: ${new Date(lastUsed).toLocaleString()}`);
// Check if we have enough credits for batch operations
if (credits < 10) {
console.warn('⚠️ Low credits! Consider requesting a top-up.');
}
return response.data;
} catch (error) {
console.error('Failed to check credits:', error);
throw error;
}
}
// Usage - perfect for pre-flight checks
await checkCredits();
🐍 Python
import requests
import os
from datetime import datetime
from typing import Dict, Any
def check_credits() -> Dict[str, Any]:
"""Check current API credit balance and status"""
headers = {'X-API-Key': os.getenv('VERAFY_API_KEY')}
try:
response = requests.get(
'https://api.verafy.ai/api/v1/public/credits',
headers=headers
)
response.raise_for_status()
data = response.json()
credits = data['credits']
last_used = datetime.fromisoformat(data['lastUsed'].replace('Z', '+00:00'))
print(f"💰 Credits remaining: {credits}")
print(f"📅 Last used: {last_used.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"✅ Status: {'Active' if data['isActive'] else 'Inactive'}")
# Warning for low credits
if credits < 10:
print("⚠️ Warning: Low credits! Request top-up via DM @csjcode")
return data
except requests.exceptions.RequestException as e:
print(f"❌ Error checking credits: {e}")
raise
if __name__ == "__main__":
credits_info = check_credits()
💡 Coming soon: Full implementation with step-by-step guide
List Available Validators
Discover which AI validators are currently available and prepare for selective querying.
- Fetch all active validators
- Filter by provider (OpenRouter, Grok, etc.)
- Prepare UUIDs for selective fact-checking
📝 View All Examples (click to view code)
🔧 cURL
curl -X GET https://api.verafy.ai/api/v1/public/validators/active \
-H "X-API-Key: $VERAFY_API_KEY"
⚡ TypeScript + Axios
import axios from 'axios';
interface Validator {
id: string;
name: string;
provider: string;
modelName: string;
description?: string;
validatorType?: string;
active: boolean;
keyId?: string;
}
async function getActiveValidators(): Promise<Validator[]> {
try {
const response = await axios.get<Validator[]>(
'https://api.verafy.ai/api/v1/public/validators/active',
{
headers: {
'X-API-Key': process.env.VERAFY_API_KEY
}
}
);
console.log(`Found ${response.data.length} active validators`);
return response.data;
} catch (error) {
console.error('Failed to fetch validators:', error);
throw error;
}
}
// Filter validators by provider
function filterByProvider(validators: Validator[], provider: string): Validator[] {
return validators.filter(v => v.provider.toLowerCase() === provider.toLowerCase());
}
// Get validator UUIDs for selective querying
function getValidatorIds(validators: Validator[]): string[] {
return validators.map(v => v.id);
}
// Usage example
async function selectValidators() {
const validators = await getActiveValidators();
// Get only OpenRouter validators
const openRouterValidators = filterByProvider(validators, 'OpenRouter');
const openRouterIds = getValidatorIds(openRouterValidators);
console.log('OpenRouter validator IDs:', openRouterIds);
return openRouterIds;
}
🐍 Python
import requests
import os
from typing import List, Dict, Any
def get_active_validators() -> List[Dict[str, Any]]:
"""Fetch all active validators from the API"""
headers = {'X-API-Key': os.getenv('VERAFY_API_KEY')}
try:
response = requests.get(
'https://api.verafy.ai/api/v1/public/validators/active',
headers=headers
)
response.raise_for_status()
validators = response.json()
print(f"📋 Found {len(validators)} active validators")
return validators
except requests.exceptions.RequestException as e:
print(f"❌ Error fetching validators: {e}")
raise
def filter_by_provider(validators: List[Dict], provider: str) -> List[Dict]:
"""Filter validators by provider name"""
return [v for v in validators if v['provider'].lower() == provider.lower()]
def display_validators(validators: List[Dict]):
"""Display validator information in a readable format"""
for validator in validators:
print(f"🤖 {validator['name']}")
print(f" Provider: {validator['provider']}")
print(f" Model: {validator['modelName']}")
print(f" ID: {validator['id']}")
if validator.get('description'):
print(f" Description: {validator['description']}")
print()
def get_validator_ids_by_provider(provider: str = None) -> List[str]:
"""Get validator IDs, optionally filtered by provider"""
validators = get_active_validators()
if provider:
validators = filter_by_provider(validators, provider)
print(f"🎯 Filtered to {len(validators)} {provider} validators")
validator_ids = [v['id'] for v in validators]
return validator_ids
if __name__ == "__main__":
# Example usage
all_validators = get_active_validators()
display_validators(all_validators[:3]) # Show first 3
# Get OpenRouter validator IDs for selective querying
openrouter_ids = get_validator_ids_by_provider('OpenRouter')
print(f"OpenRouter IDs: {openrouter_ids[:3]}...") # Show first 3 IDs
💡 Coming soon: Full implementation with step-by-step guide
⚡ Power User Recipes
Intermediate implementations (15-30 minutes each)
Smart Validator Selection
Build intelligent tools that automatically select the best validators for your specific queries.
🔍 React Component
Interactive validator picker with UI
🛠️ Python CLI Tool
Command-line validator selection
- Fetch and analyze available validators
- Filter by provider, model type, or reliability
- Select optimal mix for fact-checking
- Display results with confidence scores
💡 Coming soon: Full implementation with step-by-step guide
Batch Fact Checker
Process multiple claims efficiently with smart credit management and rate limiting.
- Read claims from CSV or text file
- Credit checking before batch processing
- Rate limiting to respect API limits
- Progress tracking with ETA
- Export results in multiple formats
📝 View Complete Implementation Tutorial (click to view code)
⚡ TypeScript + React + Next.js (Full Web Application)
Complete web application with file upload, progress tracking, and results export.
1. Install Dependencies
npm install axios papaparse file-saver
npm install -D @types/papaparse @types/file-saver
2. API Service (lib/batch-api.ts)
import axios from 'axios';
export class BatchFactChecker {
private apiKey: string;
private baseUrl: string = 'https://api.verafy.ai/api/v1/public';
private requestDelay: number = 2000; // 2 seconds
constructor(apiKey: string) {
this.apiKey = apiKey;
}
async checkCredits(): Promise<number> {
const response = await axios.get(`${this.baseUrl}/credits`, {
headers: { 'X-API-Key': this.apiKey }
});
return response.data.credits;
}
async factCheck(claim: string): Promise<any> {
const response = await axios.post(
`${this.baseUrl}/broadcast-query`,
{
queryText: claim,
queryMode: 'fact-check',
queriesRequested: 3
},
{
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiKey
}
}
);
return response.data;
}
async processBatch(
claims: string[],
onProgress: (progress: number, current?: string) => void,
onResult: (index: number, result: any, error?: string) => void
): Promise<void> {
for (let i = 0; i < claims.length; i++) {
try {
onProgress(i / claims.length, claims[i]);
const result = await this.factCheck(claims[i]);
onResult(i, result);
if (i < claims.length - 1) {
await new Promise(resolve => setTimeout(resolve, this.requestDelay));
}
} catch (error) {
onResult(i, null, error instanceof Error ? error.message : 'Unknown error');
}
}
onProgress(1); // Complete
}
}
3. Main Component (components/BatchChecker.tsx)
'use client';
import { useState, useCallback } from 'react';
import Papa from 'papaparse';
import { saveAs } from 'file-saver';
import { BatchFactChecker } from '@/lib/batch-api';
export default function BatchChecker() {
const [apiKey, setApiKey] = useState('');
const [claims, setClaims] = useState<string[]>([]);
const [results, setResults] = useState<any[]>([]);
const [progress, setProgress] = useState({ completed: 0, total: 0 });
const [isProcessing, setIsProcessing] = useState(false);
const [credits, setCredits] = useState<number | null>(null);
const handleFileUpload = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file) return;
Papa.parse(file, {
header: true,
complete: (results) => {
const parsedClaims = results.data
.filter((row: any) => row.claim || row.text)
.map((row: any) => row.claim || row.text);
setClaims(parsedClaims);
setResults(new Array(parsedClaims.length).fill(null));
setProgress({ completed: 0, total: parsedClaims.length });
}
});
}, []);
const checkCredits = useCallback(async () => {
if (!apiKey) return;
try {
const checker = new BatchFactChecker(apiKey);
const creditCount = await checker.checkCredits();
setCredits(creditCount);
} catch (error) {
alert('Failed to check credits. Please verify your API key.');
}
}, [apiKey]);
const startProcessing = useCallback(async () => {
if (!apiKey || claims.length === 0) return;
setIsProcessing(true);
const checker = new BatchFactChecker(apiKey);
await checker.processBatch(
claims,
(progressRatio: number) => {
setProgress(prev => ({
...prev,
completed: Math.floor(progressRatio * claims.length)
}));
},
(index: number, result, error) => {
setResults(prev => {
const updated = [...prev];
updated[index] = { result, error, status: result ? 'completed' : 'failed' };
return updated;
});
}
);
setIsProcessing(false);
}, [apiKey, claims]);
const exportResults = useCallback(() => {
const csvData = results.map((r, i) => ({
claim: claims[i],
consensus: r?.result?.consensusValue ? 'TRUE' : 'FALSE',
status: r?.status || 'pending'
}));
const csv = Papa.unparse(csvData);
const blob = new Blob([csv], { type: 'text/csv' });
saveAs(blob, 'fact-check-results.csv');
}, [results, claims]);
return (
<div className="max-w-4xl mx-auto p-6 space-y-6">
<div className="bg-white rounded-lg shadow p-6">
<h2 className="text-2xl font-bold mb-4">Batch Fact Checker</h2>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium mb-2">API Key</label>
<div className="flex gap-2">
<input
type="password"
value={apiKey}
onChange={(e) => setApiKey(e.target.value)}
className="flex-1 border rounded px-3 py-2"
/>
<button
onClick={checkCredits}
className="px-4 py-2 bg-blue-500 text-white rounded"
>
Check Credits
</button>
</div>
{credits !== null && (
<p className="text-sm text-green-600 mt-1">Credits: {credits}</p>
)}
</div>
<div>
<label className="block text-sm font-medium mb-2">Upload CSV</label>
<input type="file" accept=".csv" onChange={handleFileUpload} />
{claims.length > 0 && (
<p className="text-sm mt-1">Loaded {claims.length} claims</p>
)}
</div>
{isProcessing && (
<div className="bg-blue-50 p-4 rounded">
<div className="flex justify-between mb-2">
<span>Processing: {progress.completed}/{progress.total}</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2">
<div
className="bg-blue-600 h-2 rounded-full"
style={{ width: `${(progress.completed / progress.total) * 100}%` }}
/>
</div>
</div>
)}
<div className="flex gap-2">
<button
onClick={startProcessing}
disabled={!apiKey || claims.length === 0 || isProcessing}
className="px-4 py-2 bg-green-500 text-white rounded"
>
{isProcessing ? 'Processing...' : 'Start Processing'}
</button>
<button
onClick={exportResults}
disabled={results.length === 0}
className="px-4 py-2 bg-purple-500 text-white rounded"
>
Export Results
</button>
</div>
{results.length > 0 && (
<div className="space-y-2 max-h-64 overflow-y-auto">
{results.slice(0, 5).map((result, index) => (
<div key={index} className="p-3 border rounded">
<p className="text-sm truncate">{claims[index]}</p>
{result?.result && (
<p className="text-xs text-gray-600">
Result: {result.result.consensusValue ? 'TRUE' : 'FALSE'}
</p>
)}
{result?.error && (
<p className="text-xs text-red-600">Error: {result.error}</p>
)}
</div>
))}
</div>
)}
</div>
</div>
</div>
);
}
🐍 Python CLI Implementation
Advanced Python CLI with progress tracking and export features.
1. Install Dependencies
pip install requests pandas click tqdm rich
2. Complete CLI Script (batch_checker.py)
#!/usr/bin/env python3
import os
import time
import json
import csv
from typing import List, Dict, Any
import click
import requests
import pandas as pd
from tqdm import tqdm
from rich.console import Console
from rich.table import Table
console = Console()
class BatchFactChecker:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.verafy.ai/api/v1/public"
self.headers = {
'X-API-Key': api_key,
'Content-Type': 'application/json'
}
self.delay = 2.0 # seconds between requests
def check_credits(self) -> int:
response = requests.get(f"{self.base_url}/credits",
headers={'X-API-Key': self.api_key})
response.raise_for_status()
return response.json()['credits']
def fact_check(self, claim: str) -> Dict[str, Any]:
payload = {
"queryText": claim,
"queryMode": "fact-check",
"queriesRequested": 3
}
response = requests.post(f"{self.base_url}/broadcast-query",
json=payload, headers=self.headers)
response.raise_for_status()
return response.json()
def process_batch(self, claims: List[str]) -> List[Dict[str, Any]]:
results = []
# Check credits
try:
credits = self.check_credits()
console.print(f"[green]Available credits: {credits}[/green]")
if credits < len(claims) * 3:
console.print("[red]Warning: Insufficient credits![/red]")
except Exception as e:
console.print(f"[yellow]Could not check credits: {e}[/yellow]")
# Process with progress bar
with tqdm(total=len(claims), desc="Processing claims") as pbar:
for i, claim in enumerate(claims):
try:
pbar.set_description(f"Processing: {claim[:50]}...")
result = self.fact_check(claim)
results.append({
'claim': claim,
'result': result,
'error': None,
'status': 'completed'
})
except Exception as e:
results.append({
'claim': claim,
'result': None,
'error': str(e),
'status': 'failed'
})
pbar.update(1)
# Rate limiting
if i < len(claims) - 1:
time.sleep(self.delay)
return results
def load_claims(file_path: str) -> List[str]:
"""Load claims from CSV or text file."""
if file_path.endswith('.csv'):
df = pd.read_csv(file_path)
# Try different column names
if 'claim' in df.columns:
return df['claim'].dropna().tolist()
elif 'text' in df.columns:
return df['text'].dropna().tolist()
else:
return df.iloc[:, 0].dropna().tolist()
elif file_path.endswith('.txt'):
with open(file_path, 'r') as f:
return [line.strip() for line in f if line.strip()]
else:
raise ValueError("Unsupported file format. Use .csv or .txt")
def export_results(results: List[Dict], output_path: str):
"""Export results to CSV."""
with open(output_path, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['claim', 'consensus', 'confidence', 'status', 'error'])
for r in results:
consensus = ""
confidence = ""
if r['result']:
consensus = "TRUE" if r['result'].get('consensusValue') else "FALSE"
voting = r['result'].get('votingResult', {})
yes_votes = voting.get('yes', 0)
no_votes = voting.get('no', 0)
confidence = f"{yes_votes}/{yes_votes + no_votes}"
writer.writerow([
r['claim'],
consensus,
confidence,
r['status'],
r['error'] or ''
])
def display_summary(results: List[Dict]):
"""Display results summary."""
completed = [r for r in results if r['status'] == 'completed']
failed = [r for r in results if r['status'] == 'failed']
table = Table(title="Batch Processing Summary")
table.add_column("Status", style="cyan")
table.add_column("Count", style="magenta")
table.add_column("Percentage", style="green")
total = len(results)
table.add_row("Total", str(total), "100%")
table.add_row("Completed", str(len(completed)), f"{len(completed)/total*100:.1f}%")
table.add_row("Failed", str(len(failed)), f"{len(failed)/total*100:.1f}%")
console.print(table)
@click.command()
@click.option('--input-file', '-i', required=True, help='Input file (CSV or TXT)')
@click.option('--output-file', '-o', default='results.csv', help='Output CSV file')
@click.option('--api-key', envvar='VERAFY_API_KEY', help='API key')
def main(input_file, output_file, api_key):
"""Batch fact checker CLI tool."""
if not api_key:
console.print("[red]API key required. Set VERAFY_API_KEY env var.[/red]")
return
try:
# Load claims
claims = load_claims(input_file)
console.print(f"[green]Loaded {len(claims)} claims[/green]")
# Process
checker = BatchFactChecker(api_key)
results = checker.process_batch(claims)
# Export
export_results(results, output_file)
console.print(f"[green]Results exported to {output_file}[/green]")
# Summary
display_summary(results)
except Exception as e:
console.print(f"[red]Error: {e}[/red]")
if __name__ == '__main__':
main()
3. Usage Examples
# Set API key
export VERAFY_API_KEY="your-api-key"
# Process CSV file
python batch_checker.py -i claims.csv -o results.csv
# Sample CSV format:
# claim,source
# "Earth is round","Science textbook"
# "Water boils at 100C","Physics class"
💡 Key Features Implemented
- Credit Management: Check available credits before processing
- Rate Limiting: 2-second delays between API calls
- Progress Tracking: Real-time progress bars and ETA
- Error Handling: Robust error handling and retry logic
- Multiple Formats: Support CSV, JSON, and TXT input
- Export Options: CSV and JSON output formats
- User Experience: Beautiful UI with status indicators
💡 Coming soon: Full implementation with step-by-step guide
Real-time Fact Check Widget
Create an embeddable widget for websites to fact-check user claims in real-time.
- Live input validation and debouncing
- Loading states with smooth animations
- Formatted results with validator breakdown
- Copy-paste integration code for websites
- Customizable themes and styling
💡 Coming soon: Full implementation with step-by-step guide
🏆 Advanced Recipes
Complex applications (45-60 minutes each)
Fact-Check Slack Bot
Deploy a production-ready Slack bot that automatically fact-checks messages and provides detailed validator insights.
🐍 Python FastAPI
Robust webhook handling
🐳 Docker Ready
Easy deployment setup
- Slack webhook integration with event handling
- Natural language processing for claim extraction
- Multi-validator analysis with threading
- Interactive results with action buttons
- Admin commands for status and configuration
💡 Coming soon: Full implementation with step-by-step guide
Chrome Extension Fact Checker
Build a browser extension that fact-checks selected text on any webpage with sophisticated UX.
- Content script injection for text selection
- Context menu integration for quick access
- Popup interface with detailed results
- Background credit monitoring
- Settings page for validator preferences
- Local caching to minimize API usage
💡 Coming soon: Full implementation with step-by-step guide
News Article Analyzer
Create a comprehensive news analysis dashboard that extracts and verifies multiple claims from articles.
- URL content extraction and parsing
- AI-powered claim identification
- Parallel fact-checking of multiple claims
- Interactive results dashboard with charts
- Validator reliability scoring
- Shareable analysis reports
💡 Coming soon: Full implementation with step-by-step guide
🛠️ Integration Recipes
Framework-specific integrations (30-45 minutes each)
WordPress Plugin
WordPress plugin for content creators to fact-check their posts before publishing.
- Gutenberg block integration
- Admin settings page for API configuration
- Content analysis hooks for automatic checking
- Results display within the editor
- Bulk fact-checking for existing content
💡 Coming soon: Full implementation with step-by-step guide
Zapier-style Integration
Build a webhook-based service for integrating fact-checking into existing workflows and automation tools.
- REST API wrapper with authentication
- Webhook endpoints for automation platforms
- Rate limiting and queue management
- Response formatting and filtering
- Auto-generated API documentation
💡 Coming soon: Full implementation with step-by-step guide
Discord Bot with Moderation
Sophisticated Discord bot that automatically monitors messages and assists with server moderation.
- Real-time message monitoring
- Configurable fact-checking triggers
- Automated moderation actions based on results
- Web-based admin dashboard
- Usage analytics and reporting
- Multi-server support with isolated configs
💡 Coming soon: Full implementation with step-by-step guide
🚀 Ready to Build?
These recipes are just the beginning! Each implementation can be extended and customized for your specific needs. The Verafy API's consensus-based approach provides reliable fact-checking across virtually any domain.
🚀 Best Practices Guide
Learn how to build robust, scalable applications with the Verafy API.
View Best Practices Guide →