# How Paperclip Tracks Costs by Aggregating Token Usage: A Deep Dive into the ACP Pipeline

> Discover how Paperclip tracks costs by aggregating token usage at the AI agent runtime. Learn about its ACP pipeline for cost tracking, dashboards, and billing.

- Repository: [Paperclip/paperclip](https://github.com/paperclipai/paperclip)
- Tags: deep-dive
- Published: 2026-08-18

---

**Paperclip tracks costs by capturing token usage at the AI-agent runtime level, persisting each event to a `cost_events` table, and aggregating those records with SQL to power dashboards, billing reports, and daily token caps.**

Paperclip is an open-source AI compute platform (ACP) that provides infrastructure for running AI agents at scale. Understanding how it **tracks costs by aggregating token usage** reveals a well-engineered pipeline that transforms raw LLM consumption into actionable financial metrics. This article breaks down the complete data flow from runtime emission to UI display, citing the exact source files and functions that make it work.

---

## Runtime Emission: Where Token Tracking Begins

Every AI-agent execution in Paperclip starts with precise measurement. The **Tool Runtime Metrics service** ([`server/src/services/tool-runtime-metrics.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/tool-runtime-metrics.ts)) emits an `ACP UsageUpdate` message for each agent run. This message contains:

- `inputTokens` – tokens sent to the LLM
- `outputTokens` – tokens received from the LLM
- `used` – total bytes consumed
- `costUsd` – derived monetary cost

These fields form the raw data layer for all downstream cost calculations. The runtime captures usage at the moment of inference, ensuring no token goes uncounted.

---

## Persisting Usage Events to the Database

Once emitted, usage data lands in the **Run-Log Store** ([`server/src/services/run-log-store.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/run-log-store.ts)). This service writes a row to the `cost_events` table on every heartbeat of a running job.

Key columns in `cost_events` include:

| Column | Type | Purpose |
|--------|------|---------|
| `inputTokens` | integer | Tokens sent to the model |
| `outputTokens` | integer | Tokens received from the model |
| `costCents` | integer | Cost stored as integer cents for precision |
| `companyId` | string | Organization grouping for aggregations |
| `recordedAt` | timestamp | When the usage occurred |

Storing cost in **cents as integers** avoids floating-point rounding errors—a critical detail for financial accuracy at scale.

---

## SQL Aggregation: Computing Cost Summaries

The **Status-Cards service** ([`server/src/services/status-cards.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/status-cards.ts)) performs the heavy lifting of **aggregating token usage** into meaningful metrics. It uses SQL `SUM()` operations to compute totals across multiple dimensions.

### Per-Day Aggregation

```ts
// server/src/services/status-cards.ts
export async function getDailyCost(companyId: string) {
  const rows = await db
    .select({
      tokens: sql<number>`coalesce(sum(${costEvents.inputTokens} + ${costEvents.outputTokens}), 0)::int`,
      costCents: sql<number>`coalesce(sum(${costEvents.costCents}), 0)::int`,
    })
    .from(costEvents)
    .where(eq(costEvents.companyId, companyId))
    .groupBy(sql`date_trunc('day', ${costEvents.recordedAt})`);
  return rows;
}

```

This query:
- Sums `inputTokens + outputTokens` for total token consumption
- Sums `costCents` for total spend
- Groups results by calendar day using PostgreSQL's `date_trunc`

The same pattern extends to per-run and per-company aggregations that feed the Cost Summary APIs.

---

## REST API Layer: Typed Cost Endpoints

Aggregated data surfaces through the **Costs API** ([`server/src/api/costs.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/api/costs.ts)), consumed by the UI via [`ui/src/api/costs.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/api/costs.ts). The API returns strongly-typed objects:

- `CostSummary` – high-level spend overview
- `CostByAgent` – usage broken down by individual agents
- `FinanceSummary` – billing-ready totals

### Fetching Cost Data Client-Side

```ts
import { costsApi } from '@/api/costs';

// Get the cost-summary for a company over the last 30 days
const summary = await costsApi.summary('company-123', {
  from: '2024-07-01',
  to: '2024-07-31',
});
console.log(summary); // → { tokens: 123456, costCents: 487, … }

```

The API accepts date ranges, enabling flexible reporting periods for dashboards and invoices.

---

## UI Display: Formatting and Daily Cap Enforcement

The final layer transforms raw numbers into human-readable metrics. The **Status Cards formatting module** ([`ui/src/pages/StatusCards/format.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/pages/StatusCards/format.ts)) provides two essential helpers:

