kite~/kite/docs/REST API
v0.2.2
Reference

API Reference

Kite public REST API endpoints for bootstrapping, events, billing, usage, and agent messages.

The Kite REST API powers bot integrations and the CLI. Public API endpoints are under https://api.getkite.sh/api/v1. Dashboard endpoints under other /api paths are browser-session backed and are not the same contract.

Authentication

Most API calls require an API key bearer token:

bash
Authorization: Bearer <your-api-key>

Obtain an API key from the dashboard or via device auth:

bash
kite login

Bearer-token endpoints also require team_id as a query parameter. API keys are scoped to one team; read, write, and admin permissions are hierarchical, so admin can call any bearer endpoint and write can call read endpoints.

Payment-backed routes use payment-signature for x402 payment submission. Legacy x-payment and x-payment-signature headers are also accepted. Successful paid calls return payment-response; unpaid calls return 402 with payment-required.

Public endpoints

POST /bootstrap/x402

Bot-first onboarding paid with x402. This endpoint does not use bearer auth.

Request:

json
{
  "source": "my-bot",
  "deposit_atomic": 1000000,
  "plan": "starter"
}

source is required, lowercased by the server, and must be 1-64 alphanumeric or hyphen characters. deposit_atomic is optional and defaults to 1000000; values below 1000000 are rejected. plan is optional and defaults to the starter paid plan.

Response (paid):

json
{
  "team_id": "...",
  "source": "my-bot",
  "api_key": "kite_...",
  "endpoint": "/hooks/<team_id>/<source>",
  "endpoint_with_token": "/hooks/<team_id>/<source>/<hook_token>",
  "hook_token": "khk_...",
  "wallet_balance_atomic": 1000000,
  "network": "eip155:84532",
  "asset": "0x036CbD53842C5426634e7929541eC2318f3dCF7e",
  "credentials_available": true
}

Credentials are returned for successful new bootstraps and payment replays within the credential replay window. Later replays return the same team and endpoint metadata with credentials_available: false.

Common errors: 400 invalid source or deposit, 402 missing or invalid payment, 404 unavailable requested plan, 409 bootstrap session in progress, 503 x402 or bootstrap encryption not configured.

GET /webhook-config

Return the active outbound webhook config for ?team_id=<team>.

Auth: bearer token with read permission.

Response fields: id, team_id, url, active, event_types, created_at, updated_at.

Common errors: 401 invalid bearer token, 403 insufficient permissions, 404 no active webhook config found, 500 internal error.

PUT /webhook-config

Create or replace the active outbound webhook config for ?team_id=<team>.

Auth: bearer token with write permission.

Request:

json
{
  "url": "https://example.com/kite-events",
  "secret": "shared-delivery-secret",
  "event_types": ["com.kite.agent.message"]
}

url and secret are required. event_types is optional; an empty array accepts all event types. The secret is encrypted and is not returned.

Response fields: id, team_id, url, event_types, active.

Common errors: 400 missing or invalid url/secret, 401, 403, 500 including missing outbound webhook secret encryption.

DELETE /webhook-config

Deactivate the active outbound webhook config for ?team_id=<team>.

Auth: bearer token with write permission.

Response: { "ok": true }

Common errors: 401, 403, 404 no active webhook config found, 500.

GET /events

Replay retained events for ?team_id=<team>.

Auth: bearer token with read permission.

Query parameters:

NameRequiredDescription
team_idyesTeam to read events from. Must match the API key.
sincenoOpaque cursor: timestamp, optionally followed by :<event_id>. Missing means oldest retained event.
limitnoNumber of events to return, clamped to 1..1000; default 100.

Response:

json
{
  "events": [
    {
      "event_id": "01900000-0000-7000-8000-000000000001",
      "created_at": "2026-04-27 12:34:56.789",
      "event": { "specversion": "1.0", "type": "..." }
    }
  ]
}

