AgentGuard · agentguard.run

OpenRouter + AgentGuard Spend

One OpenRouter key gives you 400+ models across 60+ providers. AgentGuard Spend sits in your runtime and enforces per-task spend caps + capability gates + signed audit receipts on every call. Your CFO assigns which models which teams can use for which tasks. You ship.

Zero data plane: Your OpenRouter API key, prompts, completions, and signing keys never leave your process. AgentGuard is a library, not a proxy.

Why this combination

One key, one invoice

OpenRouter consolidates billing across Anthropic, OpenAI, Google, Bedrock, Cohere, Mistral, Meta, DeepSeek, and 50+ others. AgentGuard enforces the policy that decides which to use.

Auto failover, audited

OpenRouter falls back when a provider goes down. AgentGuard records each fallback as a signed decision so you can prove resilience to procurement.

Per-task model routing

Code reviews go to haiku at $0.10/1M. Payment approvals require gpt-5.5 with a payment-execute capability claim. Read-only research allows any model under $0.20/1M.

CFO-grade audit trail

Every decision is Ed25519-signed and hash-chained. Auditors verify the entire chain at /verify in their browser.

Install (30 seconds)

1

Install the SDK

# Node / TypeScript
npm install @agentguard-run/spend openai

# Python
pip install agentguard-spend openai
2

Set your OpenRouter key

export OPENROUTER_API_KEY=sk-or-v1-...

Stored in your env. AgentGuard never reads it.

3

Wire it up

TypeScript / Node

import OpenAI from 'openai';
import {
  withSpendGuard,
  setCostOverride,
  type SpendPolicy,
} from '@agentguard-run/spend';
import { randomBytes } from 'node:crypto';
import * as ed from '@noble/ed25519';

// Register OpenRouter model pricing (v0.3.0 will sync this automatically
// via `agentguard models --sync-pricing`). Values are cents per 1k tokens.
setCostOverride('anthropic/claude-opus-4-7',   { inputCentsPerKtok: 2.0,  outputCentsPerKtok: 10.0 });
setCostOverride('anthropic/claude-sonnet-4-6', { inputCentsPerKtok: 0.3,  outputCentsPerKtok: 1.5  });
setCostOverride('anthropic/claude-haiku-4-5',  { inputCentsPerKtok: 0.1,  outputCentsPerKtok: 0.5  });
setCostOverride('openai/gpt-5',                { inputCentsPerKtok: 0.5,  outputCentsPerKtok: 1.5  });
setCostOverride('openai/gpt-5-mini',           { inputCentsPerKtok: 0.05, outputCentsPerKtok: 0.2  });

const policy: SpendPolicy = {
  id: 'code-review-team-v1',
  name: 'Code review team',
  scope: { tenantId: 'acme', teamId: 'engineering' },
  caps: [
    // Soft daily cap: at $50/day, downgrade to haiku
    { amountCents: 5000,  window: 'per_day',    action: 'downgrade',
      downgradeTo: 'anthropic/claude-haiku-4-5',
      reason: 'over $50/day, drop to haiku' },
    // Hard daily ceiling: at $200/day, block
    { amountCents: 20000, window: 'per_day',    action: 'block',
      reason: 'hard daily ceiling' },
    // Per-minute burst guard: catches runaway loops
    { amountCents: 500,   window: 'per_minute', action: 'block',
      reason: 'runaway loop detection' },
  ],
  mode: 'enforce',
  version: 1,
  effectiveFrom: new Date().toISOString(),
};

// Your signing keys. Generated once, kept in your KMS or local secret store.
const privateKey = new Uint8Array(randomBytes(32));
const publicKey  = await ed.getPublicKeyAsync(privateKey);

// Standard OpenAI client pointed at OpenRouter
const client = new OpenAI({
  apiKey: process.env.OPENROUTER_API_KEY,
  baseURL: 'https://openrouter.ai/api/v1',
});

// Wrap it. That is all.
const guarded = withSpendGuard(client, {
  policy,
  scope: { tenantId: 'acme', teamId: 'engineering', userId: 'alice' },
  config: { signingKeys: { privateKey, publicKey } },
});

// Use any OpenRouter model. AgentGuard enforces locally before the call fires.
const completion = await guarded.chat.completions.create({
  model: 'anthropic/claude-opus-4-7',
  messages: [{ role: 'user', content: 'Review this PR for security issues...' }],
});

Python

import os
from openai import OpenAI
from agentguard_spend import with_spend_guard, set_cost_override
from agentguard_spend.types import SpendPolicy, SpendCap

set_cost_override('anthropic/claude-opus-4-7',   {'inputCentsPerKtok': 2.0,  'outputCentsPerKtok': 10.0})
set_cost_override('anthropic/claude-haiku-4-5',  {'inputCentsPerKtok': 0.1,  'outputCentsPerKtok': 0.5})
set_cost_override('openai/gpt-5',                {'inputCentsPerKtok': 0.5,  'outputCentsPerKtok': 1.5})

policy = SpendPolicy(
    id='code-review-team-v1',
    name='Code review team',
    scope={'tenantId': 'acme', 'teamId': 'engineering'},
    caps=[
        SpendCap(amountCents=5000,  window='per_day',    action='downgrade',
                 downgradeTo='anthropic/claude-haiku-4-5',
                 reason='over $50/day, drop to haiku'),
        SpendCap(amountCents=20000, window='per_day',    action='block',
                 reason='hard daily ceiling'),
        SpendCap(amountCents=500,   window='per_minute', action='block',
                 reason='runaway loop detection'),
    ],
    mode='enforce',
    version=1,
    effectiveFrom='2026-05-28T00:00:00Z',
)

client = OpenAI(
    api_key=os.environ['OPENROUTER_API_KEY'],
    base_url='https://openrouter.ai/api/v1',
)

guarded = with_spend_guard(client, policy=policy,
                            scope={'tenantId': 'acme', 'teamId': 'engineering', 'userId': 'alice'})

completion = guarded.chat.completions.create(
    model='anthropic/claude-opus-4-7',
    messages=[{'role': 'user', 'content': 'Review this PR for security issues...'}],
)
4

Watch decisions live

agentguard serve   # opens http://localhost:8787

Local dashboard reads from ~/.agentguard/<scope>/decisions.ndjson. Each decision is a signed receipt. Click any receipt to verify it.

5

Prove it to your auditor

agentguard verify --trace latest

Or share a receipt link to /verify and they can validate it in their browser without installing anything.

Common OpenRouter model assignments by task

TaskRecommended modelFallback (downgrade)Why
Code reviewanthropic/claude-haiku-4-5none (cheapest already)Strong reasoning at $0.10/1M
Risk analysisopenai/gpt-5openai/gpt-5-miniBest price-perf ratio
Payment approvalanthropic/claude-opus-4-7none — block on capHighest reasoning, no downgrade
Chargeback evidenceanthropic/claude-sonnet-4-6anthropic/claude-haiku-4-5Long context for transcripts
Agent supportopenai/gpt-5-mininoneFast and cheap
Repo scangoogle/gemini-3.1-proopenai/gpt-5-miniLong context window

What about the OpenRouter app field

When you call OpenRouter, pass an app header so they can attribute usage and show your app in the rankings:

const client = new OpenAI({
  apiKey: process.env.OPENROUTER_API_KEY,
  baseURL: 'https://openrouter.ai/api/v1',
  defaultHeaders: {
    'HTTP-Referer': 'https://your-app.example.com',
    'X-Title': 'Your App Name',
  },
});

Coming in v0.3.0