Agent Authentication
API key authentication for agents: credential management, per-key spending caps and rate limits, revocation, and per-tenant child keys for resellers
Agent Authentication Model
AI agents operate differently from human users:
- No interactive login: Agents can't click "Sign in with Google"
- No session cookies: Agents don't maintain browser sessions
- Programmatic only: All auth must be API-based
- Long-lived credentials: Agents need persistent access
SkillBoss uses API key authentication designed for agents.
Getting Your API Key
Method 1: Human Provisioning (Current)
Your human operator creates your key:
Quick setup for AI agents: Tell your agent
set up skillboss.co/skill.mdto auto-configure everything.
Human Signs Up
Human registers at skillboss.co/console
Human Creates API Key
Human generates API key from Console → API Keys → Create New Key
Options:
- Key label: Identify which agent/tenant uses this key
- Spending cap: Lifetime and/or per-month spend limit
- Rate limit: Max requests per minute
Human Provides Key to Agent
Human adds key to agent's environment:
# Environment variable
export SKILLBOSS_API_KEY="sk-abc123..."
# Config file
echo '{"skillboss_key": "sk-abc123..."}' > config.json
# MCP server
claude mcp add skillboss --api-key sk-abc123...
Using Your API Key
Standard Authentication
Include API key in Authorization header:
import requests
headers = {
"Authorization": "Bearer sk-YOUR_API_KEY",
"Content-Type": "application/json"
}
response = requests.post(
"https://api.skillboss.co/v1/chat/completions",
headers=headers,
json={
"model": "gemini/gemini-2.5-flash",
"messages": [{"role": "user", "content": "Hello"}]
}
)
print(response.json())
OpenAI SDK Compatible
SkillBoss is drop-in compatible with OpenAI SDK:
from openai import OpenAI
client = OpenAI(
api_key="sk-YOUR_SKILLBOSS_KEY",
base_url="https://api.skillboss.co/v1" # Only difference
)
# Now use standard OpenAI methods
response = client.chat.completions.create(
model="claude-4-5-sonnet", # Access Claude via OpenAI interface
messages=[{"role": "user", "content": "Hello"}]
)
Per-Key Spending Caps & Rate Limits
Every API key isolates its own usage, and you can bound each key with hard
caps. A key auto-disables when a cap is hit. Set limits with
PUT /v1/key/wholesale/{token}/limits (use me to target the calling key):
requests.put(
"https://api.skillboss.co/v1/key/wholesale/me/limits",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"spend_cap_usd": 100.0, # lifetime cap
"monthly_cap_usd": 50.0, # per-calendar-month cap
"rpm_limit": 300, # requests per minute
"stop_at_remaining_usd": 5.0, # stop when wallet buffer reaches this
},
)
All fields are optional and nullable — send only the ones you want to change.
Revoking & Rotating Keys
There is no automatic-rotation API. To revoke or rotate a key, use the
tri-state disabled flag on the limits endpoint:
# Revoke a key immediately
requests.put(
"https://api.skillboss.co/v1/key/wholesale/me/limits",
headers={"Authorization": f"Bearer {KEY_TO_REVOKE}"},
json={"disabled": True},
)
# Re-enable it later
# json={"disabled": False}
To rotate: create a new key (in the dashboard), migrate traffic to it,
then revoke the old key with {"disabled": true}.
Multi-Tenant: One Key Per Tenant (Resellers)
If you resell to your own tenants, provision one child API key per tenant in the reseller dashboard. Each child key is isolated — its own usage, its own caps, its own rate limit — and is self-managing with its own bearer token (no separate admin credential needed).
# Each tenant's key manages itself:
# 1. Set that tenant's monthly budget
requests.put(
"https://api.skillboss.co/v1/key/wholesale/me/limits",
headers={"Authorization": f"Bearer {TENANT_KEY}"},
json={"monthly_cap_usd": 25.0},
)
# 2. Read that tenant's usage / spend
usage = requests.get(
"https://api.skillboss.co/v1/key/wholesale/me/usage",
headers={"Authorization": f"Bearer {TENANT_KEY}"},
).json()["data"]
print(usage["spent_usd"], usage["monthly_cap_usd"], usage["disabled"])
# 3. Suspend that tenant
requests.put(
"https://api.skillboss.co/v1/key/wholesale/me/limits",
headers={"Authorization": f"Bearer {TENANT_KEY}"},
json={"disabled": True},
)
Billing: all child-key usage rolls up to your reseller account, and each child key is billed and reported independently.
Secure Key Storage
Environment Variables (Recommended)
# .env file
SKILLBOSS_API_KEY=sk-abc123...
# Load in agent
import os
api_key = os.getenv("SKILLBOSS_API_KEY")
Encrypted Config Files
from cryptography.fernet import Fernet
# Encrypt key before storing
cipher = Fernet(os.getenv("ENCRYPTION_KEY"))
encrypted_key = cipher.encrypt(b"sk-abc123...")
# Save encrypted key
with open("config.enc", "wb") as f:
f.write(encrypted_key)
# Decrypt when needed
with open("config.enc", "rb") as f:
encrypted = f.read()
api_key = cipher.decrypt(encrypted).decode()
Secret Management Services
# AWS Secrets Manager
import boto3
client = boto3.client('secretsmanager')
secret = client.get_secret_value(SecretId='skillboss-api-key')
api_key = secret['SecretString']
Never:
- Commit API keys to git
- Log API keys in plain text
- Share keys between unrelated agents
- Embed keys in client-side code
Authentication Errors
Common Error Codes
| Error | Cause | Solution |
|---|---|---|
401 Unauthorized | Invalid or missing API key | Check key format (starts with sk-) |
403 Forbidden | Key is disabled or revoked | Re-enable with {"disabled": false}, or provision a new key |
429 Too Many Requests | Rate limit exceeded | Implement exponential backoff |
402 Payment Required | Insufficient credits, or a spend cap was hit | Add credits in the dashboard, or raise the key's cap |
Handling Auth Errors
def authenticated_request(url, **kwargs):
"""Make request with auth error handling."""
headers = kwargs.get('headers', {})
headers['Authorization'] = f"Bearer {API_KEY}"
kwargs['headers'] = headers
response = requests.post(url, **kwargs)
if response.status_code == 401:
# Key is invalid - alert human
send_alert("API key invalid. Please update.")
raise Exception("Authentication failed")
elif response.status_code == 403:
# Key disabled or revoked - alert human
send_alert("API key disabled or revoked. Re-enable or reissue.")
raise Exception("Key disabled")
elif response.status_code == 402:
# Insufficient credits, or a spend cap was hit
send_alert("Credits depleted or spend cap hit. Add funds or raise the cap.")
raise Exception("Insufficient credits")
return response
Testing Your Authentication
Verify your API key works:
curl https://api.skillboss.co/v1/models \
-H "Authorization: Bearer sk-YOUR_KEY"
# Expected output:
# {
# "data": [
# {"id": "gemini/gemini-2.5-flash", "cost": 0.075},
# {"id": "claude-4-5-sonnet", "cost": 15.00},
# ...
# ]
# }
Test specific permissions:
# Test if you can use models
curl https://api.skillboss.co/v1/chat/completions \
-H "Authorization: Bearer sk-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini/gemini-2.5-flash",
"messages": [{"role": "user", "content": "test"}]
}'
# Check your spend / usage
curl https://api.skillboss.co/v1/usage \
-H "Authorization: Bearer sk-YOUR_KEY"
Next Steps
Quick Start
Make your first API call
Budget Management
Set spending limits
API Reference
Full API documentation
Security Best Practices
Secure your agent