> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.governanceaicore.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.governanceaicore.com/_mcp/server.

# API Patterns & Best Practices

> Common patterns and best practices for using the GovernanceAI API

# API Patterns & Best Practices

## Pagination

Handle large result sets with pagination:

```python
def get_all_audit_logs(org_id, start_date):
    """Fetch all audit logs with pagination"""

    page = 1
    all_logs = []

    while True:
        response = requests.get(
            'https://api.governanceai.com/v1/audit/logs',
            headers=headers,
            params={
                'org_id': org_id,
                'start_date': start_date,
                'page': page,
                'page_size': 100
            }
        )

        data = response.json()
        all_logs.extend(data['entries'])

        # Check if there are more pages
        if data['pagination']['page'] >= data['pagination']['total_pages']:
            break

        page += 1

    return all_logs
```

## Retry Logic

Implement exponential backoff for retries:

```python
import time

def make_request_with_retry(url, method='POST', data=None, max_retries=3):
    """Make request with exponential backoff retry"""

    for attempt in range(max_retries):
        try:
            if method == 'POST':
                response = requests.post(url, headers=headers, json=data, timeout=10)
            else:
                response = requests.get(url, headers=headers, timeout=10)

            if response.status_code == 429:  # Rate limit
                wait_time = 2 ** attempt  # 1, 2, 4 seconds
                print(f"Rate limited. Waiting {wait_time}s...")
                time.sleep(wait_time)
                continue

            response.raise_for_status()
            return response.json()

        except requests.exceptions.Timeout:
            if attempt < max_retries - 1:
                wait_time = 2 ** attempt
                time.sleep(wait_time)
                continue
            raise

        except requests.exceptions.RequestException as e:
            if attempt < max_retries - 1:
                wait_time = 2 ** attempt
                time.sleep(wait_time)
                continue
            raise

    raise Exception("Max retries exceeded")
```

## Rate Limit Handling

Check rate limit headers:

```python
def handle_rate_limits(response):
    """Extract rate limit information from response headers"""

    remaining = response.headers.get('X-RateLimit-Remaining', 'unknown')
    limit = response.headers.get('X-RateLimit-Limit', 'unknown')
    reset_time = response.headers.get('X-RateLimit-Reset', 'unknown')

    print(f"Rate Limit: {remaining}/{limit}")
    print(f"Reset at: {reset_time}")

    if int(remaining) < 10:
        print("Warning: Approaching rate limit")

    return {
        'remaining': remaining,
        'limit': limit,
        'reset_time': reset_time
    }
```

## Batch Operations

Process multiple items efficiently:

```python
def batch_evaluate_guardrails(messages_list, batch_size=10):
    """Evaluate multiple messages in batches"""

    results = []

    for i in range(0, len(messages_list), batch_size):
        batch = messages_list[i:i + batch_size]

        for message in batch:
            result = requests.post(
                'https://api.governanceai.com/v1/guardrails/evaluate',
                headers=headers,
                json={
                    'messages': [{'role': 'user', 'content': message}],
                    'context': {'org_id': ORG_ID, 'user_id': 'batch_user'}
                }
            ).json()

            results.append(result)

            # Small delay between requests
            time.sleep(0.1)

    return results
```

## Caching Responses

Cache API responses to reduce load:

```python
import json
from datetime import datetime, timedelta

cache = {}

def get_cached_policy(policy_id, cache_ttl_minutes=60):
    """Get policy with caching"""

    cache_key = f"policy_{policy_id}"

    # Check cache
    if cache_key in cache:
        cached_data, cached_time = cache[cache_key]
        if datetime.now() - cached_time < timedelta(minutes=cache_ttl_minutes):
            return cached_data

    # Fetch from API
    response = requests.get(
        f'https://api.governanceai.com/v1/policies/{policy_id}',
        headers=headers
    ).json()

    # Store in cache
    cache[cache_key] = (response, datetime.now())

    return response
```

## Webhook Handling

Process webhook events from GovernanceAI:

```python
from flask import Flask, request
import hmac
import hashlib

app = Flask(__name__)
WEBHOOK_SECRET = os.getenv('GOVERNANCEAI_WEBHOOK_SECRET')

def verify_webhook_signature(payload, signature):
    """Verify webhook signature"""

    expected = hmac.new(
        WEBHOOK_SECRET.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(signature, expected)

@app.route('/webhooks/governanceai', methods=['POST'])
def handle_webhook():
    """Handle GovernanceAI webhook"""

    signature = request.headers.get('X-Signature')
    payload = request.get_data()

    # Verify signature
    if not verify_webhook_signature(payload, signature):
        return {'error': 'Invalid signature'}, 401

    # Process event
    event = request.json
    print(f"Received event: {event['type']}")

    if event['type'] == 'vulnerability_detected':
        handle_vulnerability(event['data'])
    elif event['type'] == 'scan_completed':
        handle_scan_complete(event['data'])

    return {'status': 'ok'}, 200
```

## Monitoring & Metrics

Track API usage patterns:

```python
from collections import defaultdict
from datetime import datetime

metrics = defaultdict(list)

def track_api_call(endpoint, duration_ms, status_code):
    """Track API metrics"""

    metrics[endpoint].append({
        'timestamp': datetime.now(),
        'duration_ms': duration_ms,
        'status_code': status_code
    })

def get_metrics_summary(endpoint):
    """Get metrics summary for endpoint"""

    calls = metrics[endpoint]
    durations = [c['duration_ms'] for c in calls]

    return {
        'total_calls': len(calls),
        'avg_duration_ms': sum(durations) / len(durations),
        'p95_duration_ms': sorted(durations)[int(len(durations) * 0.95)],
        'p99_duration_ms': sorted(durations)[int(len(durations) * 0.99)]
    }
```

## Best Practices

✅ **Do:**

* Use environment variables for credentials
* Implement retry logic with exponential backoff
* Cache responses when appropriate
* Monitor rate limits
* Verify webhook signatures
* Handle all error codes
* Log API calls for debugging
* Use batch operations for multiple items

❌ **Don't:**

* Hardcode API keys
* Ignore rate limit headers
* Make synchronous calls in loops
* Store sensitive data in logs
* Skip error handling
* Make unlimited retries
* Share API responses publicly

## Next Steps

* **[cURL Examples](/code-examples/c-url)** - Shell commands
* **[Python Examples](/code-examples/python)** - Python code
* **[Node.js Examples](/code-examples/node-js)** - JavaScript code
* **[API Reference](/api)** - Complete API docs