For agents
The fastest Argus integration is the one your agent does. Everything on this site exists in machine-readable form, and the pieces below paste straight into Claude Code, Codex, or any agent with a fetch tool.
Hand it to your agent
Paste this into any coding agent and it has enough to do the whole integration — instrument your app, verify an event lands, and stop to ask you for credentials rather than inventing them:
Integrate this project with Argus (https://argus.town), the cross-provider API spend and rate-limit meter. Fetch https://argus.town/llms-full.txt and follow it: instrument our outbound API calls (prefer @argus/sdk for TypeScript, otherwise the signed ingest POST), then verify by sending one test event and reading it back from the events endpoint. If ARGUS_SOURCE_ID / ARGUS_SOURCE_SECRET (writing) and ARGUS_API_KEY (reading) aren't in the environment, run the device login from the brief and ask me to approve the link.
Getting credentials to the agent
Your agent asks, you approve once, and it receives a source and keys scoped to the project you pick. Nothing is copied by hand. Keys and secrets are only ever created by a person's approval, never by an agent on its own.
# 1. The agent asks for access
curl -s -X POST https://api.argus.town/v1/device/code \
-H "content-type: application/json" \
-d '{"client_name":"my-agent","scopes":["ingest","api"]}'
# → { "user_code": "BCDF-GHJK", "verification_uri": "https://argus.town/device",
# "device_code": "argus_dev_…", "interval": 7 }
# 2. You open verification_uri, type the user_code the agent shows, pick the project, approve.
# 3. The agent polls until approved (once only — the secrets are returned a single time)
curl -s -X POST https://api.argus.town/v1/device/token \
-H "content-type: application/json" -d '{"device_code":"argus_dev_…"}'
# → { "status": "approved", "project": { "id": "prj_…" }, "api_key": "argus_api_…",
# "source": { "id": "…", "secret": "argus_src_…" } }The approval page shows where the request came from, the name the agent gave itself and exactly what it will receive. You type the code yourself; a link with the code filled in is never offered. Scopes: ingest (a telemetry source that sends call events), api (an API key that reads your spend and creates or updates connections, alert rules and negotiated pricing; read is accepted as an alias), mcp (an MCP key that meters tools, including creating connect links). Everything it creates appears in Settings, where you can revoke it. Prefer to do it yourself? Create the values in Settings and put ARGUS_SOURCE_ID, ARGUS_SOURCE_SECRET and ARGUS_API_KEY in the agent's environment.
Provider keys without copy and paste
For providers Argus can poll, the agent asks for a hosted link, you paste the provider key there, and the agent only learns that the connection exists. The key never passes through it.
curl -s -X POST https://api.argus.town/v1/connect_links \
-H "Authorization: Bearer $ARGUS_API_KEY" -H "content-type: application/json" \
-d '{"provider":"firecrawl"}'
# → { "id": "lnk_…", "url": "https://argus.town/connect/argus_cl_…", "expires_at": "…" }
# You paste the key at that URL. Then:
curl -s https://api.argus.town/v1/connect_links/$ID -H "Authorization: Bearer $ARGUS_API_KEY"
# → { "status": "done", "connection": "conn_…" }The same two calls exist over MCP as connect_links_create and connect_links_get at mcp.argus.town (create_connect_link and get_connect_link on the legacy api.argus.town/mcp). Links are single-use and expire after an hour; a project can hold 10 unused links at a time.
Claude Code skill
One command installs Argus as a skill — Claude then knows the endpoints, the signing recipe, and the verification loop whenever Argus comes up:
mkdir -p .claude/skills/argus && curl -s https://argus.town/skills/argus.md > .claude/skills/argus/SKILL.md
Map my spend skill
Scans a repo for every paid API it calls, connects the ones Argus can poll, and wires telemetry for the rest, ending with a table of what's tracked and what still needs you:
mkdir -p .claude/skills/argus-map-spend && curl -s https://argus.town/skills/map-spend.md > .claude/skills/argus-map-spend/SKILL.md
AGENTS.md / Codex
Appends the full brief to your repo's agent instructions:
curl -s https://argus.town/llms-full.txt >> AGENTS.md
Machine-readable surfaces
argus.town/llms.txt — short orientation, per the llmstxt convention.argus.town/llms-full.txt — the complete integration brief (also below).argus.town/skills/argus.md — the Claude Code skill, raw.argus.town/skills/map-spend.md — the map-my-spend skill, raw.api.argus.town/.well-known/mcp.json — MCP server discovery: endpoint, auth scheme, tool list.
The brief itself
# Argus — integration brief for AI agents
Argus (https://argus.town) tracks usage, spend, balances, and rate limits across
the third-party APIs an app pays for (LLMs, data providers, scrapers). You
integrate by streaming telemetry to one endpoint. That is the entire
integration — nothing to install, and nothing to build in the app beyond a
single reporting hook at its egress.
## Credential
You need a source_id and source_secret (ARGUS_SOURCE_ID, ARGUS_SOURCE_SECRET).
The secret signs each telemetry batch. Read them from env; never hardcode, never
log. A human approves once; you never copy a secret by hand:
1. POST https://api.argus.town/v1/device/code with
`{"client_name":"<your agent>","scopes":["ingest","api"]}` (no auth).
Response: device_code, user_code, verification_uri, verification_uri_complete, interval.
2. Show the human the user_code and verification_uri, and ask them to open the page,
type the code and approve (they pick the project; the page lists exactly what
you'll get).
3. Poll POST https://api.argus.town/v1/device/token with `{"device_code":"…"}` every
`interval` seconds. status is pending → approved; denied, expired and
consumed are final (start again). approved returns project.id,
source.id, source.secret and (scope api) api_key — shown once; write them
to a gitignored .env.
Scopes: ingest = telemetry source, api = API key for the REST API, mcp = MCP
key. There is no unauthenticated write. If the human already pasted credentials
into your environment, skip the flow.
## Send telemetry
POST https://api.argus.town/ingest — body `{"events":[…]}`, headers:
- x-argus-source: <source_id>
- x-argus-timestamp: <epoch ms as string>
- x-argus-signature: hex(HMAC-SHA256(source_secret, timestamp + "." + body))
Timestamps over 5 minutes old are rejected. 202 means accepted. Responses are
enveloped: `{"success":true,…}` or `{"success":false,"error":"…"}`. All fields
are snake_case.
Signing (TypeScript, WebCrypto — zero dependencies):
```ts
const body = JSON.stringify({ events });
const ts = Date.now().toString();
const key = await crypto.subtle.importKey("raw",
new TextEncoder().encode(SOURCE_SECRET),
{ name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
const sig = [...new Uint8Array(await crypto.subtle.sign("HMAC", key,
new TextEncoder().encode(`${ts}.${body}`)))]
.map(b => b.toString(16).padStart(2, "0")).join("");
await fetch("https://api.argus.town/ingest", {
method: "POST",
headers: {
"content-type": "application/json",
"x-argus-source": SOURCE_ID,
"x-argus-timestamp": ts,
"x-argus-signature": sig,
},
body,
});
```
## Event fields
All optional. Include `provider` OR `hostname` so the event can be attributed,
and `id` so retries dedupe.
- id — any unique string (ULID ideal); dedupes retries
- provider — Argus provider id ("openrouter", "anthropic", "pdl", …)
- hostname — the host you called ("api.openrouter.ai"); used when you don't pass provider
- endpoint, method, status, latency_ms — endpoint drives per-operation pricing
- model — for LLMs, the model id; Argus prices its tokens from the catalog
- units — {input_tokens, output_tokens, cached_tokens, reasoning_tokens, requests, records, credits, vcpu_seconds, gib_seconds, gb_seconds, gb}
- provider_request_id — the provider's request id; enables exact server-side cost enrichment
- cost_usd + cost_provenance ("provider_reported" | "app_reported") — only if you already know the cost
- credits_spent, credits_remaining
- rate_limit — {limit_type: "rpm"|"tpm"|"credits", limit, remaining, reset_at}; or rate_limits (array)
- occurred_at — epoch ms (clamped now±48h; with top-level "backfill": true in the body, real dates up to 29 days back, older events rejected)
- metadata — your own string key/values (≤2 KB); never required for pricing
- connection_id — pin the event to one connection when you run several accounts for a provider (a connection id from GET https://api.argus.town/v1/connections, without the conn_ prefix)
- pricing_override — {rates:[{unit, nano_usd_per_unit, sku?}]} — price this event
from your own rates (a negotiated deal), instead of the catalog
Whole event ≤8 KB serialized. Omit cost_usd and Argus prices the event itself:
for LLMs from model + token units; for everything else from the endpoint you
called + units (requests/records/pages) — you never need to know Argus's SKU
names. Prefer sending the endpoint + units and letting Argus price. Order of
precedence: cost_usd → pricing_override → your dashboard rate card → catalog.
## Best practices
- Report only your calls to paid third-party API providers (LLMs, data /
enrichment / scraping vendors). Do NOT report payment processors (Stripe),
your own infra or telemetry (Axiom, Sentry, logging), free/internal endpoints,
or end-user data flows (mailboxes via Gmail/Graph). Argus can't price those —
they only add noise.
- Tag each event with the `hostname` you called — Argus maps it to the provider
and prices it. Pass `provider` directly only if you already know the id.
- Prefer omitting cost_usd — let Argus price from the catalog. Pass
provider_request_id whenever the provider returns one.
- Fire-and-forget: batch events and flush out of band. Never block, delay, or
fail a user-facing request on Argus. On Cloudflare Workers, ctx.waitUntil the
flush; in queue/cron handlers, await it before returning.
- Never copy request bodies or auth headers into events, and never log the
source_secret.
## Plan limits
Event and tracked-spend limits are soft: /ingest never drops or 429s an event
for being over plan (Free 100K events/mo, Pro 3M, Team 20M). Don't sample or
throttle on Argus's account. Plans: https://argus.town/pricing
## Reading your meters (separate from integrating)
You do NOT need any of this to integrate — writing telemetry is the whole job,
and it needs no provider ids (Argus maps hostnames for you). Reading is separate:
Spend, runway, balances, and rate-limit headroom live in the Argus dashboard
(https://argus.town). For agents there is an MCP server at
https://mcp.argus.town (bearer an ARGUS_API_KEY from the dashboard) — useful
if you want to verify your own work: after sending a test event, register the MCP
and check events_list / connections_list to confirm it landed, instead of
opening the dashboard. That's optional MCP config, not app code — never add
routes in your app that proxy Argus's read API.