Verified plugins

ai.oz0/ai-spend

What the company spends at Anthropic and OpenAI directly, read from their admin APIs on your own nodes and shown by team beside Orchestrator Zero's own spend.

For: tenant administrators and plugin users.

ai.oz0/ai-spend imports company AI spending that did not pass through Orchestrator Zero. It reads Anthropic and OpenAI admin cost and usage reports on your nodes with the organisation's admin keys.

The plugin records outside spend by day, provider, model and team alongside gateway spending. Its only outbound requests are to those two admin APIs.

FunctionWhat it does
oz0_ai_spend.import_spenddays (1 to 31, 7 by default) or start and end, and dry_run: reads both providers' cost reports, and their usage reports for tokens, for whole UTC days, maps each workspace or project to a team, and hands the rows to Orchestrator Zero. Never today, which is not over.

The oz0-ai-spend-import flow calls it, and the plugin ships a routine that runs the flow once a day for the last seven days, so a provider's late correction of a recent day is picked up and a day missed while a node was away is imported the next day. Importing the same days again adds nothing.

Install

Terminal
oz0 plugin install hub:ai.oz0/ai-spend --accept-provides outside-spend
printf '%s' "$ANTHROPIC_ADMIN_KEY" | oz0 secret set AI_SPEND_ANTHROPIC_ADMIN_KEY
printf '%s' "$OPENAI_ADMIN_KEY" | oz0 secret set AI_SPEND_OPENAI_ADMIN_KEY
oz0 setting set AI_SPEND_TEAMS 'anthropic:Research = research; openai:Growth = growth; openai:* = platform'
oz0 routine save -f plugins/ai-spend/routines/oz0-ai-spend-daily.yaml
oz0 routine run ai-spend-daily --wait
oz0 usage outside
  • --accept-provides outside-spend is a tenant admin's grant: the plugin may record spend that belongs to no job. An install without it is refused and says so. The grant is audited (plugin.provides.granted), shown by oz0 plugin list, taken back with oz0 plugin revoke-provides ai-spend outside-spend, and dropped when the plugin is removed. See the manifest's provides.
  • The admin keys are an Anthropic Admin API key (sk-ant-admin..., made by an organization admin in the Claude Console) and an OpenAI admin key (made in the organization settings). Set one or both; a provider without a key is skipped. They are tenant secrets bound by credential injection: the plugin's process holds placeholders, and the node's egress proxy puts the key on GET requests to api.anthropic.com/v1/organizations and api.openai.com/v1/organization alone.
  • AI_SPEND_TEAMS maps workspaces and projects to teams: one rule per line or separated by ;, <provider>:<workspace or project name or ID> = <team>, * for any. Anthropic's default workspace is default. The first rule that matches wins; spend no rule maps is the tenant's, shown as unassigned.
  • The routine in routines/oz0-ai-spend-daily.yaml fires at 04:20 UTC with up to 15 minutes of jitter. Set its owner_team to the team that owns spend reporting before you save it.

AI_SPEND_ANTHROPIC_URL and AI_SPEND_OPENAI_URL point the plugin at a proxy of your own (https only); the keys still go only to the providers' hosts, so a proxy must forward the request with the injected header to them.

What it reads, and what it never reads

  • The reports are asked per workspace (Anthropic) or project (OpenAI) and model, never per user, account, service account or API key, so no figure about a person ever reaches the plugin. Workspace and project names stay in the plugin; the rows carry the provider's ID, which no view shows.
  • Cost comes from the cost reports only. The usage reports lend input and output tokens to the same day, workspace and model; no amount is estimated from tokens and a price list.
  • Currencies are kept as the provider gives them, and never converted.
  • A team figure goes through works-council mode: a team of fewer people than the threshold is summed into one row that names no team.

When it fails

What it saysWhy, and what to do
the anthropic admin key was refused (401)The key expired, was revoked or is not an admin key: set a new one with oz0 secret set AI_SPEND_ANTHROPIC_ADMIN_KEY. The other provider's rows are still imported.
tenant ... has not granted plugin ai-spend outside-spendThe grant was revoked or never given: install again with --accept-provides outside-spend.
... is not on the egress allowlistAI_SPEND_*_URL names a host that is neither the provider's nor on the tenant's list: allow it with oz0 tenant egress.
more than 500 rows; import fewer days at a timeOne call carries at most 500 rows: import a shorter range (days, or start and end).

A fire that imports nothing fails, so a routine that keeps failing pauses itself and says why (routines).

Tests

make test-plugins reads the providers' admin APIs from scripts/fakellm (paging, amounts, currencies, partial days, the mapping, an expired key, and that nothing is asked per person), and scripts/e2e-examples.sh installs the plugin with its keys injected, runs its routine twice against the fakes and checks the rows by team.

The import asks by default

The plugin's suggested policy asks a person before each import_spend ("the plugin asks before it writes the tenant's outside spend"). The daily routine runs unattended, so a tenant that saves it switches the function once, with a reason: oz0 plugin policy ai-spend --set oz0_ai_spend.import_spend=allow --reason "the daily import runs unattended".

Copyright © 2026