Python SDK
The official Python client for CTWiseAPI.
Installation​
pip install ctwise
Requirements:
- Python 3.8+
requestslibrary (installed automatically)
Quick Start​
from ctwise import CTWiseClient
# Initialize with your API key
client = CTWiseClient(api_key="ctwise_sk_live_xxx")
# Search for regulatory requirements
results = client.requirements.search(
therapeutic_area="Oncology",
authorities=["FDA", "EMA"],
phase="III"
)
# Print results
for req in results.requirements:
print(f"[{req.authority}] {req.title}")
print(f" Type: {req.requirement_type}")
print(f" Reference: {req.regulatory_reference.document}")
print()
Configuration​
Basic Configuration​
from ctwise import CTWiseClient
client = CTWiseClient(
api_key="ctwise_sk_live_xxx",
base_url="https://api.ctwise.ai", # Default
timeout=30, # Request timeout in seconds
max_retries=3, # Number of retries on failure
)
Environment Variables​
export CTWISE_API_KEY="ctwise_sk_live_xxx"
from ctwise import CTWiseClient
# API key is read from CTWISE_API_KEY environment variable
client = CTWiseClient()
API Reference​
Requirements Search​
Search for regulatory requirements across multiple authorities.
results = client.requirements.search(
# Search criteria
therapeutic_area="Oncology",
requirement_types=["endpoint_definition", "safety_monitoring"],
authorities=["FDA", "ICH", "EMA"],
phase="III",
keywords=["primary endpoint", "overall survival"],
# Options
include_guidance=True,
include_examples=False,
max_results=100,
)
# Access results
print(f"Found {results.total_count} requirements")
for req in results.requirements:
print(req.requirement_id)
print(req.title)
print(req.description)
print(req.implementation_guidance) # Starter tier only
Amendment Patterns​
Get historical amendment patterns for a therapeutic area.
patterns = client.patterns.get(
therapeutic_area="Oncology",
time_period="5_years"
)
for pattern in patterns.patterns:
print(f"Pattern: {pattern.pattern_type}")
print(f"Frequency: {pattern.frequency}%")
print(f"Risk Level: {pattern.risk_level}")
Prevention Strategies​
Get prevention strategies to avoid common protocol issues.
strategies = client.prevention.get_strategies(
therapeutic_area="Oncology",
phase="III"
)
for strategy in strategies.strategies:
print(f"Strategy: {strategy.title}")
print(f"Effectiveness: {strategy.effectiveness}%")
for action in strategy.actions:
print(f" - {action}")
Protocol Validation​
Validate a protocol against regulatory requirements.
validation = client.rules.validate(
protocol={
"title": "Phase III Oncology Study",
"therapeutic_area": "Oncology",
"phase": "III",
"primary_endpoint": "Overall survival",
"sample_size": 500,
}
)
print(f"Compliance Score: {validation.compliance_score}%")
print(f"Status: {validation.status}")
for issue in validation.issues:
print(f"[{issue.severity}] {issue.description}")
print(f" Recommendation: {issue.recommendation}")
Error Handling​
from ctwise import CTWiseClient
from ctwise.exceptions import (
CTWiseError,
AuthenticationError,
RateLimitError,
ValidationError,
NotFoundError,
InsufficientTierError,
)
client = CTWiseClient(api_key="ctwise_sk_live_xxx")
try:
results = client.requirements.search(therapeutic_area="Oncology")
except AuthenticationError:
print("Invalid API key")
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after} seconds")
except InsufficientTierError:
print("This feature requires a higher tier")
except ValidationError as e:
print(f"Invalid request: {e.message}")
except CTWiseError as e:
print(f"API error: {e.message}")
Pagination​
For large result sets, use pagination:
# Get first page
results = client.requirements.search(
therapeutic_area="Oncology",
max_results=50,
)
# Iterate through all pages
all_requirements = []
for page in client.requirements.search_iter(therapeutic_area="Oncology"):
all_requirements.extend(page.requirements)
print(f"Total requirements: {len(all_requirements)}")
Async Support​
For async/await applications:
import asyncio
from ctwise import AsyncCTWiseClient
async def main():
async with AsyncCTWiseClient(api_key="ctwise_sk_live_xxx") as client:
results = await client.requirements.search(
therapeutic_area="Oncology"
)
for req in results.requirements:
print(req.title)
asyncio.run(main())
Type Hints​
The SDK includes full type hints for IDE support:
from ctwise import CTWiseClient
from ctwise.types import RequirementsSearchResponse, Requirement
client = CTWiseClient(api_key="xxx")
results: RequirementsSearchResponse = client.requirements.search(
therapeutic_area="Oncology"
)
req: Requirement = results.requirements[0]
print(req.title) # IDE autocomplete works!
Logging​
Enable debug logging:
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("ctwise")
logger.setLevel(logging.DEBUG)
# Now API calls will log request/response details
client = CTWiseClient(api_key="xxx")
Best Practices​
1. Reuse Client Instances​
# Good - reuse client
client = CTWiseClient(api_key="xxx")
results1 = client.requirements.search(therapeutic_area="Oncology")
results2 = client.requirements.search(therapeutic_area="Psychiatry")
# Bad - create new client each time
results1 = CTWiseClient(api_key="xxx").requirements.search(...)
results2 = CTWiseClient(api_key="xxx").requirements.search(...)
2. Handle Rate Limits​
from ctwise.exceptions import RateLimitError
import time
def search_with_backoff(client, **kwargs):
for attempt in range(3):
try:
return client.requirements.search(**kwargs)
except RateLimitError as e:
time.sleep(e.retry_after)
raise Exception("Max retries exceeded")
3. Use Environment Variables for Keys​
import os
from ctwise import CTWiseClient
# Never hardcode API keys
client = CTWiseClient(api_key=os.getenv("CTWISE_API_KEY"))
Examples​
Integration with Pandas​
import pandas as pd
from ctwise import CTWiseClient
client = CTWiseClient()
results = client.requirements.search(
therapeutic_area="Oncology",
max_results=100
)
# Convert to DataFrame
df = pd.DataFrame([
{
"id": r.requirement_id,
"title": r.title,
"authority": r.authority,
"type": r.requirement_type,
"effective_date": r.effective_date,
}
for r in results.requirements
])
print(df.head())
Flask Integration​
from flask import Flask, jsonify
from ctwise import CTWiseClient
app = Flask(__name__)
client = CTWiseClient()
@app.route("/search")
def search():
results = client.requirements.search(
therapeutic_area="Oncology"
)
return jsonify({
"count": results.total_count,
"requirements": [r.dict() for r in results.requirements]
})
REST API Reference​
If you prefer to call the REST API directly without the SDK, here are the available endpoints:
Public Endpoints (No Authentication Required)​
| Endpoint | Description |
|---|---|
GET /v1/catalog/sources | List all available regulatory sources |
Protected Endpoints (API Key Required)​
| Endpoint | Description |
|---|---|
GET /v1/rules | Search rules by keyword, source, category |
GET /v1/rules/{id} | Get specific rule details |
POST /v1/semantic-search | AI-powered natural language search |
GET /v1/rules/search | Alternative GET-based semantic search |
Semantic Search Endpoints​
The SDK's search() method uses these endpoints under the hood:
# SDK method
results = client.rules.search(query="informed consent requirements")
# Equivalent REST API call (POST method - recommended)
import requests
response = requests.post(
"https://api.ctwise.ai/v1/semantic-search",
headers={"x-api-key": "YOUR_API_KEY"},
json={"query": "informed consent requirements", "limit": 10}
)
# Equivalent REST API call (GET method - alternative)
response = requests.get(
"https://api.ctwise.ai/v1/rules/search",
headers={"x-api-key": "YOUR_API_KEY"},
params={"q": "informed consent requirements", "limit": 10}
)
Troubleshooting​
Common Errors​
| Error Code | HTTP Status | Cause | Solution |
|---|---|---|---|
INVALID_API_KEY | 401 | Invalid or expired API key | Verify your API key is correct and active |
MISSING_API_KEY | 401 | No API key provided | Include x-api-key header in requests |
RATE_LIMIT_EXCEEDED | 429 | Too many requests | Wait and retry with exponential backoff |
INSUFFICIENT_TIER | 403 | Feature requires higher tier | Upgrade your subscription |
INVALID_REQUEST | 400 | Malformed request body | Check request parameters |
NOT_FOUND | 404 | Resource doesn't exist | Verify the rule ID or endpoint path |
Debugging Tips​
-
Enable verbose logging to see request/response details:
import logging
logging.basicConfig(level=logging.DEBUG) -
Test connectivity with the catalog endpoint (no auth required):
response = requests.get("https://api.ctwise.ai/v1/catalog/sources")
print(response.status_code) # Should be 200 -
Verify API key format: Keys should start with
ctw_prefix -
Check tier access: Some sources (ICH, EMA, WHO) require Starter tier or higher
Support​
- PyPI: pypi.org/project/ctwise
- GitHub: github.com/ctwise/python-sdk
- Issues: github.com/ctwise/python-sdk/issues