API Reference

Complete REST API documentation for the AgentCost backend

Base URL

https://api.yourdomain.com

All API endpoints are relative to this base URL

Authentication

AgentCost uses two types of authentication:

TypeUsed ForHeader
API KeySDK tracking, analytics, eventsAuthorization: Bearer sk_xxx
JWT TokenDashboard, user actions, team managementAuthorization: Bearer eyJ...
bash
# Using API Key (for SDK/tracking)
curl -H "Authorization: Bearer sk_your_project_api_key" \
  YOUR_API_URL/v1/analytics/overview

# Using JWT Token (for user actions)
curl -H "Authorization: Bearer your_jwt_token" \
  YOUR_API_URL/v1/projects/{project_id}/members

Security: API keys provide project-level access for your SDK. JWT tokens are user-specific and expire after 1 hour, but are automatically refreshed.

User Login & Registration

These endpoints handle user account creation and authentication. After login, you receive a JWT token to use with protected endpoints.

POST/v1/auth/register

Create a new user account

Request Body:

json
{
  "email": "user@example.com",
  "password": "your_secure_password",
  "name": "John Doe"
}

Response:

json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "user": {
    "id": "usr_abc123",
    "email": "user@example.com",
    "name": "John Doe",
    "email_verified": false
  },
  "verification_email_sent": true,
  "default_project": {
    "id": "123e4567-e89b-42d3-a456-426614174000",
    "name": "My First Project",
    "api_key": "sk_live_xxxxxxxxxxxx"
  }
}

Registration signs you in immediately — the response carries the same tokens as login. A verification email is sent in the background; verify whenever convenient. The default project's api_key is shown only this once — store it securely.

POST/v1/auth/login

Authenticate and get access tokens

Request Body:

json
{
  "email": "user@example.com",
  "password": "your_password",
  "remember_me": true
}

Response:

json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "user": {
    "id": "usr_abc123",
    "email": "user@example.com",
    "name": "John Doe"
  }
}
POST/v1/auth/refresh

Get a new access token using refresh token

Request Body:

json
{
  "refresh_token": "your_refresh_token"
}

Response:

json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600
}
POST/v1/auth/logoutAuth

Invalidate current session

Response (204 No Content)

Session is invalidated. The access token will no longer be valid.

Health Check

GET/v1/health

Check if the backend is running and healthy

Response:

json
{
  "status": "ok",
  "version": "0.1.0",
  "timestamp": "2024-01-23T10:30:45.123Z"
}

Projects

POST/v1/projects

Create a new project and get an API key

Request Body:

json
{
  "name": "my-project",
  "description": "Optional project description"
}

Response:

json
{
  "id": "proj_abc123",
  "name": "my-project",
  "description": "Optional project description",
  "api_key": "sk_live_xxxxxxxxxxxx",
  "key_prefix": "sk_live_",
  "is_active": true,
  "created_at": "2024-01-23T10:30:45.123Z",
  "updated_at": "2024-01-23T10:30:45.123Z",
  "owner_id": "usr_abc123",
  "warning": "Save this API key now! It cannot be retrieved later."
}

Important: The API key is shown only once on creation. Store it securely and use rotation to generate a new one later.

GET/v1/projects/meAuth

Get the current project (API key auth)

Response:

json
{
  "id": "proj_abc123",
  "name": "my-project",
  "description": "Optional project description",
  "api_key": null,
  "key_prefix": null,
  "is_active": true,
  "created_at": "2024-01-23T10:30:45.123Z",
  "updated_at": "2024-01-23T10:30:45.123Z"
}
GET/v1/projects/{id}Auth

Get project details by ID

Response:

json
{
  "id": "proj_abc123",
  "name": "my-project",
  "description": "Optional project description",
  "api_key": null,
  "key_prefix": null,
  "is_active": true,
  "created_at": "2024-01-23T10:30:45.123Z"
}

API keys are write-only and are never returned in read endpoints.

PATCH/v1/projects/{project_id}Auth

Update project settings

Request Body:

json
{
  "name": "Updated project name",
  "description": "Updated description",
  "is_active": true
}

Response:

json
{
  "id": "proj_abc123",
  "name": "Updated project name",
  "description": "Updated description",
  "api_key": null,
  "key_prefix": null,
  "is_active": true,
  "created_at": "2024-01-23T10:30:45.123Z"
}
DELETE/v1/projects/{project_id}Auth

Delete a project

Response (200 OK)

json
{ "status": "deleted" }

Warning: Deleting a project removes all associated events and analytics.

POST/v1/projects/{project_id}/api-key/rotateAuth

Rotate the project API key (Admin only, JWT auth)

Response:

