Docs

API Reference

HTTP contracts for event ingestion, customer traits, administration, and service health.

Kite exposes a versioned ingestion API for product backends and a separate administrative API used by the CLI.

SurfaceAuthenticationIntended client
/v1/events, /v1/events/batchProject environment API keyBackend services and SDKs
/projects/*CLI bearer session and organization headerKite CLI
Health probesNoneInfrastructure
/metricsInternal bearer tokenKite operators

For Node.js applications, prefer the Node.js SDK. It implements retries, idempotency, timeouts, and typed errors around the ingestion endpoints documented here.

Base URL

Kite Cloud:

https://api.usekite.cloud

All public ingestion paths are versioned. Use /v1/events, not /events; the unversioned path does not exist.

Authentication

Send a project API key as a bearer token:

Authorization: Bearer kt_test_...
Content-Type: application/json

The key selects both the project and environment:

PrefixEnvironment
kt_test_test
kt_live_live

There is no environment field in an ingestion request. To change environments, use the corresponding key.

Keep keys on the server

Never send project API keys to a browser or mobile client. Route product events through a trusted backend and store keys in your deployment platform's secret manager.

Track an event

POST /v1/events

Records one product event. This endpoint accepts only track operations; customer traits must be sent through the batch endpoint.

curl -X POST https://api.usekite.cloud/v1/events \
  -H "Authorization: Bearer $KITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customerId": "customer_123",
    "event": "feature.used",
    "properties": { "feature": "reports" },
    "idempotencyKey": "usage_456"
  }'

Request body

FieldTypeRequiredDescription
customerIdstringyesStable customer ID from your system, up to 256 characters.
eventstringyesEvent name, up to 256 characters.
propertiesJSON objectnoEvent properties, up to 64 KiB when serialized. Defaults to {}.
timestampISO 8601 stringnoEvent time with timezone. Defaults to ingestion time.
idempotencyKeystringnoNon-empty deduplication key, up to 256 characters.
type"track"noOptional discriminator. Other values are rejected.

Valid timestamps include 2026-07-20T14:30:00Z and 2026-07-20T11:30:00-03:00. A timestamp without a timezone is rejected.

Response

Kite returns HTTP 202 Accepted after accepting the event:

{
  "eventId": "evt_01K...",
  "accepted": true,
  "queued": true,
  "duplicate": false
}

queued: true means durable ingestion accepted the event; downstream effects such as signals and webhook deliveries may continue asynchronously.

Identify a customer

Identify operations update traits used by lifecycle, rules, segments, and health. They are sent inside POST /v1/events/batch:

curl -X POST https://api.usekite.cloud/v1/events/batch \
  -H "Authorization: Bearer $KITE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      {
        "type": "identify",
        "customerId": "customer_123",
        "traits": { "plan": "growth", "seats": 12 }
      }
    ]
  }'
FieldTypeRequiredDescription
type"identify"yesSelects a trait update.
customerIdstringyesStable customer ID, up to 256 characters.
traitsJSON objectyesTraits, up to 64 KiB when serialized.

Only customerId and traits are processed for an identify operation. Do not include track fields such as event, properties, or idempotencyKey.

Batch operations

POST /v1/events/batch

Sends between 1 and 1,000 track or identify operations in one ordered request.

{
  "events": [
    {
      "type": "identify",
      "customerId": "customer_123",
      "traits": { "plan": "growth" }
    },
    {
      "type": "track",
      "customerId": "customer_123",
      "event": "workspace.invited",
      "properties": { "role": "admin" },
      "idempotencyKey": "invite_789"
    }
  ]
}

For track operations, type can be omitted and defaults to track. Operations are evaluated in array order, so an identify can affect a track operation that follows it.

Successful batches return HTTP 202:

{
  "accepted": 2,
  "rejected": 0,
  "eventIds": ["evt_01K..."]
}

eventIds contains IDs for track operations. Identify operations update state but do not create product-event IDs.

Atomic validation

Kite validates the complete batch before ingesting it. An invalid operation or idempotency conflict rejects the request without partially accepting earlier operations.

Schema validation

The active configuration defines event properties and customer traits. Kite validates:

  • declared event names;
  • required and unknown properties;
  • string, number, boolean, date, and array types;
  • enum values;
  • identify traits.

With strictSchema: true, violations return HTTP 422. The error includes the first failure and a diagnostics array with all detected paths:

{
  "error": {
    "code": "INVALID_PROPERTY_ENUM",
    "message": "Property \"plan\" must be one of: free, pro.",
    "field": "events[0].properties.plan",
    "requestId": "req_...",
    "diagnostics": [
      {
        "code": "INVALID_STRUCTURE",
        "message": "Property \"plan\" must be one of: free, pro.",
        "path": "events[0].properties.plan"
      }
    ]
  }
}

With strictSchema: false, Kite accepts the operation and logs the schema diagnostics. See the Config Reference for schema definitions.

Idempotency

Set idempotencyKey on track operations that may be retried.

  • Repeating the same key with the same canonical payload returns the original eventId and duplicate: true for a single event.
  • Reusing a key with a different customer, event, properties, or explicit timestamp returns HTTP 409 IDEMPOTENCY_CONFLICT.
  • Keys are isolated by project and environment.
  • Within a batch, conflicting uses reject the entire batch atomically.

Property key order does not change the canonical payload, so semantically identical JSON objects remain duplicates.

Errors

Errors use a consistent envelope:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "...",
    "requestId": "req_...",
    "field": "customerId",
    "value": null,
    "reason": "...",
    "fix": "...",
    "docs": "https://docs.usekite.cloud/api#VALIDATION_ERROR"
  }
}

field and diagnostics appear only when relevant. Include requestId when contacting support.

StatusTypical codeMeaning
400VALIDATION_ERROR, MALFORMED_JSON, BATCH_SIZE_INVALIDInvalid request shape, field, timestamp, or batch size.
401INVALID_API_KEYMissing, malformed, unknown, or revoked key.
402PLAN_REQUIREDThe organization cannot use cloud execution.
409IDEMPOTENCY_CONFLICTAn idempotency key was reused with another payload.
422Schema diagnostic codePayload violates a strict active schema.
429RATE_LIMIT_EXCEEDED, MONTHLY_QUOTA_EXCEEDEDPer-key rate limit or monthly quota exceeded.
5xxServer errorTemporary service failure. Retry with backoff.

Retry network errors, 429, and 5xx. Do not retry validation, authentication, or idempotency conflicts without correcting the request.

Rate limits

Rate limiting is applied per API key and each operation in a batch counts as one event. The service returns:

HeaderMeaning
RateLimit-LimitCurrent event allowance for the window.
RateLimit-RemainingRemaining operations.
Retry-AfterSeconds to wait after HTTP 429.
RateLimit-ResetSeconds until capacity is available after HTTP 429.

Limits can vary by deployment and plan; clients should rely on response headers rather than a hard-coded value.

Request IDs

Every response includes X-Request-ID. You may provide your own value:

X-Request-ID: checkout_456_event

Use a non-sensitive correlation ID. Kite returns it in the response header and includes it in structured error bodies.

Administrative API

The /projects/* surface powers the CLI for project creation, API-key management, configuration versions, customer inspection, events, recomputation, diagnostics, webhooks, and AI assistance.

Administrative requests use both headers:

Authorization: Bearer <cli-session>
X-Kite-Organization: org_...

These are user and organization credentials, not project ingestion keys. Roles and billing entitlements are enforced per operation. Prefer kite auth login and CLI commands instead of building directly against this surface while its public contract evolves.

Service health

EndpointAuthenticationMeaning
GET /liveznoneProcess is alive.
GET /startupznoneStartup completed; otherwise returns 503.
GET /readyznoneReady for traffic, including database and worker checks.
GET /healthnoneCompatibility alias for readiness.
GET /metricsinternal tokenDetailed service and queue metrics for operators.

Successful probes return:

{ "status": "ok" }

Webhook delivery

Webhook delivery is at least once. A worker crash after the receiver accepts a request but before Kite records completion can cause the same event to be sent again.

Deduplicate the stable identifier in the kite-event-id header. The same value is available as id in the JSON payload and remains unchanged across retries. A webhook receives only events emitted after that webhook was created.

See Webhooks and signatures for payloads, signatures, retry timing, and verification. See Backfill and recomputation for delayed data and state replay semantics.

On this page