Skip to main content
Every dollar the gateway spends has to post somewhere finance can reconcile it — a team, a key, and a person. This page covers the three pieces that make that possible: roles (who can do what), teams (the cost centers spend rolls up into), and the attribution rule LEDGER and Overview use to assign a key’s spend to a team.

Roles

Every user in a tenant has exactly one role:
RoleCan do
DeveloperView their own usage, sessions, and budget on MY LANE; request budget increases
ManagerEverything a developer can, plus: approve/deny budget requests, create/edit policies and virtual keys, create teams, invite members, assign a member’s team
AdminEverything a manager can, plus: change a member’s role, remove a member, and manage billing
Role changes and member removal are deliberately gated a step higher than team assignment — an admin has to be in the loop for anything that looks like privilege escalation (a manager granting themselves admin, for example), while day-to-day team reassignment stays a manager-level action.

The team model

A team is a named cost center with an optional monthly budgetPoolUsd — a reporting target LEDGER tracks utilization against (shown as POOL $X · N% CONSUMED), not a gateway-enforced limit. Enforcement happens at the per-key and per-user budget level; the pool is a planning figure. Teams themselves are created and managed through the team API — there’s no dedicated teams panel in the Console today; a manager assigns each existing member to a team from the Members panel. Deleting a team unassigns its members and keys rather than deleting them. A user has one home team (users.team_id, nullable — “Unassigned” is a valid state). A manager sets it per-member from the Members panel: Console → Team & roles → Members — the Team column on each row.

Key → team cost-attribution rule

Spend doesn’t post to a person — it posts to a virtual key, and every key has its own, independent team assignment (virtual_keys.team_id). Owner and cost center are deliberately separate concepts:
  • Owner (user_id) — who the key is attributed to in analytics; who can see it as “their” key on MY LANE.
  • Team (team_id) — which team’s budget pool and LEDGER row the key’s spend rolls up into.
They default together but can diverge. At key creation, if no team is explicitly chosen, the key’s team defaults to its owner’s current home team. From then on the two are independent: a key can be owned by one person but billed to another team (cross-charge), or carry a team with no human owner at all — the shape a CI or service key needs, since those have no “owner” to inherit a team from. The resolution rule every rollup uses is:
effective_team = COALESCE(key.team_id, owner.team_id)
The key-level team wins when set; the owner’s home team is the fallback for older keys created before a team was chosen explicitly. If the resolved team no longer exists (deleted after the key was created), the key’s spend is bucketed as unassigned rather than silently dropped or mis-attributed — the total always reconciles.

Where this shows up

  • LEDGER — the cost-allocation table groups every key’s spend by its resolved team, with an “Unassigned” row for keys with no resolvable team. Click a team row to drill into its per-key breakdown.
  • Overview — the team allocation card is the same rollup, condensed to a bar list for the org-wide summary.
  • Console → Team & roles — where roles, invites, and per-member team assignment are managed.
  • Outcomes scoring — cost/session, one of the scoring diagnostics, is read off the same session-grouped spend that feeds LEDGER.

Managing teams via the API

# Create a team with a monthly budget pool
curl -X POST https://api.wardin.ai/v1/team/teams \
  -H "Authorization: Bearer wardin_sk_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "platform-eng", "budgetPoolUsd": 2000}'

# Assign a member to that team
curl -X PATCH https://api.wardin.ai/v1/team/members/USER_ID/team \
  -H "Authorization: Bearer wardin_sk_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"teamId": "TEAM_ID"}'
Full endpoint reference: POST /v1/team/teams · GET /v1/team/teams · GET /v1/team/members · PATCH /v1/team/members/:userId/team · PATCH /v1/team/members/:userId/role. A key’s own team is set at creation or updated afterward via the key-management endpoints — see Virtual Keys.