Official Python SDK for Sema - Universal ingestion infrastructure for AI Agents
Project description
Sema Python SDK
Official Python SDK for Sema - Universal ingestion infrastructure for AI Agents.
Installation
pip install sema-sdk
Quick Start
API Client
from sema_sdk import SemaClient
with SemaClient(api_key="sk_live_...") as client:
# Create an inbox
inbox = client.create_inbox(
name="My Inbox",
webhook_url="https://example.com/webhooks/sema",
)
print(f"Created inbox: {inbox.id}")
# Upload content
item = client.upload_item(
inbox_id=inbox.id,
file=b"Hello, World!",
sender_address="sender@example.com",
subject="Test Upload",
)
print(f"Created item: {item.id}")
# Check deliveries
deliveries = client.get_item_deliveries(item.id)
for d in deliveries.deliveries:
print(f"Delivery {d.id}: {d.status}")
Async API Client
import asyncio
from sema_sdk import AsyncSemaClient
async def main() -> None:
async with AsyncSemaClient(api_key="sk_live_...") as client:
# Create an inbox
inbox = await client.create_inbox(
name="My Inbox",
webhook_url="https://example.com/webhooks/sema",
)
print(f"Created inbox: {inbox.id}")
# Upload content
item = await client.upload_item(
inbox_id=inbox.id,
file=b"Hello, World!",
sender_address="sender@example.com",
subject="Test Upload",
)
print(f"Created item: {item.id}")
# Check deliveries
deliveries = await client.get_item_deliveries(item.id)
for d in deliveries.deliveries:
print(f"Delivery {d.id}: {d.status}")
asyncio.run(main())
Webhook Verification
from sema_sdk import WebhookVerifier, WebhookVerificationError
verifier = WebhookVerifier(secret="whsec_...")
def handle_webhook(request):
try:
event = verifier.verify(
payload=request.body,
headers=request.headers,
)
# Use event.webhook_id as idempotency key
print(f"Received: {event.webhook_id}")
print(f"Item ID: {event.payload.item_id}")
print(f"Event type: {event.payload.event_type}")
return Response(status=200)
except WebhookVerificationError as e:
return Response(status=400, body=str(e))
API Reference
SemaClient
Synchronous client for the Sema API.
client = SemaClient(
api_key="sk_live_...",
base_url="https://api.withsema.com", # optional
timeout=30.0, # optional, in seconds
max_retries=3, # optional, set to 0 to disable retries
)
The client automatically retries requests on transient failures (5xx errors, network errors, rate limits) with exponential backoff. Rate-limited requests (429) respect the Retry-After header when present.
AsyncSemaClient
Async client for the Sema API.
from sema_sdk import AsyncSemaClient
async with AsyncSemaClient(
api_key="sk_live_...",
base_url="https://api.withsema.com", # optional
timeout=30.0, # optional, in seconds
max_retries=3, # optional, set to 0 to disable retries
) as client:
inboxes = await client.list_inboxes(limit=10)
Inbox Methods
create_inbox(name, *, description=None, webhook_url=None, ...)- Create a new inboxget_inbox(inbox_id)- Get an inbox by IDupdate_inbox(inbox_id, *, name=None, webhook_url=None, ...)- Update an inboxlist_inboxes(*, limit=None, offset=None)- List inboxes with optional pagination; returnsInboxList(inboxes,total)
Item Methods
upload_item(inbox_id, file, *, sender_address, ...)- Upload content to an inboxget_item(item_id)- Get an item by IDlist_items(inbox_id, *, limit=None, offset=None)- List items in an inbox
Delivery Methods
get_item_deliveries(item_id)- Get deliveries for an item
Attachment Methods
get_item_attachments(item_id)- Get attachments for an item with presigned download URLs
Pagination Iterators
For large result sets, use async iterators to automatically paginate:
# Iterate through all items in an inbox
async for item in client.iter_items(inbox_id):
print(item.id, item.status)
# Iterate through all inboxes
async for inbox in client.iter_inboxes():
print(inbox.id, inbox.name)
# Custom page size
async for item in client.iter_items(inbox_id, page_size=50):
print(".", end="")
Observability Hooks
Add optional hooks for logging, tracing, or metrics:
def before_request(ctx):
print(f"→ {ctx['method']} {ctx['url']} (attempt {ctx['attempt']})")
def after_response(ctx):
print(f"← {ctx['status']} in {ctx['duration_ms']:.1f}ms")
def on_error(ctx, error):
print(f"✗ {ctx['method']} {ctx['url']}: {error}")
client = SemaClient(
api_key="sk_live_...",
on_before_request=before_request,
on_after_response=after_response,
on_error=on_error,
)
Hook context includes:
method- HTTP method (GET, POST, etc.)url- Request URLattempt- Attempt number (1-based, increases on retries)status- HTTP status code (after_response only)duration_ms- Request duration in milliseconds (after_response only)
Hooks can be sync or async. Errors raised in hooks are silently ignored to prevent breaking SDK functionality.
WebhookVerifier
Verifies Standard Webhooks signatures.
verifier = WebhookVerifier(
secret="whsec_...",
tolerance_seconds=300, # optional, default 5 minutes
)
event = verifier.verify(payload, headers)
# Returns WebhookEvent with:
# - webhook_id: str (use as idempotency key)
# - timestamp: int
# - payload: WebhookPayload
Email Utilities
resolve_email_inline_images
HTML emails embed inline images using cid: references. This utility replaces them with download URLs:
from sema_sdk import SemaClient, WebhookVerifier, resolve_email_inline_images
client = SemaClient(api_key="sk_live_...")
verifier = WebhookVerifier(secret="whsec_...")
def handle_webhook(request):
event = verifier.verify(request.body, request.headers)
# Get the HTML body with cid: references
content_summary = event.payload.deliverable.content_summary
body_html = (content_summary.body_html or "") if content_summary else ""
# Fetch attachments with presigned download URLs
attachments = client.get_item_attachments(event.payload.item_id).attachments
# Replace cid: references with actual URLs
resolved_html = resolve_email_inline_images(body_html, attachments)
# resolved_html now has working image URLs
return resolved_html
partition_email_attachments
Email clients like Gmail set content_id on ALL attachments, not just inline ones. This utility correctly identifies which attachments are truly inline (embedded in HTML) vs which should be listed separately:
from sema_sdk import SemaClient, partition_email_attachments, resolve_email_inline_images
client = SemaClient(api_key="sk_live_...")
def handle_webhook(request):
# ... verify webhook ...
content_summary = event.payload.deliverable.content_summary
body_html = (content_summary.body_html or "") if content_summary else ""
attachments = client.get_item_attachments(event.payload.item_id).attachments
# Resolve inline images in HTML
resolved_html = resolve_email_inline_images(body_html, attachments)
# Partition: inline images vs files to list separately
inline, non_inline = partition_email_attachments(body_html, attachments)
# inline attachments are already displayed in resolved_html
# non_inline attachments should be listed separately
for att in non_inline:
print(f"Attachment: {att.filename} ({att.content_type})")
Exceptions
SemaError- Base exception for all SDK errorsSemaAPIError- Error returned by the API (hasstatus_codeandresponse_body)AuthenticationError- Invalid or missing API key (401)NotFoundError- Resource not found (404)RateLimitError- Rate limit exceeded (429)WebhookVerificationError- Signature or timestamp validation failed
Examples
See the examples/ directory for runnable examples:
send_content.py- Create inbox and upload contentreceive_webhook.py- Flask webhook receiver with signature verification
Requirements
- Python 3.10+
- httpx
- pydantic
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sema_sdk-0.1.0.tar.gz.
File metadata
- Download URL: sema_sdk-0.1.0.tar.gz
- Upload date:
- Size: 17.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bfea2ecdcc208090b3f63d4789fd3b44875beb7ac3ffbc6cffd919bd4a4218ea
|
|
| MD5 |
f162d9137809b5bc1757e85b974a8649
|
|
| BLAKE2b-256 |
727495abf0ce9703bb2a5d9f18caf8813fcb66324465c8874541bfccde279ff2
|
File details
Details for the file sema_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sema_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 19.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
59532faa08dfb053a6a5ac42df7a1b56bd99334aa3d2afe829ce322c26aed5bb
|
|
| MD5 |
352dc5c997d6a104b8a210e35975cd92
|
|
| BLAKE2b-256 |
73e518137d68d8b261962b9b357589558cfebbc0c8f63ddd63041f56dcf0923d
|