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/loginand required for every dashboard, billing, agent, alert, key, and org-budget endpoint. - API key (Bearer) — an
ak_{env}_...key, used only byPOST /v1/ingestandPOST /v1/sync-config. Pass it in the sameAuthorization: Bearer <key>header.
ℹ️ Base URL
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).
| 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 (defaults to 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 silently 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 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
| Status | Condition |
|---|---|
401 | Missing/malformed Authorization header, or unknown API key. |
403 | Subscription cancelled or paused. Reactivate to resume. |
422 | Request body fails Pydantic validation (e.g. negative tokens). |
429 | Daily 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.
| 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/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:
{
"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.
{
"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
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:
{
"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).
{
"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 tocompletedwhen 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).
| 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 #
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.
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 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.