kite~/kite/docs/Emitting Events
v0.2.2
Guide

Emitting Events

Send structured events from your own application into Kite with the TypeScript or Rust SDK, then watch them arrive in the CLI and agent sessions.

Kite isn't only for third-party webhooks like GitHub or Stripe. Your own application can be a source too. The Kite SDK lets you emit structured events straight from your code:

code
your app ──(SDK)──▶ api.getkite.sh ──▶ kite stream / kite proxy / agents

Events you emit flow through the same ingest pipeline as provider webhooks and arrive as CloudEvents in kite stream, kite proxy, and agent sessions — so you can react to a user signup, a background job finishing, or any domain event the same way you react to a webhook.

// 01Prerequisites

  • Kite installed and authenticated (kite login)
  • A team id (visible in the dashboard or kite status)

// 02Step 1 — Create an endpoint and hook token

Create a custom source for your application and mint a hook token:

bash
kite endpoints create --source my-app

Kite prints a hook token. Store it as a secret (for example KITE_HOOK_TOKEN) — the SDK uses it to authenticate each emit. The source slug (my-app here) must be lowercase alphanumeric plus hyphens, start with an alphanumeric, be at most 64 characters, and cannot be kite.

// 03Step 2 — Install the SDK

TypeScript

bash
npm install @getkite/sdk
# or: pnpm add @getkite/sdk  /  bun add @getkite/sdk

Rust

bash
cargo add kite-sdk

// 04Step 3 — Emit an event

Build and send a CloudEvent with a custom type and payload.

TypeScript

ts
import { Kite } from "@getkite/sdk";

const kite = new Kite({
  teamId: "your-team",
  source: "my-app",
  token: process.env.KITE_HOOK_TOKEN!,
});

await kite.emit(
  "com.myapp.user.signup",
  { userId: "u_123", plan: "pro" },
  { summary: "User u_123 signed up (pro)" },
);

Rust

rust
use kite_sdk::Kite;
use serde_json::json;

let kite = Kite::builder()
    .team_id("your-team")
    .source("my-app")
    .token(std::env::var("KITE_HOOK_TOKEN")?)
    .build()?;

kite.emit("com.myapp.user.signup", json!({ "userId": "u_123", "plan": "pro" }))
    .summary("User u_123 signed up (pro)")
    .send()
    .await?;

The SDK posts the event with Content-Type: application/cloudevents+json and authenticates with the hook token (a Bearer header by default).

// 05Step 4 — Watch it arrive

In another terminal, stream your source:

bash
kite stream --source my-app

Trigger the code path that emits, and you'll see the event:

code
[com.myapp.user.signup] User u_123 signed up (pro)

Proxy it to a local handler instead:

bash
kite proxy --source my-app --target http://localhost:3000/events

// 06Custom types, summaries, and subjects

The event type is a reverse-DNS string you choose — com.myapp.user.signup, com.myapp.job.completed, and so on. It's what you filter on downstream:

bash
kite stream --source my-app --event-type com.myapp.user.signup

Two optional fields make events easier to read and route:

  • summary — a human-readable one-liner stored on the kitesummary extension. It's what kite stream prints and what agent sessions surface. Kite preserves the summary you supply (trimmed, and capped at 500 characters); if you omit it, Kite derives a generic one.
  • subject — the CloudEvents subject, useful for the specific entity the event is about (an order id, a user id).

TypeScript

ts
await kite.emit(
  "com.myapp.order.paid",
  { orderId: "o_42", amount: 4999 },
  { summary: "Order o_42 paid ($49.99)", subject: "o_42" },
);

Rust

rust
kite.emit("com.myapp.order.paid", json!({ "orderId": "o_42", "amount": 4999 }))
    .summary("Order o_42 paid ($49.99)")
    .subject("o_42")
    .send()
    .await?;

// 07Plain-JSON fallback

If you'd rather not think about CloudEvents, send raw JSON and let Kite wrap it. The server derives the type com.{source}.event and a https://{source} source URI.

TypeScript

ts
await kite.emitRaw({ hello: "world" });
// arrives as type "com.my-app.event"

Rust

rust
kite.emit_raw(json!({ "hello": "world" })).await?;

// 08Limits and delivery semantics

  • Payload size — a serialized event is capped at 256 KB. The SDK checks this before sending and the server enforces it (HTTP 413).
  • Rate limits — ingest is rate limited per team. On HTTP 429 the SDK retries with backoff, honoring the server's retry_after_secs when present.
  • At-least-once delivery — Kite aims to deliver each event to your listeners at least once. Design consumers to be idempotent (for example, key off the event id or your own subject) so a redelivery is harmless.

For the full configuration and error surface, see the SDK reference. Source code lives at github.com/Alpha-Centauri-Cyberspace/kite-sdk.