How to Attribute AI Gateway Spend by Service with Stateful Actors A developer published Attribution Wheel, an open-source TypeScript sample that attributes AI gateway spend to individual services, environments, and tenants by attaching metadata to each metered request via an x-ltg-metadata header. Running on Telnyx Edge Compute, it uses one Stateful Actor per gateway token group to maintain a per-service daily spend ledger with idempotent upserts and a resumable sweep cursor, and flags anomalies using a seven-day baseline with thresholds of a 40-percentage-point share increase or 2.0x mean daily spend. The sample includes a demo mode for testing baseline, spike, and recovery flows without generating inference traffic. An AI gateway invoice can tell you the total. It does not automatically tell you which application, environment, or tenant caused a sudden increase. That becomes a real operational problem when several services share the same gateway. A support assistant, billing workflow, and documentation tool may all be healthy from an availability perspective while one of them quietly produces far more requests or spend than usual. Attribution Wheel https://github.com/team-telnyx/telnyx-code-examples/tree/main/attribution-wheel is an open-source TypeScript sample that treats spend attribution as a durable workflow: The sample runs on Telnyx Edge Compute and uses one Stateful Actor per AI Gateway token group. A built-in demo mode lets you test the baseline, spike, and recovery flow without generating inference traffic or sending a real alert. Attribution gets harder when it is reconstructed later from application logs. Logs may use different identifiers, arrive late, or omit the information needed to connect a request with a service or tenant. Attribution Wheel puts the dimensions on the request itself through the x-ltg-metadata header: metadata = { "service": "support", "env": "prod", "tenant": "example-health" } headers = { "Authorization": f"Bearer {service token key}", "Content-Type": "application/json", "x-ltg-metadata": json.dumps metadata , } The sample then requests spend grouped by metadata:service . It can also build report views grouped by metadata:tenant and metadata:env . This makes the attribution dimensions part of the metered request rather than a separate reconciliation pipeline. The sample combines four pieces: bootstrap creates one token group and separate keys for the support , billing , and docs services. AttributionWheel actor owns the schedule, sweep cursor, token-group reference, and masked key references. spend daily and spend dims . The actor is selected by name: js const id = env.WHEELS.idFromName group ; const wheel = env.WHEELS.get id ; Using the token-group name as the actor identity gives each group an independent state machine and ledger workflow. The central SQL table uses date, service as its primary key: CREATE TABLE spend daily date TEXT NOT NULL, service TEXT NOT NULL, requests INTEGER NOT NULL DEFAULT 0, input tokens INTEGER NOT NULL DEFAULT 0, output tokens INTEGER NOT NULL DEFAULT 0, spend REAL NOT NULL DEFAULT 0, reserved spend REAL NOT NULL DEFAULT 0, unknown requests INTEGER NOT NULL DEFAULT 0, baseline ratio REAL NOT NULL DEFAULT 0, breach INTEGER NOT NULL DEFAULT 0, source TEXT NOT NULL DEFAULT 'gateway', note TEXT, PRIMARY KEY date, service ; Writes use ON CONFLICT date, service DO UPDATE . Reprocessing a service for the same day therefore updates its row instead of inserting another copy. The actor also checkpoints the last processed service in a cursor. If a sweep is interrupted, a later call for the same day can resume after that cursor. This protects the ledger from duplicate rows, but production alert delivery still deserves its own idempotency key or outbox if duplicate suppression must survive every possible failure between sending an SMS and recording that it was sent. That distinction matters: database idempotency and notification delivery guarantees are related, but they are not the same thing. Global spend thresholds are often too blunt. A large service may cross them during normal traffic while a smaller service can multiply its spend without reaching the same absolute number. Attribution Wheel calculates a seven-day history for each service and uses two checks: The defaults are a 40-percentage-point share increase or 2.0x mean daily spend. For example, if support normally represents 20% of requests and reaches 62%, the increase is 42 percentage points. That crosses the default share threshold. The sample records the result as an anomaly, continued breach, recovery, or normal row. It sends an alert only when the code sees a new breach, rather than sending another message for every sweep while the same condition remains active. bootstrap schedules the first run. After each scheduled sweep, nightly schedules the next run for 23:00 UTC: async nightly : Promise