Stats API
Below is a REST API documentation for Stats endpoints, which track usage metrics such as prompt/completion tokens, event names, and aggregated monthly stats.
All examples assume a base URL of https://app.openagentsbuilder.com.
Note: There is an API client plus example available on: https://github.com/CatchTheTornado/open-agents-builder-client and https://github.com/CatchTheTornado/open-agents-builder-example
1. Overview
The Stats API helps you record usage data (like prompt/completion tokens for LLM usage) and retrieve aggregated metrics for:
- This month
- Last month
- Today
Key Capabilities:
- Add or update a stats record (via a “PUT” that aggregates tokens by hour/day/month).
- Fetch aggregated usage stats for the current month, last month, and today.
2. Data Schema
2.1 StatDTO (for storing usage events)
export const statsSchema = z.object({ id: z.number().positive().int().optional(), eventName: z.string().min(1), promptTokens: z.number().positive().int(), completionTokens: z.number().positive().int(), finishReasons: z.string().nullable().optional(), createdAt: z.string().default(() => getCurrentTS()), createdMonth: z.number().positive().int().nullable().optional(), createdDay: z.number().positive().int().nullable().optional(), createdYear: z.number().positive().int().nullable().optional(), createdHour: z.number().positive().int().nullable().optional(), counter: z.number().positive().int().optional()});export type StatDTO = z.infer<typeof statsSchema>;Key fields:
eventName: A string label (e.g.,chat,apiCall, etc.).promptTokens&completionTokens: For usage metrics (LLM token counts, etc.).finishReasons: Additional info about why or how the event completed.createdAt: Timestamp, defaults to now if not provided.createdMonth,createdDay,createdYear,createdHour: The server auto-fills these to group by date/time.counter: How many times that event occurred in the hour/day partition (the server increments it automatically).
2.2 AggregatedStatsDTO (for the aggregated stats response)
export type AggregatedStatsDTO = { thisMonth: { overallTokens: number; promptTokens: number; completionTokens: number; overalUSD: number; requests: number; }; lastMonth: { overallTokens: number; promptTokens: number; completionTokens: number; overalUSD: number; requests: number; }; today: { overallTokens: number; promptTokens: number; completionTokens: number; overalUSD: number; requests: number; };};Key sections:
thisMonthlastMonthtoday
Each includes:
overallTokens=promptTokens + completionTokenspromptTokens,completionTokensrequests= the sum ofcounterfor all events.overalUSD: A rough cost estimate based on a reference model’s pricing (like GPT-4).
3. Endpoints
3.1 PUT /api/stats
3.1.1 Description
Takes a StatDTO in the body and aggregates it. This means:
- If an event with the same hour/day/month/year and the same
eventNamealready exists, it incrementscounterby 1 and adds the new tokens. - Otherwise, it creates a new row.
This is how it compresses many usage events into hourly stats.
3.1.2 cURL Example
curl -X PUT \ "https://app.openagentsbuilder.com/api/stats" \ -H "Authorization: Bearer <YOUR_API_KEY>" \ -H "database-id-hash: <YOUR_DATABASE_ID_HASH>" \ -H "Content-Type: application/json" \ -d '{ "eventName": "chat", "promptTokens": 100, "completionTokens": 150 }'3.1.3 TypeScript fetch Example
async function putStats(statData: any) { const response = await fetch("https://app.openagentsbuilder.com/api/stats", { method: "PUT", headers: { "Authorization": "Bearer <YOUR_API_KEY>", "database-id-hash": "<YOUR_DATABASE_ID_HASH>", "Content-Type": "application/json" }, body: JSON.stringify(statData) });
const result = await response.json(); if (!response.ok) { throw new Error(`Error aggregating stats: ${result.message}`); } console.log("Stats aggregated:", result.data); return result.data;}
// Usage:putStats({ eventName: "chat", promptTokens: 100, completionTokens: 150}).catch(console.error);3.1.4 Example Success Response (HTTP 200)
{ "message": "Stats aggregated!", "data": { "id": 42, "eventName": "chat", "promptTokens": 200, // if we already had 100, now 100 more added "completionTokens": 300,// if 150 more added "createdAt": "2025-03-21T10:00:00.000Z", "createdMonth": 2, "createdDay": 21, "createdYear": 2025, "createdHour": 10, "counter": 2 }, "status": 200}(The server might have aggregated it with an existing row, incrementing counter to 2.)
Using the TypeScript API Client
import { OpenAgentsBuilderClient } from "open-agents-builder-client";
const client = new OpenAgentsBuilderClient({ apiKey: "YOUR_API_KEY", databaseIdHash: "YOUR_DATABASE_ID_HASH"});
async function putStatsClientExample() { await client.stats.putStats({ eventName: "chat", promptTokens: 100, completionTokens: 150 }); console.log("Stats aggregated via client!");}
putStatsClientExample();3.2 GET /api/stats/aggregated
3.2.1 Description
Returns the aggregated usage for:
- This month
- Last month
- Today
In a single JSON (AggregatedStatsDTO).
3.2.2 cURL Example
curl -X GET \ "https://app.openagentsbuilder.com/api/stats/aggregated" \ -H "Authorization: Bearer <YOUR_API_KEY>" \ -H "database-id-hash: <YOUR_DATABASE_ID_HASH>"3.2.3 TypeScript fetch Example
async function getAggregatedStats() { const response = await fetch("https://app.openagentsbuilder.com/api/stats/aggregated", { method: "GET", headers: { "Authorization": "Bearer <YOUR_API_KEY>", "database-id-hash": "<YOUR_DATABASE_ID_HASH>" } }); const result = await response.json(); if (!response.ok) { throw new Error(`Error fetching aggregated stats: ${result.message}`); } console.log("Aggregated stats:", result.data); return result.data;}
// Usage:getAggregatedStats().catch(console.error);3.2.4 Example Success Response (HTTP 200)
{ "message": "Stats aggregated!", "data": { "thisMonth": { "overallTokens": 9999, "promptTokens": 4000, "completionTokens": 5999, "overalUSD": 4.50, "requests": 27 }, "lastMonth": { "overallTokens": 3000, "promptTokens": 1000, "completionTokens": 2000, "overalUSD": 2.30, "requests": 10 }, "today": { "overallTokens": 999, "promptTokens": 400, "completionTokens": 599, "overalUSD": 0.45, "requests": 2 } }, "status": 200}Using the TypeScript API Client
async function getAggregatedStatsClientExample() { const aggregated = await client.stats.getAggregatedStats(); console.log("Aggregated stats via client:", aggregated);}
getAggregatedStatsClientExample();4. Internal Pricing Logic
The server uses a reference cost structure from a JSON file (pricing.json) to estimate overalUSD. E.g., GPT-4 might cost $0.03/1k tokens for prompt and $0.06/1k tokens for completion. These values are simplified in the code:
currentPricing["gpt-4o"].input / 1000 * promptTokens + currentPricing["gpt-4o"].output / 1000 * completionTokensHence the overalUSD is just a rough cost estimate. Modify in the code if you track a different model or want more accurate pricing.
5. Error Handling
- 400 or 499/500: If an unexpected server or DB error occurs.
- 401/403 Unauthorized: Missing or invalid
Authorizationordatabase-id-hash. - Validation Errors (400): If you pass a
StatDTOmissingeventName,promptTokens, orcompletionTokens.
Error responses generally include:
{ "message": "Error details", "status": <number>}6. Summary of Stats Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/api/stats | PUT | Aggregates usage stats (tokens, eventName). Automatically merges same hour. |
/api/stats/aggregated | GET | Returns an object with monthly + daily usage cost/tokens (thisMonth, lastMonth, today). |
You can expand the logic to add more time frames or advanced queries as needed. This approach focuses on LLM usage but can be adapted for other usage tracking.