Python SDK for Vettly content moderation API
Project description
vettly
Don't let one bad post kill your startup. Content moderation API for text, images, and video.
Installation
pip install vettly
Quick Start
from vettly import ModerationClient
client = ModerationClient("sk_live_...")
result = client.check(
content="User-generated text",
policy_id="community-safe"
)
if result.action == "block":
# Content blocked
pass
Get Your API Key
- Sign up at vettly.dev
- Go to Dashboard → API Keys
- Create and copy your key
Features
- Text, images, video - One unified API for all content types
- Custom policies - Define thresholds in YAML
- Webhooks - Get notified when content is flagged
- Dashboard - Monitor decisions and export logs
- Automatic retries - Exponential backoff for rate limits and server errors
- Async support - Full async/await support with
AsyncModerationClient
Text Moderation
result = client.check(
content="User-generated text",
policy_id="community-safe"
)
print(result.action) # 'allow' | 'flag' | 'block'
print(result.categories) # List of CategoryResult
print(result.id) # Decision ID for audit trail
Image Moderation
# From URL
result = client.check_image(
image_url="https://example.com/image.jpg",
policy_id="strict"
)
# From base64
result = client.check_image(
image_url="data:image/jpeg;base64,/9j/4AAQ...",
policy_id="strict"
)
Idempotency
Prevent duplicate processing with request IDs:
result = client.check(
content="Hello",
policy_id="default",
request_id="unique-request-id-123"
)
Error Handling
The SDK provides typed exceptions for better error handling:
from vettly import (
VettlyAuthError,
VettlyRateLimitError,
VettlyQuotaError,
VettlyValidationError,
)
try:
result = client.check(content="test", policy_id="default")
except VettlyAuthError:
print("Invalid API key")
except VettlyRateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after}s")
except VettlyQuotaError as e:
print(f"Quota exceeded: {e.quota}")
Webhook Signature Verification
Verify webhook signatures to ensure authenticity:
from vettly import verify_webhook_signature, construct_webhook_event
@app.route("/webhooks/vettly", methods=["POST"])
def handle_webhook():
payload = request.get_data(as_text=True)
signature = request.headers.get("X-Vettly-Signature")
if not verify_webhook_signature(payload, signature, webhook_secret):
return "Invalid signature", 401
event = construct_webhook_event(payload)
if event["type"] == "decision.blocked":
# Handle blocked content
pass
return "OK", 200
Async Support
from vettly import AsyncModerationClient
async with AsyncModerationClient("sk_live_...") as client:
result = await client.check(
content="User content",
policy_id="community-safe"
)
Configuration
from vettly import ModerationClient
client = ModerationClient(
api_key="sk_live_...",
api_url="https://api.vettly.dev", # Optional: custom API URL
timeout=30.0, # Optional: request timeout in seconds
max_retries=3, # Optional: max retries for failures
retry_delay=1.0, # Optional: base delay for backoff in seconds
)
FastAPI Example
from fastapi import FastAPI, HTTPException
from vettly import AsyncModerationClient
app = FastAPI()
client = AsyncModerationClient("sk_live_...")
@app.post("/comments")
async def create_comment(content: str):
result = await client.check(content=content, policy_id="community-safe")
if result.action == "block":
raise HTTPException(403, "Content blocked")
return {"status": "ok"}
Response Format
CheckResponse(
id="550e8400-e29b-41d4-a716-446655440000",
safe=False,
flagged=True,
action=Action.BLOCK,
categories=[
CategoryResult(category="hate_speech", score=0.91, threshold=0.8, triggered=True),
CategoryResult(category="harassment", score=0.08, threshold=0.8, triggered=False),
],
latency_ms=147,
policy_id="community-safe",
)
Pricing
| Plan | Price | Text | Images | Videos |
|---|---|---|---|---|
| Developer | Free | 2,000/mo | 100/mo | 25/mo |
| Growth | $49/mo | 50,000/mo | 5,000/mo | 1,000/mo |
| Pro | $149/mo | 250,000/mo | 25,000/mo | 5,000/mo |
| Enterprise | Custom | Unlimited | Unlimited | Unlimited |
Links
- vettly.dev - Sign up
- docs.vettly.dev - Documentation
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
vettly-0.1.5.tar.gz
(10.2 kB
view details)
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
vettly-0.1.5-py3-none-any.whl
(11.5 kB
view details)
File details
Details for the file vettly-0.1.5.tar.gz.
File metadata
- Download URL: vettly-0.1.5.tar.gz
- Upload date:
- Size: 10.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
def09ee1703b1c01c7e49759af67df4303d0045cec62d60f43c0abfc2d10e116
|
|
| MD5 |
2f40646de938fd2645c2d2117abd4e1e
|
|
| BLAKE2b-256 |
eee3e1d413266f2f8d8a90eb26e8dc0515f124e0c566ccee0027c5d33263a826
|
File details
Details for the file vettly-0.1.5-py3-none-any.whl.
File metadata
- Download URL: vettly-0.1.5-py3-none-any.whl
- Upload date:
- Size: 11.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a8068d670a7b96a63b3cd50e845d9442304f35e0eacfbc8b9cbd8142df1712a2
|
|
| MD5 |
6d382e0ef87f8cc9a15a5424a7b6131f
|
|
| BLAKE2b-256 |
e7fae675e2d099b7f0b2003c8f83ee8567718c0498d9e12d0b12c0d2dd506646
|