json
{
  "status": "ok",
  "project_id": "proj_abc123",
  "api_key": "sk_live_xxxxxxxxxxxx",
  "key_prefix": "sk_live_",
  "message": "Save this API key now. It cannot be retrieved later."
}

Team Management

Manage team members and their access to your project. All team endpoints require JWT authentication.

RolePermissions
AdminFull access: invite/remove members, change roles, delete project
MemberView analytics, create events, export data
ViewerRead-only access to analytics and events
GET/v1/projects/{project_id}/membersAuth

List all members of a project

Response:

json
{
  "members": [
    {
      "id": "mem_123",
      "user_id": "usr_abc",
      "email": "admin@example.com",
      "name": "John Doe",
      "role": "admin",
      "is_owner": true,
      "is_pending": false,
      "accepted_at": "2024-01-20T10:00:00Z"
    },
    {
      "id": "mem_456",
      "user_id": "usr_def",
      "email": "viewer@example.com",
      "name": "Jane Smith",
      "role": "viewer",
      "is_owner": false,
      "is_pending": false,
      "accepted_at": "2024-01-22T15:30:00Z"
    }
  ],
  "total": 2
}
POST/v1/projects/{project_id}/membersAuth

Invite a user to the project (Admin only)

Request Body:

json
{
  "email": "newmember@example.com",
  "role": "member"
}

Response:

json
{
  "message": "Invitation sent to newmember@example.com",
  "membership_id": "mem_789",
  "role": "member"
}

An invitation email is sent to the user. They must accept it to join the project.

GET/v1/projects/invitations/pendingAuth

Get your pending project invitations

Response:

json
{
  "invitations": [
    {
      "project_id": "proj_abc123",
      "project_name": "My Project",
      "role": "member",
      "invited_by": {
        "name": "John Doe",
        "email": "john@example.com"
      },
      "invited_at": "2024-01-23T10:30:45.123Z"
    }
  ],
  "total": 1
}
POST/v1/projects/{project_id}/invitations/acceptAuth

Accept a project invitation

Response:

json
{
  "status": "accepted",
  "project_id": "proj_abc123",
  "role": "member"
}
POST/v1/projects/{project_id}/invitations/declineAuth

Decline a project invitation

Response (204 No Content)

PATCH/v1/projects/{project_id}/members/{user_id}Auth

Update a member's role (Admin only)

Request Body:

json
{
  "role": "admin"
}

Response:

json
{
  "status": "updated",
  "new_role": "admin"
}
DELETE/v1/projects/{project_id}/members/{user_id}Auth

Remove a member from the project (Admin only)

Response (204 No Content)

POST/v1/projects/{project_id}/leaveAuth

Leave a project voluntarily

Response (204 No Content)

Project owners cannot leave. They must transfer ownership or delete the project.

Events

POST/v1/events/batchAuth

Ingest a batch of LLM call events (used by SDK)

Try it from your terminal — this one command ingests a sample event and lights up your dashboard:

bash
curl -X POST "https://api.agentcost.tech/v1/events/batch" \
  -H "Authorization: Bearer sk_your_project_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": "123e4567-e89b-42d3-a456-426614174000",
    "events": [
      {
        "agent_name": "my-first-agent",
        "model": "gpt-4o-mini",
        "input_tokens": 150,
        "output_tokens": 80,
        "latency_ms": 1234,
        "timestamp": "2026-08-04T10:30:45Z",
        "success": true
      }
    ]
  }'

project_id is your project's UUID from Settings (not its name) and must match the API key's project — a mismatch returns 403. total_tokens and cost are optional; the server derives and prices them for you.

Request Body:

json
{
  "project_id": "proj_abc123",
  "events": [
    {
      "agent_name": "router-agent",
      "model": "gpt-4",
      "input_tokens": 150,
      "output_tokens": 80,
      "total_tokens": 230,
      "cost": 0.0093,
      "latency_ms": 1234,
      "timestamp": "2024-01-23T10:30:45.123Z",
      "success": true,
      "metadata": {"user_id": "user_123"}
    }
  ]
}

Response:

json
{
  "status": "ok",
  "inserted": 1
}
GET/v1/eventsAuth

Get recent events for the authenticated project

Query Parameters:

ParameterTypeDefaultDescription
limitint100Maximum events to return
offsetint0Number of events to skip
agent_namestr-Filter by agent name

Analytics

GET/v1/analytics/overviewAuth

Get cost overview for the project

Query Parameters:

ParameterTypeDescription
rangestrTime range: 24h, 7d, 30d, 90d

Response:

json
{
  "total_cost": 45.32,
  "total_calls": 2150,
  "total_tokens": 1250000,
  "avg_cost_per_call": 0.021,
  "avg_latency_ms": 850.5,
  "success_rate": 99.5,
  "period_start": "2024-01-16T00:00:00Z",
  "period_end": "2024-01-23T00:00:00Z"
}
GET/v1/analytics/agentsAuth

