Skip to main content

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

ParameterTypeDefaultDescription
monthly_limitFloatRequiredMonthly spending cap in USD
warning_threshold_percentFloat80.0Percentage to trigger warning
hard_limit_actionString"block"Action at 100%: block, notify, none
limit_enforcedBooleantrueWhether 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 TypeDescriptionLogged Data
limit_setNew limit createdlimit amount, threshold, action
limit_updatedLimit modifiedold values, new values
warning_triggered80% threshold reachedspend, utilization
kill_switch_triggered100% reached or manualreason, triggered_by
kill_switch_releasedAccess restoredreason, 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:

OperationTargetActual
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

EndpointMethodDescription
/billing/spend-limitsPOSTSet spend limit
/billing/spend-limits/{org_id}GETGet limit config
/billing/spend-limits/{org_id}PUTUpdate limit
/billing/spend-status/{org_id}GETGet current status
/billing/kill-switch/{org_id}/triggerPOSTTrigger kill switch
/billing/kill-switch/{org_id}/releasePOSTRelease kill switch
/billing/audit-log/{org_id}GETGet audit history

Best Practices

Setting Limits

  1. Start Conservative: Set limits below expected usage initially
  2. Monitor Patterns: Understand normal spend before tightening
  3. Buffer for Growth: Leave room for legitimate usage increases
  4. Review Monthly: Adjust limits based on actual patterns

Warning Thresholds

  1. 80% Default: Standard warning gives time to react
  2. 70% for Critical: Lower threshold for mission-critical orgs
  3. Multiple Alerts: Consider 70%, 80%, 90% notifications
  4. Clear Escalation: Define who gets notified at each threshold

Kill-Switch Management

  1. Document Release: Always require reason for release
  2. Time-Bound Override: Consider temporary overrides vs permanent
  3. Review Process: Establish review cadence for blocked orgs
  4. Emergency Contacts: Maintain list of authorized releasers