A virtual key is what your code authenticates with when calling the Wardin gateway. It looks like wardin_sk_abc123... and is never a real Anthropic or OpenAI key.
When a request arrives, Wardin:
- Validates the virtual key
- Loads the key’s budget, rate limits, and policies
- Swaps in the real provider credential before forwarding the request
Your actual provider API keys never leave Wardin’s control plane — your code never touches them.
Why virtual keys?
| Problem | Virtual key solution |
|---|
| Sharing one API key across the team | Issue one virtual key per developer or CI job |
| No visibility into who spent what | Every request is attributed to the key (and its owner) |
| Can’t disable a single developer | Revoke or pause one key without touching others |
| Budget leaks discovered in billing | Hard limit enforced before the request is forwarded |
Key properties
Each virtual key has:
- Monthly budget — hard spend ceiling in USD (enforced via Redis before forwarding)
- RPM limit — requests per minute cap
- TPM limit — tokens per minute cap
- Model allowlist — optional list of permitted models; all others return
403
- Policies — which guardrail policies apply to this key
- Owner — the user the key is attributed to in analytics
Creating a key
Dashboard
Console → Keys & Limits → Create key. Set a name, budget, and any rate limits. The key is shown once at creation — store it.
REST API
curl -X POST https://api.wardin.ai/v1/keys \
-H "Authorization: Bearer wardin_sk_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "alice-dev",
"monthlyBudgetUsd": 50,
"rpmLimit": 60,
"tpmLimit": 100000
}'
Response:
{
"id": "key_01j...",
"name": "alice-dev",
"key": "wardin_sk_abc123...",
"monthlyBudgetUsd": 50,
"currentSpendUsd": 0,
"createdAt": "2025-01-15T10:00:00Z"
}
The key field is only returned at creation time. It cannot be retrieved again — store it securely.
Key lifecycle
active → paused → active (manual toggle)
active → budget_exceeded (automatic, resets monthly)
active → revoked (permanent)
A key in budget_exceeded state returns:
{
"error": {
"type": "budget_exceeded",
"message": "Monthly budget of $50.00 has been reached.",
"code": 429
}
}
Security recommendations
- Issue separate keys for each developer and each CI environment
- Set conservative budgets; raise them via budget increase requests
- Register
wardin_sk_ with your secret scanner (GitHub Advanced Security, truffleHog, etc.)
- Rotate keys periodically — revoke the old one, issue a new one
- Never commit virtual keys to version control