API Reference

REST endpoints exposed by the AgentKavach backend. All paths are prefixed with /v1. Two authentication schemes are in use.

  • JWT bearer token. Returned by POST /v1/auth/login. Required for every dashboard, billing, agent, alert, key, and org-budget endpoint.
  • API key bearer token. An ak_{env}_... key. Used by POST /v1/ingest and POST /v1/sync-config. Pass it in the same Authorization: Bearer <key> header.

ℹ️ Base URL

Production: https://agentcostguard-backend.onrender.com. Local development: http://localhost:8000. API keys carry their environment in the prefix (ak_prod_..., ak_dev_..., ak_local_...). The Python SDK uses the prefix to pick the right backend.

POST /v1/ingest #

Submit a batch of usage events. Authenticated with an API key. The endpoint validates subscription status, daily event quota, burst rate, and the active agent cap. It then writes events to Kafka in production or directly to the database in dev.

PropertyValue
Method / PathPOST /v1/ingest
AuthAuthorization: Bearer ak_{env}_...
Status code on success202 Accepted

Request body

{ "events": [Event, ...] }. Batch size is capped server-side. Default 1000 events.

ParameterTypeRequiredDefaultDescription
agent_namestringYesLogical name of the agent that made the LLM call.
providerstringYes"openai", "anthropic", "google", or "mistral".
modelstringYesModel identifier (e.g. "gpt-4o", "claude-sonnet-4-0").
input_tokensintYesPrompt tokens. Must be >= 0.
output_tokensintYesCompletion tokens. Must be >= 0.
costfloatYesComputed cost in USD. Must be >= 0.
timestampstringYesISO 8601 timestamp.
duration_msintNo0Wall-clock duration of the LLM call.
idempotency_keystringNoUnique per-event key. Duplicates within the deduplication window are dropped.
run_idstringNoIdentifier that groups events into a single run.
promptstringNoPrompt text. Only sent when the SDK was constructed with save_prompts=True.

Request example

bash
curl -X POST https://agentcostguard-backend.onrender.com/v1/ingest \
  -H "Authorization: Bearer ak_prod_..." \
  -H "Content-Type: application/json" \
  -d '{
    "events": [{
      "agent_name": "research-bot",
      "provider": "openai",
      "model": "gpt-4o",
      "input_tokens": 1500,
      "output_tokens": 800,
      "cost": 0.0155,
      "duration_ms": 1250,
      "timestamp": "2026-05-25T14:30:00Z",
      "run_id": "run_abc123",
      "idempotency_key": "evt_unique_001"
    }]
  }'

Response

json
{
  "accepted": 1,
  "rejected": 0,
  "mode": "kafka",
  "rejected_agents": []
}

mode is "kafka" in production and "direct" on backends without Kafka. rejected_agents lists agents whose events were dropped because the org is at its tier's max_agents cap.

Error responses

StatusCondition
401Missing or malformed Authorization header, or unknown API key.
403Subscription cancelled or paused. Reactivate to resume.
422Request body fails Pydantic validation, for example negative tokens.
429Daily quota exhausted, burst rate exceeded, or org cost budget exceeded. The response body includes reason: daily_limit, burst, or org_budget_exceeded.

Authentication #

POST /v1/auth/register

Creates the organization and the owner user. Emails a 6-digit verification code. Returns 202 Accepted. No JWT is issued until the email is verified.

ParameterTypeRequiredDefaultDescription
emailstringYesUser email.
passwordstringYesUser password.
org_namestringYesDisplay name for the new organization.
first_namestringNo""Owner first name.
last_namestringNo""Owner last name.
json
{
  "message": "Verification code sent",
  "email": "alice@example.com",
  "requires_verification": true
}

409 Conflict if the email is already registered.

POST /v1/auth/verify-email

Body: { "email": "...", "code": "123456" }. Returns a JWT on success. 400 for an invalid or expired code. 404 if the user does not exist. 429 when the per-IP OTP throttle trips.

POST /v1/auth/login

Body: { "email", "password" }. Returns the access token.

json
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "bearer",
  "expires_in": 86400
}

401 for bad credentials. 403 if the email is unverified.

Other auth endpoints

  • POST /v1/auth/forgot-password. Emails a reset code. Always returns 200 to prevent user enumeration.
  • POST /v1/auth/verify-reset-code. Exchanges a code for a short-lived reset token (5 minutes).
  • POST /v1/auth/reset-password. Sets a new password using the reset token.
  • POST /v1/auth/resend-otp. Resend a code. Rate-limited.
  • POST /v1/auth/refresh. Refresh an access token within a 24-hour grace window.
  • POST /v1/auth/change-password. Change password while authenticated.
  • GET /v1/auth/me. Current user profile.

API keys #

JWT bearer required.

POST /v1/keys

Mints a new ak_{env}_... key. The raw key is returned only once.

json
{
  "id": "key_abc...",
  "name": "Production",
  "prefix": "ak_prod_abc12345",
  "is_active": true,
  "created_at": "2026-05-25T14:30:00Z",
  "last_used_at": null,
  "auth_failures_count": 0,
  "last_failed_at": null,
  "raw_key": "ak_prod_<64-hex>"
}

⚠️ Save the raw key now

The server stores a hash. The plaintext key is shown once at creation and once on rotation. Treat it as a password.

GET /v1/keys

Lists the org's keys. The raw key is never returned. The response includes auth_failures_count and last_failed_at so you can spot stale agents still using a revoked key.

DELETE /v1/keys/{key_id}

Soft-deletes the key by setting is_active=false and flushes the auth cache. Returns 204. Returns 404 if the key is not in the caller's org.

POST /v1/keys/{key_id}/rotate

Atomically revokes the old key and returns a new one with the same name.

Agents #

