Server SDKs: quickstart
Everything below uses your secret write key (project settings → API keys). Keep it in an environment variable; it must never ship to a browser.
Install
Section titled “Install”composer require kilden/kilden-phpnpm install @kilden-io/nodepip install kildengem install kilden --prego get go.kilden.io/sdk# No install — the HTTP API is documented at /api/captureFirst event
Section titled “First event”$kilden = new Kilden\Client(getenv('KILDEN_SECRET_KEY'));
$kilden->track('user_42', 'order_completed', [ 'revenue' => 99.9, 'currency' => 'CLP',]);import { Client } from "@kilden-io/node";
const kilden = new Client(process.env.KILDEN_SECRET_KEY!);
kilden.track("user_42", "order_completed", { revenue: 99.9, currency: "CLP" });from kilden import Client
kilden = Client(os.environ["KILDEN_SECRET_KEY"])kilden.track("user_42", "order_completed", {"revenue": 99.9, "currency": "CLP"})require "kilden"
kilden = Kilden::Client.new(ENV["KILDEN_SECRET_KEY"])kilden.track("user_42", "order_completed", { "revenue" => 99.9, "currency" => "CLP" })client, err := kilden.New(os.Getenv("KILDEN_SECRET_KEY"))if err != nil { log.Fatal(err)}defer client.Close()
client.Track("user_42", "order_completed", map[string]any{ "revenue": 99.9, "currency": "CLP",})curl -X POST https://ingest.kilden.io/capture \ -H 'Content-Type: application/json' \ -d '{ "write_key": "'$KILDEN_SECRET_KEY'", "sent_at": "2026-07-14T12:00:00.500Z", "batch": [{ "uuid": "0197fa10-7a2b-7c3d-8e4f-5a6b7c8d9e0f", "event": "order_completed", "distinct_id": "user_42", "properties": {"revenue": 99.9, "currency": "CLP"}, "timestamp": "2026-07-14T12:00:00.000Z" }] }'Events are queued in memory and sent in batches. Call close() when your
process shuts down (Laravel, FPM and the shutdown hooks handle this for you
in PHP; in Go use defer client.Close()); anything still queued past a
10-second deadline is dropped rather than hanging your process.
Identify
Section titled “Identify”identify upserts person traits. The distinct_id is explicit on every
call — server SDKs hold no identity state.
# identify is a $identify event whose traits travel under properties.$setcurl -X POST https://ingest.kilden.io/capture \ -H 'Content-Type: application/json' \ -d '{ "write_key": "'$KILDEN_SECRET_KEY'", "sent_at": "2026-07-14T12:00:00.500Z", "batch": [{ "uuid": "0197fa10-7a2b-7c3d-8e4f-5a6b7c8d9e10", "event": "$identify", "distinct_id": "user_42", "properties": {"$set": {"plan": "pro", "email": "[email protected]"}}, "timestamp": "2026-07-14T12:00:00.000Z" }] }'Sign identity tokens
Section titled “Sign identity tokens”Identity verification needs your backend
to sign a short-lived JWT for the logged-in user. IdentitySigner does it
without a JWT library — and your endpoint is three lines. Only ever sign
an id your backend authenticated: signing a user id taken from request
input lets anyone impersonate anyone, with a “verified” seal on top.
$signer = new Kilden\IdentitySigner(getenv('KILDEN_IDENTITY_SECRET'), ['kid' => 'k1']);
$token = $signer->sign($user->id, [ 'traits' => ['plan' => $user->plan],]);Using Laravel? kilden/laravel ships a publishable POST /kilden/identity
route behind your auth middleware — no code at all.
import { IdentitySigner } from "@kilden-io/node";
const signer = new IdentitySigner(process.env.KILDEN_IDENTITY_SECRET!, { kid: "k1" });
app.post("/kilden/identity", (req, res) => { const user = req.user; res.json({ distinct_id: String(user.id), token: signer.sign(String(user.id), { traits: { plan: user.plan } }), });});from kilden import IdentitySigner
signer = IdentitySigner(os.environ["KILDEN_IDENTITY_SECRET"], kid="k1")
@app.route("/kilden/identity", methods=["POST"])@login_requireddef kilden_identity(): token = signer.sign(current_user.id, traits={"plan": current_user.plan}) return {"distinct_id": current_user.id, "token": token}signer = Kilden::IdentitySigner.new(ENV["KILDEN_IDENTITY_SECRET"], kid: "k1")
token = signer.sign(current_user.id.to_s, traits: { "plan" => current_user.plan })signer, err := kilden.NewIdentitySigner(os.Getenv("KILDEN_IDENTITY_SECRET"), "k1")if err != nil { log.Fatal(err)}
token, err := signer.Sign(userID, kilden.WithTraits(map[string]any{"plan": plan}))# There is no curl shortcut for signing — the token is an HS256 JWT your# backend must produce. Use a server SDK, or see the identity verification# guide for the exact claim set and canonical form.The WordPress plugin exposes the same thing at
/wp-json/kilden/v1/identity, cache-safe by construction.
Feature flags
Section titled “Feature flags”isEnabled(flag_key, distinct_id, { person_properties?, default? })getFeatureFlag(flag_key, distinct_id, { person_properties?, default? })Evaluated by Kilden server-side, cached in-process for 30 seconds per
distinct_id, one attempt with a hard timeout, then your default. Full
semantics in the feature flags guide.
Where to next
Section titled “Where to next”- Identity verification — the trust model these tokens plug into.
- HTTP API: capture — the wire format underneath.
- The spec repo — the contracts all five SDKs are tested against.