Get per-agent cost breakdown

Response:

json
[
  {
    "agent_name": "router-agent",
    "total_calls": 850,
    "total_tokens": 425000,
    "total_cost": 18.50,
    "avg_latency_ms": 750,
    "success_rate": 99.8
  },
  {
    "agent_name": "technical-agent",
    "total_calls": 650,
    "total_tokens": 520000,
    "total_cost": 15.20,
    "avg_latency_ms": 920,
    "success_rate": 99.2
  }
]
GET/v1/analytics/modelsAuth

Get per-model cost breakdown

Response:

json
[
  {
    "model": "gpt-4",
    "total_calls": 500,
    "total_tokens": 300000,
    "input_tokens": 180000,
    "output_tokens": 120000,
    "total_cost": 25.50,
    "cost_share": 56.3
  },
  {
    "model": "gpt-3.5-turbo",
    "total_calls": 1200,
    "total_tokens": 600000,
    "input_tokens": 400000,
    "output_tokens": 200000,
    "total_cost": 8.40,
    "cost_share": 18.5
  }
]
GET/v1/analytics/timeseriesAuth

Get time series data for charting

Response:

json
[
  {
    "timestamp": "2024-01-23T00:00:00Z",
    "cost": 5.32,
    "calls": 245,
    "tokens": 125000
  },
  {
    "timestamp": "2024-01-23T01:00:00Z",
    "cost": 4.85,
    "calls": 220,
    "tokens": 115000
  }
]
GET/v1/analytics/fullAuth

Get complete analytics response (overview + agents + models + timeseries)

Response:

json
{
  "overview": { ... },
  "agents": [ ... ],
  "models": [ ... ],
  "timeseries": [ ... ]
}

Workflows & Traces

Cost attributed to the shape of a run rather than to the model that served it. These endpoints read only events carrying trace structure, which the SDK adds when you use workflow(), step() and tool(). Calls made outside a workflow are absent here by design, and remain visible under Analytics. Every endpoint accepts range (1h, 24h, 7d, 30d, 90d).

GET/v1/analytics/workflowsAuth

Cost per workflow, including the average cost of a single run

Response:

json
[
  {
    "workflow": "support-triage",
    "runs": 9500,
    "total_cost": 321.47,
    "avg_cost_per_run": 0.0338,
    "max_cost_per_run": 0.0879,
    "total_calls": 41800,
    "avg_calls_per_run": 4.4,
    "avg_steps_per_run": 3,
    "max_depth": 2,
    "success_rate": 98.7
  }
]
GET/v1/analytics/workflows/stepsAuth

Cost per step. calls_per_run above 1 indicates retries or a loop

Optional workflow query parameter restricts the result to one workflow.

json
[
  {
    "workflow": "support-triage",
    "step_name": "search_docs",
    "calls": 23400,
    "runs": 9500,
    "calls_per_run": 2.4,
    "cost_per_run": 0.0209,
    "total_cost": 203.18,
    "avg_latency_ms": 1250,
    "success_rate": 96.9
  }
]
GET/v1/analytics/workflows/toolsAuth

LLM spend incurred while a named tool was running

Response:

json
[
  {
    "tool_name": "search_docs",
    "calls": 23400,
    "runs": 9500,
    "total_cost": 203.18,
    "total_tokens": 51000000,
    "avg_latency_ms": 1250
  }
]
GET/v1/analytics/workflows/repeated-workAuth

Identical calls repeated within a single run, and what they cost

Distinct from the cross-run duplication the caching analyzer reports: that argues for a cache, this usually means the control flow is looping. wasted_cost covers every occurrence beyond the first.

json
[
  {
    "trace_id": "9f2c41a0b7d3e5f1",
    "workflow": "support-triage",
    "step_name": "search_docs",
    "model": "gpt-4o",
    "occurrences": 4,
    "spend": 0.0435,
    "wasted_cost": 0.0326,
    "first_seen": "2026-08-11T09:14:22Z"
  }
]
GET/v1/analytics/workflows/outcomesAuth

Cost per completed outcome, charging failed runs to the successes

Populated only for runs that called track_costs.outcome(). Runs that declared nothing are counted as unknown rather than as failures.

json
[
  {
    "workflow": "support-triage",
    "runs": 9500,
    "succeeded": 8645,
    "failed": 684,
    "unknown": 171,
    "cost_on_success": 292.20,
    "cost_on_failure": 23.12,
    "cost_per_success": 0.0365,
    "success_rate": 92.67
  }
]
GET/v1/analytics/workflows/distributionAuth

