Spend Control
Overview
The OWL AI Platform Spend Control Service provides financial governance for AI agent operations. It enforces per-organization spending limits with configurable warning thresholds and automatic kill-switch functionality when budgets are exceeded. The service is designed for hot-path performance (sub-0.5ms checks) while maintaining comprehensive audit trails for compliance.
Key Capabilities
- Monthly Spend Limits: Set per-organization budget caps
- Warning Thresholds: Configurable alerts at percentage milestones (default 80%)
- Automatic Kill-Switch: Immediate blocking when 100% limit reached
- Manual Override: Admin-controlled release with audit trail
- Redis-Cached: Sub-0.5ms hot-path performance
- Fail-Open Design: Does not block operations if Redis unavailable
- Compliance Ready: SOC 2 CC6.1 and PCI-DSS 3.5 compliant
How It Works
Spend Control Architecture
┌─────────────────────────────────────────────────────────────────────────────────┐
│ SPEND CONTROL ARCHITECTURE │
└─────────────────────────────────────────────────────────────────────────────────┘
┌──────────────────┐
│ API Request │
│ (Any endpoint) │
└────────┬─────────┘
│
v
┌──────────────────────────────────────────────────────────────────┐
│ SPEND LIMIT CHECK (Hot Path - <0.5ms) │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 1. Check Redis Kill-Switch Flag │ │
│ │ Key: billing:kill_switch:{org_id} │ │
│ │ If set → BLOCK immediately │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 2. Get Cached Spend Data │ │
│ │ Key: billing:spend:{org_id}:limits │ │
│ │ - current_spend │ │
│ │ - monthly_limit │ │
│ │ - warning_threshold │ │
│ │ - limit_enforced │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 3. Calculate Utilization │ │
│ │ utilization = (current_spend / monthly_limit) × 100 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 4. Return Result │ │
│ │ - allowed: true/false │ │
│ │ - blocked: true/false │ │
│ │ - warning_triggered: true/false │ │
│ │ - utilization_percent │ │
│ └─────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
│
│ allowed = true
v
┌──────────────────┐
│ Continue with │
│ API Request │
└──────────────────┘
Spend Limit Lifecycle
┌─────────────────────────────────────────────────────────────────────────────────┐
│ SPEND LIMIT LIFECYCLE │
└─────────────────────────────────────────────────────────────────────────────────┘
0% 80% 100%
│ │ │
┌───────────────┼───────────────────┼───────────────────┼───────────────────┐
│ │ │ │ │
│ ACTIVE │ ACTIVE │ WARNING │ EXCEEDED │
│ │ │ │ │
│ No alerts │ No alerts │ ⚠️ Alert sent │ 🚫 Kill switch │
│ All allowed │ All allowed │ All allowed │ All blocked │
│ │ │ │ │
└───────────────┴───────────────────┴───────────────────┴───────────────────┘
Status: active warning exceeded
Blocked: false false true
Notification: none 80% warning 100% exceeded
Action: none notify admins block + notify
Kill-Switch Flow
┌────────────────────┐
│ Spend Reaches │
│ 100% of Limit │
└─────────┬──────────┘
│
v
┌────────────────────┐
│ Trigger Kill │
│ Switch │
│ │
│ • Set Redis flag │
│ • Update DB │
│ • Log event │
│ • Send alerts │
└─────────┬──────────┘
│
v
┌────────────────────┐
│ ALL API REQUESTS │
│ BLOCKED │
│ │
│ HTTP 402 │
│ Payment Required │
└─────────┬──────────┘
│
│ Admin intervention required
v
┌────────────────────┐
│ RELEASE KILL │
│ SWITCH │
│ │
│ • Requires admin │
│ • Audit logged │
│ • Reason required │
│ • Warning reset │
└─────────┬──────────┘
│
v
┌────────────────────┐
│ Service Restored │
│ (Status: active) │
└────────────────────┘
Configuration
Set Spend Limit
from owlai import OWLClient
client = OWLClient(api_key="your_api_key")
# Set monthly spend limit for organization
client.billing.set_spend_limit(
organization_id=123,
monthly_limit=10000.00, # $10,000 monthly limit
warning_threshold_percent=80.0, # Alert at 80%
hard_limit_action="block" # block, notify, or none
)
Configuration Options
| Parameter | Type | Default | Description |
|---|---|---|---|
monthly_limit | Float | Required | Monthly spending cap in USD |
warning_threshold_percent | Float | 80.0 | Percentage to trigger warning |
hard_limit_action | String | "block" | Action at 100%: block, notify, none |
limit_enforced | Boolean | true | Whether limit is actively enforced |
API Configuration
# Set spend limit via API
curl -X POST https://api.owlai.io/v1/billing/spend-limits \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"organization_id": 123,
"monthly_limit": 10000.00,
"warning_threshold_percent": 80.0,
"hard_limit_action": "block"
}'
# Response:
# {
# "success": true,
# "spend_limit": {
# "organization_id": 123,
# "monthly_limit": 10000.00,
# "warning_threshold_percent": 80.0,
# "hard_limit_action": "block",
# "current_spend": 0.00,
# "utilization_percent": 0.0,
# "status": "active"
# }
# }
Environment Variables
# Enable/disable spend limits
ENABLE_SPEND_LIMITS=true
# Redis connection
REDIS_URL=redis://localhost:6379/0
Usage Examples
Check Spend Limit (Hot Path)
from services.spend_control_service import get_spend_control_service
spend_service = get_spend_control_service()
# Check if organization can proceed (sub-0.5ms)
result = await spend_service.check_spend_limit(organization_id=123)
if result.blocked:
raise HTTPException(
status_code=402,
detail=result.message
)
if result.warning_triggered:
logger.warning(f"Organization {org_id} at {result.utilization_percent}% of limit")
# Proceed with request
FastAPI Dependency
from fastapi import Depends, HTTPException
from services.spend_control_service import check_spend_limit_dependency
@router.post("/actions")
async def submit_action(
action: ActionCreate,
spend_check: SpendCheckResult = Depends(check_spend_limit_dependency)
):
if spend_check.blocked:
raise HTTPException(402, spend_check.message)
# Proceed with action
...
Get Current Status
curl -X GET https://api.owlai.io/v1/billing/spend-status/123 \
-H "Authorization: Bearer $TOKEN"
# Response:
# {
# "organization_id": 123,
# "current_spend": 7500.00,
# "monthly_limit": 10000.00,
# "utilization_percent": 75.0,
# "status": "active",
# "warning_triggered": false,
# "kill_switch_active": false,
# "days_remaining": 11,
# "projected_month_end": 9750.00
# }
Update Spend (Background Worker)
from services.spend_control_service import get_spend_control_service
spend_service = get_spend_control_service()
# Update current spend from aggregated usage
result = await spend_service.update_spend(
db=db,
organization_id=123,
new_spend=8500.00 # Updated total spend
)
if result.warning_triggered:
print(f"Warning: {result.utilization_percent}% of limit used")
if result.blocked:
print(f"Kill switch triggered: {result.message}")
Manual Kill-Switch Control
# Trigger kill switch manually (admin only)
await spend_service.trigger_kill_switch(
db=db,
organization_id=123,
reason="Suspected fraudulent activity",
user_id=admin_user_id
)
# Release kill switch (admin only, requires reason)
await spend_service.release_kill_switch(
db=db,
organization_id=123,
reason="Fraud investigation completed, activity verified legitimate",
user_id=admin_user_id
)
Kill-Switch API
# Trigger kill switch
curl -X POST https://api.owlai.io/v1/billing/kill-switch/123/trigger \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reason": "Budget exceeded - awaiting approval for increase"
}'
# Release kill switch
curl -X POST https://api.owlai.io/v1/billing/kill-switch/123/release \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reason": "Budget increase approved, new limit set"
}'
Audit Trail
All spend control events are logged for compliance:
Event Types
| Event Type | Description | Logged Data |
|---|---|---|
limit_set | New limit created | limit amount, threshold, action |
limit_updated | Limit modified | old values, new values |
warning_triggered | 80% threshold reached | spend, utilization |
kill_switch_triggered | 100% reached or manual | reason, triggered_by |
kill_switch_released | Access restored | reason, released_by |
Audit Log Example
{
"event_id": "evt_123456",
"event_type": "kill_switch_triggered",
"organization_id": 123,
"timestamp": "2026-01-20T15:30:00Z",
"triggered_by": "system",
"previous_value": {
"spend": 9800.00,
"status": "warning"
},
"new_value": {
"spend": 10050.00,
"status": "exceeded",
"reason": "spend_limit_exceeded"
},
"compliance_tags": ["SOC2-CC6.1", "PCI-DSS-3.5"]
}
Query Audit History
curl -X GET "https://api.owlai.io/v1/billing/audit-log/123?days=30" \
-H "Authorization: Bearer $ADMIN_TOKEN"
# Response:
# {
# "events": [
# {
# "event_type": "kill_switch_triggered",
# "timestamp": "2026-01-20T15:30:00Z",
# "triggered_by": "system"
# },
# {
# "event_type": "warning_triggered",
# "timestamp": "2026-01-18T10:15:00Z",
# "utilization": 80.5
# }
# ]
# }
Performance
Hot Path Optimization
The spend check is optimized for minimal latency:
| Operation | Target | Actual |
|---|---|---|
| Redis GET (kill switch) | <1ms | ~0.2ms |
| Redis HGETALL (limits) | <1ms | ~0.3ms |
| Total check time | <0.5ms | ~0.5ms |
Caching Strategy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ CACHING STRATEGY │
└─────────────────────────────────────────────────────────────────────────────────┘
Redis Key TTL Description
───────────────────────────────── ───────── ────────────────────────────────
billing:kill_switch:{org_id} No expiry Kill switch flag (manual release)
billing:spend:{org_id}:limits 10 min Spend limits and current usage
Database Purpose
───────────────────────────────── ────────────────────────────────────────────
spend_limits Source of truth for limits
spend_limit_events Audit trail for all changes
Fail-Open Design
If Redis is unavailable, the system fails open (allows requests):
try:
result = await spend_service.check_spend_limit(org_id)
except Exception as e:
# Fail-open: Don't block on Redis failures
logger.warning(f"SpendControl: Check failed, allowing: {e}")
return SpendCheckResult(allowed=True)
API Reference
SpendCheckResult
@dataclass
class SpendCheckResult:
allowed: bool # Whether request can proceed
blocked: bool # Whether org is blocked
current_spend: float # Current month spend
monthly_limit: float # Monthly limit
utilization_percent: float # Usage percentage
status: str # active, warning, exceeded
warning_triggered: bool # 80% threshold reached
kill_switch_active: bool # Kill switch is active
message: Optional[str] # User-facing message
Endpoints
| Endpoint | Method | Description |
|---|---|---|
/billing/spend-limits | POST | Set spend limit |
/billing/spend-limits/{org_id} | GET | Get limit config |
/billing/spend-limits/{org_id} | PUT | Update limit |
/billing/spend-status/{org_id} | GET | Get current status |
/billing/kill-switch/{org_id}/trigger | POST | Trigger kill switch |
/billing/kill-switch/{org_id}/release | POST | Release kill switch |
/billing/audit-log/{org_id} | GET | Get audit history |
Best Practices
Setting Limits
- Start Conservative: Set limits below expected usage initially
- Monitor Patterns: Understand normal spend before tightening
- Buffer for Growth: Leave room for legitimate usage increases
- Review Monthly: Adjust limits based on actual patterns
Warning Thresholds
- 80% Default: Standard warning gives time to react
- 70% for Critical: Lower threshold for mission-critical orgs
- Multiple Alerts: Consider 70%, 80%, 90% notifications
- Clear Escalation: Define who gets notified at each threshold
Kill-Switch Management
- Document Release: Always require reason for release
- Time-Bound Override: Consider temporary overrides vs permanent
- Review Process: Establish review cadence for blocked orgs
- Emergency Contacts: Maintain list of authorized releasers
Related
- Billing Overview - Usage tracking and invoicing
- API Keys - Rate limiting and quotas
- Organizations - Org-level settings
- Audit Logs - Compliance logging
- Alerts - Alert configuration