Skip to main content

Corpus Product API Integration Guide

This guide provides everything you need to integrate with the Intrace Corpus Product API.

Getting Started

1. Obtain API Key

Contact your Intrace representative to receive an API key. The API key is required for all requests.

2. Base URLs

Production: https://api.intrace.com Development: http://localhost:8000 (for testing)

3. Authentication

All requests must include your API key in the X-API-Key header:
curl -H "X-API-Key: your-api-key-here" \
  https://api.intrace.com/v1/corpus/events

Common Use Cases

Query Events by Category

Filter events by category to focus on specific domains:
import requests

response = requests.get(
    "https://api.intrace.com/v1/corpus/events",
    headers={"X-API-Key": "your-api-key"},
    params={
        "event_category": "cyber",
        "page": 1,
        "page_size": 50
    }
)

events = response.json()
print(f"Found {events['total']} cyber events")
for event in events['items']:
    print(f"- {event['title']}")

Filter by Date Range

Get events within a specific time period:
from datetime import date, timedelta

end_date = date.today()
start_date = end_date - timedelta(days=30)

response = requests.get(
    "https://api.intrace.com/v1/corpus/events",
    headers={"X-API-Key": "your-api-key"},
    params={
        "date_from": start_date.isoformat(),
        "date_to": end_date.isoformat(),
        "event_category": "conflict",
        "country": "Ukraine"
    }
)

Search Events

Search across event titles and descriptions:
response = requests.get(
    "https://api.intrace.com/v1/corpus/events",
    headers={"X-API-Key": "your-api-key"},
    params={
        "search": "ransomware attack",
        "event_category": "cyber"
    }
)

Get Event Details

Retrieve full details including actors and metadata:
event_id = "550e8400-e29b-41d4-a716-446655440000"

response = requests.get(
    f"https://api.intrace.com/v1/corpus/events/{event_id}",
    headers={"X-API-Key": "your-api-key"}
)

event = response.json()
print(f"Event: {event['title']}")
print(f"Actors: {[a['canonical_name'] for a in event['actors']]}")
print(f"Metadata: {event['metadata']}")

Export Data

Export filtered events in various formats:
# Export as CSV
response = requests.get(
    "https://api.intrace.com/v1/corpus/events/export",
    headers={"X-API-Key": "your-api-key"},
    params={
        "format": "csv",
        "event_category": "political",
        "date_from": "2026-01-01",
        "date_to": "2026-01-31"
    }
)

with open("political_events_jan2026.csv", "wb") as f:
    f.write(response.content)

# Export as GeoJSON for mapping
response = requests.get(
    "https://api.intrace.com/v1/corpus/events/export",
    headers={"X-API-Key": "your-api-key"},
    params={
        "format": "geojson",
        "country": "Syria",
        "event_category": "conflict"
    }
)

geojson_data = response.json()

Discover Filter Values

Use metadata endpoints to find valid filter values:
# Get all available categories
categories = requests.get(
    "https://api.intrace.com/v1/corpus/metadata/event-categories",
    headers={"X-API-Key": "your-api-key"}
).json()

print("Available categories:")
for cat in categories['categories']:
    print(f"- {cat['value']}: {cat['count']} events")

# Get types within a category
types = requests.get(
    "https://api.intrace.com/v1/corpus/metadata/event-types",
    headers={"X-API-Key": "your-api-key"},
    params={"category": "cyber"}
).json()

print("\nCyber event types:")
for typ in types['types']:
    print(f"- {typ['value']}: {typ['count']} events")

Pagination Best Practices

Handle large result sets with pagination:
def get_all_events(category: str):
    """Fetch all events for a category using pagination."""
    all_events = []
    page = 1

    while True:
        response = requests.get(
            "https://api.intrace.com/v1/corpus/events",
            headers={"X-API-Key": "your-api-key"},
            params={
                "event_category": category,
                "page": page,
                "page_size": 500  # Max page size
            }
        )

        data = response.json()
        all_events.extend(data['items'])

        if page >= data['total_pages']:
            break

        page += 1

    return all_events

# Usage
all_cyber_events = get_all_events("cyber")
print(f"Retrieved {len(all_cyber_events)} cyber events")

Code Examples

Python

Complete example using the requests library:
import requests
from typing import List, Dict, Any

class IntraceCorpusClient:
    def __init__(self, api_key: str, base_url: str = "https://api.intrace.com"):
        self.api_key = api_key
        self.base_url = base_url
        self.headers = {"X-API-Key": api_key}

    def list_events(
        self,
        category: str = None,
        event_type: str = None,
        country: str = None,
        date_from: str = None,
        date_to: str = None,
        page: int = 1,
        page_size: int = 50
    ) -> Dict[str, Any]:
        """List events with optional filters."""
        params = {
            "page": page,
            "page_size": page_size
        }

        if category:
            params["event_category"] = category
        if event_type:
            params["event_type"] = event_type
        if country:
            params["country"] = country
        if date_from:
            params["date_from"] = date_from
        if date_to:
            params["date_to"] = date_to

        response = requests.get(
            f"{self.base_url}/v1/corpus/events",
            headers=self.headers,
            params=params
        )
        response.raise_for_status()
        return response.json()

    def get_event(self, event_id: str) -> Dict[str, Any]:
        """Get a single event by ID."""
        response = requests.get(
            f"{self.base_url}/v1/corpus/events/{event_id}",
            headers=self.headers
        )
        response.raise_for_status()
        return response.json()

    def export_events(
        self,
        format: str = "csv",
        **filters
    ) -> bytes:
        """Export events in specified format."""
        params = {"format": format, **filters}

        response = requests.get(
            f"{self.base_url}/v1/corpus/events/export",
            headers=self.headers,
            params=params
        )
        response.raise_for_status()
        return response.content

