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 byPOST /v1/ingestandPOST /v1/sync-config. Pass it in the sameAuthorization: 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.
| Property | Value |
|---|---|
| Method / Path | POST /v1/ingest |
| Auth | Authorization: Bearer ak_{env}_... |
| Status code on success | 202 Accepted |
Request body
{ "events": [Event, ...] }. Batch size is capped server-side. Default 1000 events.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
agent_name | string | Yes | — | Logical name of the agent that made the LLM call. |
provider | string | Yes | — | "openai", "anthropic", "google", or "mistral". |
model | string | Yes | — | Model identifier (e.g. "gpt-4o", "claude-sonnet-4-0"). |
input_tokens | int | Yes | — | Prompt tokens. Must be >= 0. |
output_tokens | int | Yes | — | Completion tokens. Must be >= 0. |
cost | float | Yes | — | Computed cost in USD. Must be >= 0. |
timestamp | string | Yes | — | ISO 8601 timestamp. |
duration_ms | int | No | 0 | Wall-clock duration of the LLM call. |
idempotency_key | string | No | — | Unique per-event key. Duplicates within the deduplication window are dropped. |
run_id | string | No | — | Identifier that groups events into a single run. |
prompt | string | No | — | Prompt text. Only sent when the SDK was constructed with save_prompts=True. |
Request example
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
{
"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
| Status | Condition |
|---|---|
401 | Missing or malformed Authorization header, or unknown API key. |
403 | Subscription cancelled or paused. Reactivate to resume. |
422 | Request body fails Pydantic validation, for example negative tokens. |
429 | Daily 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.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
email | string | Yes | — | User email. |
password | string | Yes | — | User password. |
org_name | string | Yes | — | Display name for the new organization. |
first_name | string | No | "" | Owner first name. |
last_name | string | No | "" | Owner last name. |
{
"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.
{
"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.
{
"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.
{
"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}/budgetsandPOST /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).
{
"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 tocompletedwhen 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).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
budget_type | string | Yes | — | "cost", "tokens_total", "tokens_input", "tokens_output", "calls", or "duration". |
period | string | Yes | — | "daily", "monthly", or "total". |
limit_value | float | Yes | — | Limit 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.
curl https://agentcostguard-backend.onrender.com/v1/pricingHealth #
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.