JWT bearer required.

GET /v1/agents

Lists agents with spend roll-ups. Accepts optional start and end ISO timestamps for a custom range.

json
{
  "agents": [
    {
      "agent_name": "research-bot",
      "provider": "openai",
      "model": "gpt-4o",
      "total_events": 15000,
      "total_cost": 120.00,
      "cost_today": 12.50,
      "cost_week": 45.00,
      "cost_month": 120.00,
      "input_tokens_today": 500000,
      "output_tokens_today": 150000,
      "total_input_tokens": 3000000,
      "total_output_tokens": 800000,
      "total_duration_ms": 1500000,
      "range_events": 1200,
      "range_cost": 25.00,
      "budget_limit_usd": 50.00,
      "budget_used_pct": 25.0,
      "status": "active",
      "has_kill_switch": false,
      "last_active": "2026-05-25T14:30:00Z"
    }
  ],
  "total": 1,
  "api_key_prefix": "ak_prod_abc12345",
  "tier": "pro",
  "timezone": "America/New_York",
  "rejected_agents": []
}

rejected_agents lists agents whose events /v1/ingest is dropping because the org is at its tier's max_agents cap.

GET /v1/agents/{name}

Detail view with spend per period, primary model, model usage breakdown, and a 7-day spend history. 404 if the agent name is not known.

Related agent endpoints

  • GET /v1/agents/{name}/events. Recent events for the agent.
  • GET /v1/agents/{name}/alerts. Alert history for the agent.
  • GET /v1/agents/{name}/configs. Alert configurations on the agent.
  • GET /v1/agents/{name}/budgets and POST /v1/agents/{name}/budgets. List or create per-agent budgets.
  • POST /v1/agents/{name}/kill. Trigger the kill switch for one agent.
  • POST /v1/agents/kill-all. Kill every active agent in the org.

Dashboard #

JWT bearer required.

GET /v1/dashboard/overview

Spend totals, event counts, active agent counts, and token and duration roll-ups for the org. Query parameters: range (today | 7d | 30d | custom), from_date, to_date (ISO; required when range=custom).

json
{
  "total_spend_today": 12.45,
  "total_spend_week": 67.23,
  "total_spend_month": 234.56,
  "events_today": 1250,
  "events_week": 8430,
  "events_month": 31200,
  "tier": "pro",
  "active_agents_today": 5,
  "active_agents_week": 7,
  "active_agents_month": 12,
  "events_per_day": 10000,
  "max_agents": 100,
  "input_tokens_today": 500000,
  "output_tokens_today": 150000,
  "duration_ms_today": 345000,
  "org_budget_limit": 50.0,
  "org_budget_used": 23.45,
  "org_budget_pct": 46.9,
  "org_budget_period": "daily"
}

GET /v1/dashboard/spend

Time series for charts. Query parameters: granularity (hourly or daily, default hourly) and days (1 to 90, default 7).

GET /v1/dashboard/stats

Top models and top agents by spend for the selected range. Same range / from_date / to_date parameters as /overview.

PUT /v1/dashboard/settings

Update org_name or timezone (IANA name). Also exposed at GET/PUT/PATCH /v1/settings.

Runs #

Runs group events that share a run_id. JWT bearer required.

  • GET /v1/agents/{name}/runs. List runs for an agent.
  • GET /v1/runs/{run_id}. Single run summary. Status auto-resolves to completed when no events have arrived for more than 5 minutes.
  • GET /v1/runs/{run_id}/events. Events recorded for the run.

Alerts #

  • GET /v1/alerts?range=today|7d|30d|90d. Recent alert events. Newest 200.
  • GET /v1/alerts/configs. Configured alert channels.
  • POST /v1/alerts/configs. Create an alert config { agent_name, channel, threshold_pct, target? }.

Org budgets #

GET /v1/org/budgets

Lists org-wide budgets with current usage and percentage utilization.

POST /v1/org/budgets

Creates or upserts an org budget by (budget_type, period).

ParameterTypeRequiredDefaultDescription
budget_typestringYes"cost", "tokens_total", "tokens_input", "tokens_output", "calls", or "duration".
periodstringYes"daily", "monthly", or "total".
limit_valuefloatYesLimit value. Must be > 0.

DELETE /v1/org/budgets/{id}

204 on success. 404 if the budget id is unknown.

Billing #

Every endpoint requires JWT bearer except /webhook.

  • GET /v1/billing/plan. Current tier, quotas, subscription status, trial info.
  • POST /v1/billing/checkout. Create a Stripe Checkout session.
  • POST /v1/billing/portal. Create a Stripe Customer Portal session.
  • POST /v1/billing/confirm-payment. Manual confirmation for the dev checkout path.
  • POST /v1/billing/change-tier. Dev-only tier switch.
  • POST /v1/billing/pause, /resume, /cancel, /reactivate. Subscription lifecycle.
  • POST /v1/billing/toggle-auto-renew. Flip auto-renew on the active paid plan.
  • GET /v1/billing/payments. Payment history.
  • POST /v1/billing/webhook. Stripe webhook receiver. Signature verified. No JWT.
  • DELETE /v1/billing/delete-organization. Soft-delete the org.

Pricing #

GET /v1/pricing

Public endpoint. No authentication. Returns the model pricing table the SDK uses for cost calculation. The SDK fetches it once on startup and falls back to its bundled table when the backend is unreachable.

bash
curl https://agentcostguard-backend.onrender.com/v1/pricing

Health #

  • GET /healthz. Liveness probe.
  • GET /v1/status. Reports DB, Redis, and Kafka availability.

Error response format #

All errors follow the FastAPI shape { "detail": "..." }. Some endpoints add extra fields, for example reason, resume_at, or subscription_status. See Error Codes for the SDK and HTTP mapping.