Team Key Isolation

Separate API keys, spend, and logs by team or project.

Overview

Teams let you carve Stockyard into isolated namespaces. Each team gets its own API keys, and every request made with a team key is automatically tagged in logs, traces, and spend tracking. No configuration needed beyond creating the team and generating keys.

This is the recommended way to give separate projects, environments, or teams their own slice of your Stockyard instance without running multiple instances.

Create a Team

curl -X POST https://your-host/api/teams \
  -H "X-Admin-Key: $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Frontend", "description": "Frontend web app"}'

Response:

{
  "id": 1,
  "name": "Frontend",
  "slug": "frontend",
  "description": "Frontend web app",
  "created_by": 0,
  "created_at": "2026-03-28T12:00:00Z",
  "updated_at": "2026-03-28T12:00:00Z"
}

Generate a Team Key

curl -X POST https://your-host/api/teams/1/keys \
  -H "X-Admin-Key: $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "production"}'

The response includes the full API key. Copy it immediately — it is only shown once.

{
  "id": 5,
  "user_id": 1,
  "team_id": 1,
  "key_prefix": "sk-sy-aBcDeF...",
  "name": "production",
  "scopes": "*",
  "key": "sk-sy-aBcDeFgHiJkLmNoPqRsTuVwXyZ..."
}

Use the Key

Team keys work exactly like regular Stockyard keys. Just set the Authorization header:

curl https://your-host/v1/chat/completions \
  -H "Authorization: Bearer sk-sy-YOUR_TEAM_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Hello"}]
  }'

Stockyard automatically detects the team key, tags the request with the team ID, and routes it through all configured middleware. Nothing else changes.

View Team Spend

curl https://your-host/api/teams/1/spend \
  -H "X-Admin-Key: $ADMIN_KEY"
{
  "team_id": "1",
  "total": {
    "requests": 1482,
    "cost_usd": 12.4830,
    "tokens_in": 892400,
    "tokens_out": 341200
  },
  "this_month": {
    "requests": 340,
    "cost_usd": 3.2100
  },
  "today": {
    "requests": 42,
    "cost_usd": 0.3800
  }
}

View Team Logs

curl "https://your-host/api/teams/1/logs?limit=20" \
  -H "X-Admin-Key: $ADMIN_KEY"

Returns only requests made with keys belonging to team 1. Supports limit and offset query parameters for pagination.

Manage Keys

ActionEndpointMethod
List keys/api/teams/{id}/keysGET
Create key/api/teams/{id}/keysPOST
Revoke key/api/teams/{id}/keys/{keyId}DELETE
Rotate key/api/teams/{id}/keys/{keyId}/rotatePOST

Rotating a key atomically revokes the old key and generates a new one with the same name. The old key stops working immediately.

Manage Teams

ActionEndpointMethod
List teams/api/teamsGET
Create team/api/teamsPOST
Get team + keys/api/teams/{id}GET
Update team/api/teams/{id}PUT
Delete team/api/teams/{id}DELETE

Deleting a team automatically revokes all its keys.

Dashboard

The Teams tab in the dashboard (at /ui) provides a full UI for creating teams, generating keys, viewing spend, and managing everything without touching the API directly.

How It Works

When a request arrives with a team-scoped API key:

1. The auth middleware validates the key and looks up the associated team.

2. The team and user are injected into the request context.

3. The proxy handler copies the team ID onto the request metadata.

4. All downstream systems — request logging, trace recording, spend tracking — include the team ID automatically.

Existing user keys (without a team) continue to work exactly as before. Team isolation is purely additive.

Note: Team keys still require a user_id for ownership tracking. When creating a team key via the admin API, the key is owned by user ID 1 by default. You can specify a different user_id in the request body.
Explore: Proxy-only mode · Self-hosted proxy · OpenAI-compatible