TOKENR

API Documentation

Track and query LLM costs programmatically using the tokenr API.

Authentication

All API requests require a Bearer token in the Authorization header:

Authorization: Bearer YOUR_API_TOKEN

Generate tokens from the API Tokens page.


Endpoints

POST /api/v1/track

Track a single LLM request. Requires write scope.

Request Body

{
  "model": "gpt-4o",
  "provider": "openai",
  "agent_id": "customer-support-agent",
  "feature_name": "ticket-classification",
  "team_id": "engineering",
  "input_tokens": 500,
  "output_tokens": 150,
  "total_cost": 0.0195,        // optional, calculated if omitted
  "latency_ms": 1250,
  "status": "success",
  "external_id": "req_abc123", // optional, for deduplication
  "requested_at": "2024-01-15T10:30:00Z",
  "tags": { "env": "production" },
  "metrics": { "temperature": 0.7 }
}

Response

{
  "id": 12345,
  "cost": 0.0195
}

POST /api/v1/track/batch

Track multiple LLM requests at once. Requires write scope.

Request Body

{
  "requests": [
    { "model": "gpt-4o", "input_tokens": 100, "output_tokens": 50, "agent_id": "agent-1" },
    { "model": "gpt-4o-mini", "input_tokens": 200, "output_tokens": 100, "agent_id": "agent-2" }
  ]
}

Response

{
  "accepted": 2,
  "rejected": 0,
  "errors": []
}

GET /api/v1/costs

Query cost data with filters. Requires read scope.

Query Parameters

ParameterDescription
start_dateStart date (ISO 8601). Default: 30 days ago
end_dateEnd date (ISO 8601). Default: now
agent_idFilter by agent ID
modelFilter by model name
team_idFilter by team ID
featureFilter by feature name
group_byGroup results: agent_id, feature_name, team_id

Response

{
  "total_cost": 1250.45,
  "total_requests": 45230,
  "total_tokens": 12500000,
  "input_tokens": 10000000,
  "output_tokens": 2500000,
  "period": {
    "start": "2024-01-01T00:00:00Z",
    "end": "2024-01-31T23:59:59Z"
  }
}

GET /api/v1/costs/agents

Get costs grouped by agent. Requires read scope.

Query Parameters

ParameterDescription
limitNumber of agents to return. Default: 50
start_dateStart date filter
end_dateEnd date filter

Response

{
  "agents": [
    {
      "agent_id": "customer-support-agent",
      "total_cost": 450.25,
      "input_tokens": 5000000,
      "output_tokens": 1200000,
      "request_count": 12500
    }
  ]
}

GET /api/v1/costs/models

Get costs grouped by model. Requires read scope.

Response

{
  "models": [
    {
      "model": "gpt-4o",
      "display_name": "GPT-4o",
      "total_cost": 800.50,
      "input_tokens": 8000000,
      "output_tokens": 2000000,
      "request_count": 25000
    }
  ]
}

GET /api/v1/costs/timeseries

Get time series cost data. Requires read scope.

Query Parameters

ParameterDescription
intervalhour, day, week, or month. Default: day
start_dateStart date filter
end_dateEnd date filter

Response

{
  "interval": "day",
  "data": [
    { "time": "2024-01-15T00:00:00Z", "cost": 45.25, "tokens": 500000, "requests": 1250 },
    { "time": "2024-01-16T00:00:00Z", "cost": 52.10, "tokens": 580000, "requests": 1400 }
  ]
}

GET /api/v1/tokens/me

Get information about the current API token.

Response

{
  "token": {
    "prefix": "ac_prod_",
    "name": "Production SDK",
    "scopes": ["read", "write"],
    "created_at": "2024-01-01T00:00:00Z",
    "expires_at": null,
    "usage_count": 12500,
    "last_used_at": "2024-01-15T10:30:00Z"
  },
  "organization": {
    "id": 1,
    "name": "Acme Corp",
    "slug": "acme-corp"
  }
}

Rate Limits

Rate limit headers are included in responses:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
Retry-After: 60

Error Responses

// 401 Unauthorized
{ "error": "Invalid API token" }

// 403 Forbidden
{ "error": "Token missing required scope: write" }

// 429 Too Many Requests
{ "error": "Rate limit exceeded. Retry in 45 seconds." }

// 422 Unprocessable Entity
{ "error": "Model can't be blank" }

Ruby SDK

Install the SDK for automatic tracking:

# Gemfile
gem 'tokenr_sdk'

# Configuration
tokenrSdk.configure do |c|
  c.api_key = ENV['AGENT_COST_API_KEY']
  c.agent_id = 'my-agent'
end

# Track manually
tokenrSdk.track(model: 'gpt-4o', input_tokens: 500, output_tokens: 100)

# Or wrap your OpenAI client
client = OpenAI::Client.new(access_token: ENV['OPENAI_KEY'])
tracked = tokenrSdk::Integrations::OpenAI.wrap(client, agent_id: 'my-agent')
tracked.chat(parameters: { model: 'gpt-4o', messages: [...] })