# Usage
client = IntraceCorpusClient(api_key="your-api-key")
events = client.list_events(category="cyber", country="United States")
print(f"Found {events['total']} events")

JavaScript/TypeScript

Example using fetch API:
class IntraceCorpusClient {
  constructor(
    private apiKey: string,
    private baseUrl: string = "https://api.intrace.com"
  ) {}

  async listEvents(params: {
    category?: string;
    eventType?: string;
    country?: string;
    dateFrom?: string;
    dateTo?: string;
    page?: number;
    pageSize?: number;
  }): Promise<any> {
    const queryParams = new URLSearchParams();

    if (params.category) queryParams.set("event_category", params.category);
    if (params.eventType) queryParams.set("event_type", params.eventType);
    if (params.country) queryParams.set("country", params.country);
    if (params.dateFrom) queryParams.set("date_from", params.dateFrom);
    if (params.dateTo) queryParams.set("date_to", params.dateTo);
    queryParams.set("page", String(params.page || 1));
    queryParams.set("page_size", String(params.pageSize || 50));

    const response = await fetch(
      `${this.baseUrl}/v1/corpus/events?${queryParams}`,
      {
        headers: {
          "X-API-Key": this.apiKey,
        },
      }
    );

    if (!response.ok) {
      throw new Error(`API error: ${response.statusText}`);
    }

    return response.json();
  }

  async getEvent(eventId: string): Promise<any> {
    const response = await fetch(
      `${this.baseUrl}/v1/corpus/events/${eventId}`,
      {
        headers: {
          "X-API-Key": this.apiKey,
        },
      }
    );

    if (!response.ok) {
      throw new Error(`API error: ${response.statusText}`);
    }

    return response.json();
  }
}

// Usage
const client = new IntraceCorpusClient("your-api-key");
const events = await client.listEvents({
  category: "political",
  country: "France",
});
console.log(`Found ${events.total} events`);

cURL

Basic cURL examples:
# List events
curl -H "X-API-Key: your-api-key" \
  "https://api.intrace.com/v1/corpus/events?event_category=conflict&page=1&page_size=10"

# Get specific event
curl -H "X-API-Key: your-api-key" \
  "https://api.intrace.com/v1/corpus/events/550e8400-e29b-41d4-a716-446655440000"

# Export to CSV
curl -H "X-API-Key: your-api-key" \
  "https://api.intrace.com/v1/corpus/events/export?format=csv&event_category=cyber" \
  -o cyber_events.csv

# Get metadata
curl -H "X-API-Key: your-api-key" \
  "https://api.intrace.com/v1/corpus/metadata/event-categories"

Export Formats

CSV Format

Comma-separated values with headers. Suitable for spreadsheet analysis.
  • Use case: Import into Excel, Google Sheets, or data analysis tools
  • File extension: .csv
  • MIME type: text/csv

JSON Format

Array of complete event objects with actors and metadata.
  • Use case: Programmatic processing, full data fidelity
  • File extension: .json
  • MIME type: application/json

GeoJSON Format

Geographic data format following RFC 7946 specification.
  • Use case: Mapping applications, GIS tools, Leaflet/Mapbox
  • File extension: .geojson
  • MIME type: application/geo+json

ACLED Format

Compatible with ACLED (Armed Conflict Location & Event Data Project) schema.
  • Use case: Integration with existing ACLED workflows and tools
  • File extension: .json
  • MIME type: application/json

Flat Format

Denormalized JSON with one object per event-actor combination.
  • Use case: Spreadsheet import where actor relationships need to be explicit
  • File extension: .json
  • MIME type: application/json

Error Handling

The API uses standard HTTP status codes:
CodeMeaningDescription
200SuccessRequest completed successfully
400Bad RequestInvalid parameters or malformed request
401UnauthorizedMissing or invalid API key
404Not FoundResource not found (e.g., event ID doesn’t exist)
422Validation ErrorRequest parameters failed validation
429Rate LimitedToo many requests (contact support for rate limit increase)
500Server ErrorInternal server error (contact support if persistent)
Example error response:
{
  "detail": "Event not found"
}
Python error handling:
try:
    response = requests.get(
        f"https://api.intrace.com/v1/corpus/events/{event_id}",
        headers={"X-API-Key": api_key}
    )
    response.raise_for_status()
    event = response.json()
except requests.exceptions.HTTPError as e:
    if e.response.status_code == 404:
        print(f"Event {event_id} not found")
    elif e.response.status_code == 401:
        print("Invalid API key")
    else:
        print(f"API error: {e}")

Rate Limits

Default rate limits:
  • 100 requests per minute per API key
  • 10,000 requests per day per API key
Contact support if you need higher limits for your use case.

Next Steps