Distribution of cost per run, with percentiles and the tail's share of spend

Computed over every run in the window rather than a top-N slice. Defaults to the highest-spend workflow; pass workflow to choose one, and buckets (6-60) to set the resolution. The final histogram bucket is the tail, marked is_tail.

json
{
  "workflow": "support-triage",
  "runs": 9500,
  "truncated": false,
  "p50": 0.035,
  "p95": 0.045,
  "p99": 0.156,
  "max": 0.182,
  "tail_runs": 476,
  "tail_threshold": 0.0461,
  "tail_share_percent": 14.8,
  "tail_ratio": 4.5,
  "histogram": [
    { "lower": 0.022, "upper": 0.0228, "count": 12, "is_tail": false }
  ]
}
GET/v1/analytics/tracesAuth

Individual runs, most expensive first

Optional workflow parameter. Use the returned trace_id with the endpoint below.

json
[
  {
    "trace_id": "9f2c41a0b7d3e5f1",
    "workflow": "support-triage",
    "calls": 11,
    "total_cost": 0.0879,
    "max_depth": 2,
    "failed_calls": 0,
    "started_at": "2026-08-11T09:14:20Z",
    "duration_ms": 7420
  }
]
GET/v1/analytics/traces/{trace_id}Auth

Every span of one run, ordered as it executed

Spans are returned flat with parent ids rather than pre-nested, so a span whose parent never arrived cannot break the response. Returns 404 if the trace does not belong to your project.

json
{
  "trace_id": "9f2c41a0b7d3e5f1",
  "workflow": "support-triage",
  "total_cost": 0.0879,
  "total_calls": 11,
  "max_depth": 2,
  "duration_ms": 7420,
  "spans": [
    {
      "span_id": "1b40a23d06f0401f",
      "parent_span_id": null,
      "step_name": "classify",
      "tool_name": null,
      "step_index": 0,
      "depth": 1,
      "model": "gpt-4o",
      "cost": 0.00082,
      "latency_ms": 340,
      "success": true
    }
  ]
}

Optimizations

GET/v1/optimizationsAuth

Get AI-powered cost optimization suggestions

Response:

json
[
  {
    "type": "model_downgrade",
    "title": "Switch router-agent from gpt-4 to gpt-3.5-turbo",
    "description": "Agent 'router-agent' uses gpt-4 but generates only 50 tokens on average.",
    "estimated_savings_monthly": 45.50,
    "estimated_savings_percent": 95.0,
    "priority": "high",
    "action_items": [
      "Review prompts and outputs",
      "Test with gpt-3.5-turbo",
      "Update model configuration"
    ]
  }
]
GET/v1/optimizations/summaryAuth

Get summary of potential savings

Response:

json
{
  "total_potential_savings_monthly": 125.50,
  "total_potential_savings_percent": 35.2,
  "suggestion_count": 5,
  "high_priority_count": 2
}

Error Handling

The API uses standard HTTP status codes. Error responses include a message explaining what went wrong:

json
{
  "detail": "Invalid API key"
}
Status CodeDescription
200Success
201Created
400Bad Request - Invalid input
401Unauthorized - Invalid or missing API key
404Not Found - Resource does not exist
429Too Many Requests - Rate limit exceeded
500Internal Server Error

Rate Limiting

The API enforces rate limiting to ensure fair usage and protect the service. Rate limits are applied per API key or IP address.

Default limits: 100 requests per minute

Rate limit headers are included in all API responses:

http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 45

When rate limited, you'll receive a 429 response:

json
{
  "detail": "Rate limit exceeded. Please slow down.",
  "retry_after": 45,
  "limit": 100,
  "period": "60 seconds"
}

Tip: The SDK automatically handles rate limiting with built-in batching and retry logic. You typically don't need to worry about rate limits when using the SDK.

SDKs & Libraries

Official SDK for integrating AgentCost into your applications:

Python SDK

For OpenAI, Anthropic, Gemini, and LangChain applications

bash
pip install agentcost

Coming Soon: JavaScript/TypeScript SDK, Go SDK, and REST client libraries for other languages.

Webhooks

Receive real-time notifications when events occur in your project.

Planned Webhook Events

  • cost.threshold.exceeded - Daily cost limit exceeded
  • error.rate.high - Error rate above threshold
  • latency.high - Average latency above threshold
  • project.created - New project created

Coming Soon: Webhooks are currently in development. Contact us if you need this feature for your use case.

API Versioning

The API uses URL path versioning. The current version is v1.

VersionStatusNotes
v1CurrentStable, recommended for production

We follow semantic versioning. Breaking changes will result in a new major version. Deprecated endpoints will be announced at least 6 months before removal.