AI-Powered Content Moderation API with Usage-Based Billing
A serverless, production-ready content moderation API built with FastAPI, React, AWS services, and Stripe. ShieldAPI provides enterprise-grade content safety detection using AWS Rekognition and Bedrock Claude, with transparent usage-based billing.
βββββββββββββββββββ
β React Frontend β (Vite + Tailwind + Clerk Auth)
β (Developer Hub) β
ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββ
β API Gateway β (Rate limiting, API key validation)
β (The Shield) β
ββββββββββ¬βββββββββ
β
ββββββ΄βββββ
β β
βΌ βΌ
ββββββββββ ββββββββββββββββββ
β Lambda β β Step Functions β (Rekognition β Bedrock)
β β β (The Brain) β
βββββ¬βββββ ββββββββββββββββββ
β
βΌ
βββββββββββββββ ββββββββββββ
β DynamoDB ββββββΆβ Stripe β
β (Single-Table) β β (Billing)β
βββββββββββββββ ββββββββββββ
- Frontend (The Hub): React application for developer portal
- API Gateway (The Shield): Request throttling and API key validation
- Execution Layer (The Brain): Step Functions orchestrating AI models
- Billing Engine (The Pulse): Stripe Meters for real-time usage tracking
- Data Layer: DynamoDB with single-table design
- Node.js 18+ and npm
- Python 3.11+
- AWS CLI configured with credentials
- AWS CDK installed globally:
npm install -g aws-cdk - Stripe account (for billing)
- Clerk account (for authentication)
# Clone the repository
git clone <your-repo>
cd shield_ai
# Copy environment files
cp backend/.env.example backend/.env
cp frontend/.env.example frontend/.env
# Edit config.yaml with your settings
nano config.yamlStore your sensitive credentials in AWS Secrets Manager:
# Stripe API key
aws secretsmanager create-secret \
--name shieldapi/stripe/api_key \
--secret-string "sk_test_YOUR_STRIPE_KEY"
# Clerk secret key
aws secretsmanager create-secret \
--name shieldapi/clerk/secret_key \
--secret-string "sk_test_YOUR_CLERK_KEY"cd infra
# Install dependencies
pip install -r requirements.txt
# Bootstrap CDK (first time only)
cdk bootstrap
# Deploy all stacks
cdk deploy --allNote the outputs: API Gateway URL, DynamoDB table name, Usage Plan ID
# Create a billing meter for usage tracking
stripe meters create \
--display-name "Moderation API Usage" \
--event-name moderation_usage \
--value-settings '{"event_payload_key": "value"}' \
--default-aggregation '{"formula": "sum"}'
# Update config.yaml with the meter IDcd backend
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Run FastAPI server
uvicorn app.main:app --reloadAPI will be available at http://localhost:8000
cd frontend
# Install dependencies
npm install
# Start dev server
npm run devFrontend will be available at http://localhost:3000
All settings are centralized in config.yaml:
project:
name: "ShieldAPI"
stage: "prod"
region: "us-east-1"
billing:
provider: "stripe"
meter_id: "mtr_12345" # Update after creating Stripe meter
auth:
provider: "clerk"
jwt_issuer: "https://clerk.your-app.com"
limits:
free_tier_monthly: 100
burst_limit: 5
rate_limit: 2Sign up at the frontend (/dashboard) or call the onboard endpoint:
curl -X POST https://your-api-url/onboard \
-H "Content-Type: application/json" \
-d '{
"clerk_user_id": "user_xyz",
"email": "dev@example.com",
"jwt": "eyJ..."
}'Response:
{
"success": true,
"api_key": "abcd1234...",
"stripe_customer_id": "cus_xyz"
}curl -X POST https://your-api-url/moderate \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"image_url": "https://example.com/image.jpg",
"idempotency_key": "unique-request-id"
}'Response:
{
"success": true,
"execution_arn": "arn:aws:states:...",
"status": "PROCESSING"
}Single-Table Design:
| PK | SK | Attributes |
|---|---|---|
USER#<id> |
PROFILE |
email, stripe_customer_id, created_at |
USER#<id> |
API_KEY#<val> |
aws_key_id, status |
USAGE#<id> |
DATE#<iso> |
total_calls, endpoint |
USER#<id> |
IDEMPOTENCY#<key> |
response, timestamp |
Global Secondary Indexes:
ApiKeyIndex: Query byapi_keyStripeCustomerIndex: Query bystripe_customer_id
- β Secrets in AWS Secrets Manager (never hardcoded)
- β JWT validation with Clerk
- β Idempotency keys for duplicate prevention
- β Stripe webhook signature verification
- β API key rotation support
- β DynamoDB encryption at rest
- β Rate limiting at API Gateway level
cd backend
python -m pytest tests/test_onboarding.py# Start a moderation request
curl -X POST http://localhost:8000/moderate \
-H "x-api-key: test-key" \
-H "Content-Type: application/json" \
-d '{"image_url": "https://example.com/test.jpg"}'# API Gateway logs
aws logs tail /aws/apigateway/ShieldAPI --follow
# Lambda logs
aws logs tail /aws/lambda/OnboardFunction --follow
# Step Functions execution history
aws stepfunctions list-executions \
--state-machine-arn <your-state-machine-arn>aws dynamodb scan --table-name shieldapi-usersstripe events list --limit 10cd frontend
# Build production bundle
npm run build
# Deploy to S3
aws s3 sync dist/ s3://shieldapi-frontend-prod --delete
# Invalidate CloudFront cache
aws cloudfront create-invalidation \
--distribution-id <your-distribution-id> \
--paths "/*"cd infra
# Preview changes
cdk diff
# Deploy updates
cdk deploy --allModeration State Machine:
ββββββββββββββββββββ
β Rekognition β (Detect moderation labels)
β Detection β
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββ
β Choice β (High confidence violation?)
βββββ¬βββββ
β
ββββββ΄ββββββ
β β
βΌ βΌ
ββββββββ βββββββββββ
β Flag β β Bedrock β (Contextual analysis)
β β β Claude β
ββββββββ ββββββ¬βββββ
β
βΌ
ββββββββββββ
β Format β
β Response β
ββββββββββββ
Free Tier: 100 requests/month (tracked via Stripe Meters)
Usage-Based:
- Requests 1-100: Free
- Requests 101-1,000: $0.01 each
- Requests 1,000+: $0.005 each
Billing is handled automatically through Stripe with real-time metering.
shield_ai/
βββ config.yaml # Central configuration
βββ .github/
β βββ copilot-instructions.md # Project guidelines
βββ infra/ # AWS CDK infrastructure
β βββ app.py
β βββ stacks/
β β βββ api_stack.py
β β βββ database_stack.py
β β βββ pipeline_stack.py
β βββ utils/
β βββ config_loader.py
βββ backend/ # FastAPI application
β βββ app/
β β βββ main.py
β β βββ config.py
β β βββ services/
β β βββ auth.py
β β βββ billing.py
β β βββ database.py
β β βββ stepfunctions.py
β βββ lambdas/
β βββ onboard/
β βββ moderate/
β βββ webhook/
βββ frontend/ # React application
βββ src/
β βββ pages/
β β βββ Landing.jsx
β β βββ Dashboard.jsx
β βββ components/
β βββ ApiKeyManager.jsx
β βββ UsageChart.jsx
β βββ BillingPortal.jsx
βββ package.json
Solution: Ensure AWS credentials are configured and you've run cdk bootstrap
aws configure
cdk bootstrap aws://ACCOUNT-ID/REGIONSolution: Check API key is associated with usage plan:
aws apigateway get-usage-plan-keys --usage-plan-id <plan-id>Solution: Verify webhook endpoint is receiving events:
stripe listen --forward-to localhost:8000/webhook- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Open a Pull Request
MIT License - see LICENSE file for details
- AWS CDK Documentation
- FastAPI Documentation
- Stripe Billing Documentation
- Clerk Authentication
- AWS Rekognition
- AWS Bedrock
For issues or questions:
- Open an issue on GitHub
- Email: support@shieldapi.com
Built with β€οΈ using FastAPI, React, and AWS