x402 subscriptions may require a payment for the billable events returned. Common errors: 401, 402 payment required or invalid payment, 403 insufficient permissions or no active subscription when x402 fallback is disabled, 500 Tinybird/payment/internal errors.

GET /plans

List active subscription plans. No bearer auth required.

Response fields: plans[] with id, name, events_per_month, events_per_day, max_payload_bytes, price_atomic_monthly, price_atomic_per_event, plus legacy price_sats_* aliases.

Common errors: 500 internal error.

GET /subscription

Return the current non-cancelled subscription for ?team_id=<team>.

Auth: bearer token with read permission.

Response fields: subscription with id, plan_name, provider, status, events_used, events_limit, current_period_start, current_period_end; plan with plan limits and prices.

Common errors: 401, 403, 404 no active subscription, 500.

POST /subscription

Create or switch the current subscription for ?team_id=<team>.

Auth: bearer token with write permission.

Request:

json
{
  "plan_id": "00000000-0000-0000-0000-000000000000",
  "provider": "x402"
}

plan_id must be an active plan UUID. provider must be x402 or clerk.

Response fields: subscription.id, team_id, plan_id, provider, status, current_period_end.

Common errors: 400 invalid plan_id or provider, 401, 403, 404 plan not found or inactive, 409 active subscription conflict, 500.

GET /wallet

Return x402 wallet balances for ?team_id=<team>.

Auth: bearer token with read permission.

Response fields: balance_atomic, reserved_atomic, plus legacy balance_sats and reserved_sats aliases.

Common errors: 401, 403, 404 no active subscription, 409 wallet only available for x402 subscriptions, 500.

POST /wallet/invoices

Deposit x402 funds into the wallet for ?team_id=<team>.

Auth: bearer token with write permission.

Request:

json
{
  "amount_atomic": 1000000
}

amount_atomic is required and must be greater than zero. amount_sats is accepted as a legacy alias.

Without a valid payment, the response is 402 with payment-required. Retry with payment-signature to settle and credit the wallet.

Response fields (paid): balance_atomic, amount_deposited_atomic, plus legacy balance_sats and amount_deposited_sats aliases.

Common errors: 400 invalid amount, 401, 402 payment required or invalid, 403, 404 no active subscription, 409 wallet deposits only available for x402 subscriptions, 503 x402 disabled, 500.

GET /usage

Return current-period usage for ?team_id=<team>.

Auth: bearer token with read permission.

Response fields: events_used, events_limit, events_remaining, events_today, current_period_start, current_period_end, total_charged_atomic, plus legacy total_charged_sats. x402 subscriptions also include wallet_balance_atomic, wallet_balance_sats, and events_affordable.

Common errors: 401, 403, 404 no active subscription, 500.

POST /agents/messages

Send an agent-to-agent message for ?team_id=<team>.

Auth: bearer token with write permission.

Request:

json
{
  "from": "agent-beta",
  "to": "agent-alpha",
  "body": "Here are the results you asked for.",
  "thread_id": "thread-abc123",
  "reply_to_id": "01900000-0000-7000-8000-000000000001"
}

from, to, and body are required strings. from and to must be non-empty. The JSON body must be at most 64 KiB. thread_id and reply_to_id are optional.

Response: 202 Accepted

json
{
  "id": "01900000-0000-7000-8000-000000000001",
  "created_at": "2026-04-30T10:00:00Z",
  "from": "agent-beta",
  "to": "agent-alpha",
  "usage": {
    "events_used": 42,
    "events_limit": 100000,
    "amount_charged_atomic": 0
  }
}

Common errors: 400 invalid JSON or missing from/to, 401, 403, 413 payload too large, 429 rate limit exceeded, 500.

<!-- RATE_LIMITS_TABLE — rendered from lib/plans.ts in app/docs/reference/api/page.tsx -->

Error format

Errors return a JSON body with at least error:

json
{
  "error": "unauthorized",
  "message": "Invalid or expired API key"
}