# Veritas B2B API SDK for Python

Official Python SDK for the Veritas News B2B API. Provides comprehensive access
to news articles, fact-checks, entities, media assets, and monitoring alerts.

## Features

- **Full API Coverage**: Access to all B2B API endpoints
- **Async & Sync Support**: Both async and synchronous clients
- **Type Hints**: Complete type annotations for IDE support
- **Automatic Retries**: Exponential backoff with jitter
- **Rate Limit Handling**: Built-in rate limit awareness
- **Pagination Helpers**: Async iterators for easy pagination
- **Sandbox Support**: Automatic test mode detection

## Installation

```bash
pip install veritas-sdk
```

## Quick Start

### Async Usage

```python
import asyncio
from veritas_sdk import VeritasClient

async def main():
    # Create client (auto-detects sandbox mode from key prefix)
    async with VeritasClient(api_key="sk_live_your_api_key") as client:
        # List articles
        response = await client.feed.list(limit=10, category="politics")
        for article in response["items"]:
            print(f"- {article['headline']}")

        # Search articles
        results = await client.search.query(
            q="climate change",
            category=["science", "politics"],
            from_date="2024-01-01",
        )
        print(f"Found {results['total']} articles")

        # Iterate through all results automatically
        async for article in client.feed.iterate(category="sports"):
            print(article["headline"])

asyncio.run(main())
```

### Sync Usage

```python
from veritas_sdk import SyncVeritasClient

with SyncVeritasClient(api_key="sk_live_your_api_key") as client:
    # List articles
    response = client.feed.list(limit=10)
    for article in response["items"]:
        print(article["headline"])

    # Verify a claim
    claim = client.claims.verify("The earth is flat")
    if claim:
        print(f"Verdict: {claim['verdict']}")
```

## API Resources

### Feed API

Access news articles with filtering and pagination.

```python
# List articles
response = await client.feed.list(
    limit=20,
    category="politics",
    topic="elections",
    lang="en",
    from_date="2024-01-01",
)

# Get single article
article = await client.feed.get("article-uuid")

# Get trending articles
trending = await client.feed.trending(hours=24, limit=10)

# Iterate through all articles
async for article in client.feed.iterate(category="business"):
    process(article)
```

### Search API

Full-text search with faceted results.

```python
# Search with filters
results = await client.search.query(
    q="artificial intelligence",
    category=["technology", "business"],
    bias=["center", "center-left", "center-right"],
    sort_by="relevance",
)

# Access aggregations
for bucket in results["aggregations"]["categories"]:
    print(f"{bucket['label']}: {bucket['count']}")

# Get autocomplete suggestions
suggestions = await client.search.suggest(q="pres", limit=5)
```

### Fact-Check API

Access fact-checked claims with ClaimReview structured data.

```python
# List claims
claims = await client.claims.list(verdict="false", limit=10)

# Search claims
results = await client.claims.search(q="vaccine efficacy")

# Quick verify
claim = await client.claims.verify("COVID vaccines contain microchips")
if claim:
    print(f"Verdict: {claim['verdict']}")
    print(f"Evidence: {claim['evidenceSummary']}")
```

### Entity API

Knowledge graph operations for people, organizations, and locations.

```python
# Search entities
results = await client.entities.search(
    q="Nana Akufo-Addo",
    type="person",
)

# Get entity with relationships
data = await client.entities.get_with_relationships("entity-uuid")
entity = data["entity"]
relationships = data["relationships"]

# Create entity
new_entity = await client.entities.create(
    name="Ghana Revenue Authority",
    type="organization",
    description="Tax authority of Ghana",
    aliases=["GRA"],
)

# Find or create
entity, created = await client.entities.find_or_create(
    name="John Doe",
    type="person",
)
```

### Media API

Access images, videos, and other media assets.

```python
# List media
media = await client.media.list(kind="image", role="featured_image")

# Get media for article
article_media = await client.media.for_article("article-uuid")

# Search media
results = await client.media.search(q="parliament", kind="video")

# Get best variant for responsive images
url = client.media.get_best_variant(asset, target_width=800)
```

### Alerts API

Set up monitoring and notifications.

```python
# Create keyword alert
subscription = await client.alerts.create_keyword_alert(
    name="Elections Alert",
    keywords=["election", "voting", "ballot"],
    webhook_url="https://example.com/webhook",
    frequency="instant",
)

# Create entity alert
await client.alerts.create_entity_alert(
    name="Track Ghana President",
    entity_ids=["entity-uuid"],
    email="alerts@example.com",
)

# Create breaking news alert
await client.alerts.create_breaking_news_alert(
    name="Breaking Politics",
    categories=["politics"],
    webhook_url="https://example.com/webhook",
)

# List subscriptions
subscriptions = await client.alerts.list(is_active=True)

# Get notifications
notifications = await client.alerts.notifications(delivered=False)

# Get monitoring stats
stats = await client.alerts.stats()
```

### Sandbox API

Manage test environment (test keys only).

```python
# Create test client
client = VeritasClient(api_key="sk_test_your_test_key")

# Get sandbox status
status = await client.sandbox.status()

# Configure sandbox
await client.sandbox.configure(
    seed="my-test-seed",
    simulated_latency_ms=500,
)

# Reset sandbox
await client.sandbox.reset(preserve_config=True)

# Force error for testing
await client.sandbox.force_error(503)
```

## Configuration

```python
client = VeritasClient(
    api_key="sk_live_your_api_key",
    base_url="https://api.veritas.news",  # Optional: custom API URL
    timeout=30.0,                          # Request timeout in seconds
    retry=True,                            # Enable automatic retries
    max_retries=3,                         # Maximum retry attempts
    headers={"X-Custom-Header": "value"},  # Custom headers
)
```

## Error Handling

```python
from veritas_sdk import (
    VeritasError,
    AuthenticationError,
    RateLimitError,
    NotFoundError,
    ValidationError,
    ServerError,
)

try:
    article = await client.feed.get("article-uuid")
except AuthenticationError:
    print("Invalid API key")
except NotFoundError as e:
    print(f"Article not found: {e.resource_id}")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after} seconds")
except ValidationError as e:
    print(f"Validation error: {e.details}")
except ServerError:
    print("Server error, please retry")
except VeritasError as e:
    print(f"API error: {e.message} (code: {e.code})")
```

## Type Hints

The SDK provides complete type hints for all API responses:

```python
from veritas_sdk import Article, Claim, Entity, MediaAsset

async def process_article(article: Article) -> None:
    headline: str = article["headline"]
    categories = article["categories"]  # List[Category]
    entities = article["entities"]       # List[EntityMention]
```

## License

MIT
