API Reference

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

  • JWT (Bearer) — obtained from POST /v1/auth/login and required for every dashboard, billing, agent, alert, key, and org-budget endpoint.
  • API key (Bearer) — an ak_{env}_... key, used only 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_...) and the Python SDK uses that prefix to pick the right backend automatically.

POST /v1/ingest #

Submit a batch of usage events. Authenticated with an API key. The endpoint validates subscription status, per-tier daily event quota, burst rate, and the per-tier active agent cap, then writes events to Kafka (production) or directly to the database (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 (defaults to 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 silently 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 where Kafka is not configured. rejected_agents lists any agents whose events were dropped because the org is at its tier's max_agents cap.

Error responses

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

Authentication #

POST /v1/auth/register

Creates the organization and owner user, then emails a 6-digit verification OTP. Returns 201. 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/expired code, 404 if the user does not exist, 429 if the per-IP OTP throttle trips.

POST /v1/auth/login

Body: { "email", "password" }. Returns:

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 OTP. Always returns 200 to prevent user enumeration.
  • POST /v1/auth/verify-reset-code — exchanges an OTP for a short-lived reset token (5 min).
  • POST /v1/auth/reset-password — sets a new password using the reset token.
  • POST /v1/auth/resend-otp — resend an OTP (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 #

Bearer JWT required for every endpoint in this section.

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 immediately

The hashed key is stored server-side. The plaintext is shown once at creation and on rotation. Treat it as a password.

GET /v1/keys

List the org's keys. The raw key is never returned; auth_failures_count and last_failed_at surface revoked-key usage attempts so you can spot stale agents.

DELETE /v1/keys/{key_id}

Soft-deletes the key (is_active=false) and flushes the auth cache. Returns 204; 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 #

Bearer JWT required.

GET /v1/agents

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

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 silently 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 series. 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 / POST /v1/agents/{name}/budgets — list / 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 #

Bearer JWT required.

GET /v1/dashboard/overview

Spend totals, event counts, active agent counts, and token / 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 charting. Query parameters: granularity (hourly or daily, default hourly) and days (1–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 and/or timezone (IANA name). Also exposed at GET/PUT/PATCH /v1/settings.

Runs #

Runs group events sharing the same run_id. Bearer JWT required.

  • GET /v1/agents/{name}/runs — list runs for an agent.
  • GET /v1/runs/{run_id} — single run summary. Status is auto-resolved to completed when no events have arrived for > 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 computed 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 #

All endpoints (except /webhook) require Bearer JWT.

  • 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 this once on startup and falls back to its bundled table if 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 convention { "detail": "..." }. Some endpoints add additional fields (e.g. reason, resume_at, subscription_status) to help clients react programmatically. See Error Codes for the SDK and HTTP mapping.