- `formatTokens()` – converts token counts to compact notation (e.g., 96,000 → "96.0k")
- `formatCents()` – converts cents to dollar strings (e.g., 48 → "$0.48")

### Displaying Token/Cost Pairs

```ts
import { formatTokens, formatCents } from '@/pages/StatusCards/format';

const tokens = 96_000;               // from the API
const cents  = 48;                  // $0.48
const label = `${formatCents(cents)} · ${formatTokens(tokens)}`;
// label => "$0.48 · 96.0k tok"

```

This concise format appears throughout Paperclip's dashboards, giving users immediate cost visibility.

### Daily Token Cap Enforcement

Paperclip also enforces **spending limits** at the UI layer. It checks aggregated daily totals against configured caps and pauses auto-updates when thresholds are reached. The test file [`ui/src/pages/StatusCards/format.test.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/pages/StatusCards/format.test.ts) validates this cap logic alongside formatting functions.

---

## Key Source Files in the Cost Pipeline

| Component | File Path | Role in Cost Tracking |
|-----------|-----------|----------------------|
| Runtime metrics emission | [`server/src/services/tool-runtime-metrics.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/tool-runtime-metrics.ts) | Emits `ACP UsageUpdate` with token counts and USD cost |
| Event persistence | [`server/src/services/run-log-store.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/run-log-store.ts) | Writes to `cost_events` table |
| SQL aggregation | [`server/src/services/status-cards.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/status-cards.ts) | Computes daily/company totals with `SUM()` |
| REST API | [`server/src/api/costs.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/api/costs.ts) | Exposes typed cost endpoints |
| UI API client | [`ui/src/api/costs.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/api/costs.ts) | Calls server cost-summary endpoints |
| Formatting utilities | [`ui/src/pages/StatusCards/format.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/pages/StatusCards/format.ts) | Renders tokens and cents for display |
| Cap enforcement tests | [`ui/src/pages/StatusCards/format.test.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/pages/StatusCards/format.test.ts) | Validates daily token limit logic |

---

## Summary

Paperclip's cost tracking system demonstrates a **clear separation of concerns** across five pipeline stages:

- **Capture** – Runtime metrics service records every token at inference time
- **Persist** – Run-Log Store writes normalized cost events to PostgreSQL
- **Aggregate** – Status-Cards service uses SQL `SUM()` for efficient grouping
- **Serve** – Costs API exposes typed endpoints for flexible querying
- **Display** – UI formatting helpers render readable metrics with cap enforcement

This architecture scales from individual agent runs to enterprise billing reports while maintaining **cent-level financial precision** throughout.

---

## Frequently Asked Questions

### How does Paperclip avoid rounding errors in cost calculations?

Paperclip stores all monetary values as **integer cents** in the `costCents` column rather than floating-point dollars. This approach eliminates rounding errors during aggregation and ensures billing accuracy. The conversion to display format (`$0.48`) only happens at the UI layer.

### Can I query cost data for custom date ranges?

Yes. The Costs API accepts `from` and `to` parameters in ISO date format. The `costsApi.summary()` method in [`ui/src/api/costs.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/api/costs.ts) passes these directly to the server endpoint, enabling arbitrary reporting periods for dashboards or invoices.

### What happens when a company hits its daily token cap?

The UI enforces caps by checking aggregated daily totals against configured limits. When thresholds are reached, auto-updates pause to prevent additional spend. This logic is tested in [`ui/src/pages/StatusCards/format.test.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/pages/StatusCards/format.test.ts) alongside the formatting utilities.

### Where does the initial USD cost value come from?

The `costUsd` field originates in the **Tool Runtime Metrics service** ([`server/src/services/tool-runtime-metrics.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/tool-runtime-metrics.ts)), which calculates cost based on model-specific pricing at runtime. This derived value is then converted to integer cents before database storage.