Installation
Copy
pip install raily
Quick Start
Copy
from raily import Raily
import os
raily = Raily(api_key=os.environ["RAILY_API_KEY"])
# Create content
content = raily.content.create(
external_id="article-123",
title="My Article",
type="article",
source="https://example.com/article"
)
print(f"Created: {content.id}")
Configuration
Copy
from raily import Raily
raily = Raily(
# Required
api_key=os.environ["RAILY_API_KEY"],
# Optional
base_url="https://api.raily.ai",
timeout=30.0, # 30 seconds
max_retries=3,
)
Environment Variables
Copy
export RAILY_API_KEY=raily_sk_xxxxx
export RAILY_BASE_URL=https://api.raily.ai # Optional
Content API
Create Content
Copy
content = raily.content.create(
external_id="article-123",
title="Introduction to AI",
type="article",
source="https://example.com/articles/ai",
policy_id="pol_premium",
metadata={
"author": "Jane Smith",
"category": "Technology"
},
tags=["ai", "technology"]
)
List Content
Copy
content = raily.content.list(limit=20, type="article")
for item in content.data:
print(f"{item.title} ({item.id})")
# Pagination
if content.has_more:
next_page = raily.content.list(cursor=content.next_cursor)
Get Content
Copy
content = raily.content.get("cnt_abc123", expand=["policy"])
print(content.title)
print(content.policy.name)
Update Content
Copy
updated = raily.content.update(
"cnt_abc123",
title="Updated Title",
metadata={"featured": True}
)
Upsert Content
Copy
# Creates if doesn't exist, updates if it does
content = raily.content.upsert(
external_id="article-123",
title="My Article",
type="article",
source="https://example.com/article"
)
Delete Content
Copy
raily.content.delete("cnt_abc123")
Bulk Operations
Copy
result = raily.content.bulk_create(
items=[
{"external_id": "a1", "title": "Article 1", "type": "article", "source": "..."},
{"external_id": "a2", "title": "Article 2", "type": "article", "source": "..."}
],
options={"skip_duplicates": True}
)
print(f"Created: {result.created}, Skipped: {result.skipped}")
Policies API
Create Policy
Copy
policy = raily.policies.create(
name="Premium Access",
rules=[
{
"action": "allow",
"priority": 1,
"conditions": {"has_valid_license": True},
"permissions": ["full_access"]
},
{
"action": "deny",
"priority": 99,
"conditions": {"default": True}
}
]
)
List Policies
Copy
policies = raily.policies.list()
Update Policy
Copy
updated = raily.policies.update(
"pol_abc123",
rules=[...] # new rules
)
Test Policy
Copy
result = raily.policies.test(
policy_id="pol_abc123",
request={
"requester_id": "test_partner",
"license_type": "enterprise"
}
)
print(f"Would be: {'ALLOWED' if result.allowed else 'DENIED'}")
Access API
Check Access
Copy
access = raily.access.check(
content_id="cnt_abc123",
requester_id="my_app",
context={
"purpose": "rag",
"model": "gpt-4"
}
)
if access.allowed:
print("Access granted!")
print(f"Permissions: {', '.join(access.permissions)}")
print(f"Content URL: {access.content_url}")
# Fetch content
import requests
response = requests.get(
access.content_url,
headers={"Authorization": f"Bearer {access.token}"}
)
content = response.text
else:
print(f"Access denied: {access.reason}")
Analytics API
Usage Analytics
Copy
usage = raily.analytics.usage(
period="30d",
group_by="day",
content_id="cnt_abc123" # Optional filter
)
print(f"Total requests: {usage.summary.total_requests}")
print(f"Allowed: {usage.summary.allowed}")
print(f"Denied: {usage.summary.denied}")
Revenue Analytics
Copy
revenue = raily.analytics.revenue(
period="30d",
currency="USD"
)
print(f"Total revenue: ${revenue.summary.total}")
Webhooks API
Create Webhook
Copy
webhook = raily.webhooks.create(
url="https://api.example.com/webhooks/raily",
events=["access.granted", "access.denied"]
)
print(f"Webhook secret: {webhook.secret}")
Verify Webhook (Flask)
Copy
from flask import Flask, request, abort
from raily.webhooks import verify_signature
import hmac
app = Flask(__name__)
@app.route("/webhooks/raily", methods=["POST"])
def handle_webhook():
signature = request.headers.get("X-Raily-Signature")
timestamp = request.headers.get("X-Raily-Timestamp")
try:
event = verify_signature(
payload=request.data,
signature=signature,
timestamp=timestamp,
secret=os.environ["RAILY_WEBHOOK_SECRET"]
)
except ValueError:
abort(401)
# Handle event
if event["type"] == "access.granted":
handle_access_granted(event["data"])
return "OK", 200
Error Handling
Copy
from raily import Raily
from raily.exceptions import (
RailyError,
AuthenticationError,
NotFoundError,
RateLimitError,
ValidationError
)
try:
content = raily.content.get("invalid")
except NotFoundError:
print("Content not found")
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after}s")
except ValidationError as e:
print(f"Validation error: {e.message}")
print(f"Field: {e.param}")
except AuthenticationError:
print("Invalid API key")
except RailyError as e:
print(f"API error: {e.code} - {e.message}")
Async Support
The SDK supports async/await:Copy
import asyncio
from raily import AsyncRaily
async def main():
raily = AsyncRaily(api_key=os.environ["RAILY_API_KEY"])
# All methods are async
content = await raily.content.create(
external_id="article-123",
title="My Article",
type="article",
source="https://example.com"
)
access = await raily.access.check(
content_id=content.id,
requester_id="my_app",
context={"purpose": "rag"}
)
print(f"Access: {'granted' if access.allowed else 'denied'}")
asyncio.run(main())
Type Hints
The SDK includes full type hints:Copy
from raily import Raily
from raily.types import Content, Policy, AccessCheckResponse
raily = Raily(api_key=os.environ["RAILY_API_KEY"])
# Type hints for better IDE support
content: Content = raily.content.create(
external_id="article-123",
title="My Article",
type="article",
source="https://example.com"
)
access: AccessCheckResponse = raily.access.check(
content_id=content.id,
requester_id="my_app",
context={"purpose": "rag"}
)
Integration Examples
With LangChain
Copy
from langchain.schema import BaseRetriever, Document
from raily import Raily
import requests
class RailyRetriever(BaseRetriever):
def __init__(self, content_ids: list[str], requester_id: str):
self.content_ids = content_ids
self.requester_id = requester_id
self.raily = Raily(api_key=os.environ["RAILY_API_KEY"])
def get_relevant_documents(self, query: str) -> list[Document]:
documents = []
for content_id in self.content_ids:
access = self.raily.access.check(
content_id=content_id,
requester_id=self.requester_id,
context={"purpose": "rag"}
)
if access.allowed:
response = requests.get(access.content_url)
documents.append(Document(page_content=response.text))
return documents
With FastAPI
Copy
from fastapi import FastAPI, Depends
from raily import Raily
app = FastAPI()
def get_raily():
return Raily(api_key=os.environ["RAILY_API_KEY"])
@app.get("/content/{content_id}")
async def get_content(content_id: str, raily: Raily = Depends(get_raily)):
access = raily.access.check(
content_id=content_id,
requester_id="api_user",
context={"purpose": "api_access"}
)
if not access.allowed:
raise HTTPException(status_code=403, detail=access.reason)
return {"content_url": access.content_url}