guides / federation
Getting Started with Federation
Connect two Kite instances so events flow between them automatically. This guide walks through peer registration, token exchange, scope configuration, and verifying your first federated event.
Prerequisites
- →Two running Kite server instances (self-hosted or cloud) — call them Instance A and Instance B
- →Admin API access on both instances
- →Both instances reachable over HTTPS (TLS required for federation)
- →Kite server v0.2.0+ on both instances (federation shipped in v0.2.0)
01 Generate federation tokens
Each side of the peer relationship needs two tokens: one it will send (outbound) and one it will accept (inbound). Generate these on each instance before registering.
On Instance A — generate outbound token
curl -s -X POST https://a.kite.example.com/api/federation/tokens \
-H "Authorization: Bearer $KITE_A_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"label": "peer-b-outbound"}' | jq .tokenSave this as $TOKEN_A_TO_B
On Instance B — generate inbound token (what A will send)
curl -s -X POST https://b.kite.example.com/api/federation/tokens \
-H "Authorization: Bearer $KITE_B_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"label": "peer-a-inbound"}' | jq .tokenSave this as $TOKEN_B_INBOUND
02 Register Instance B as a peer of Instance A
Register B on A's peer registry. This tells Instance A where to forward events and how to authenticate when posting to B.
curl -s -X POST https://a.kite.example.com/api/federation/peers \
-H "Authorization: Bearer $KITE_A_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "instance-b",
"peer_hook_url": "https://b.kite.example.com/hooks/{your_team_id}/kite",
"outbound_token": "'$TOKEN_A_TO_B'",
"inbound_token": "'$TOKEN_B_INBOUND'",
"scopes": ["stripe.*", "com.kite.agent.message"],
"max_hops": 3
}'Key fields:
peer_hook_urlB's inbound endpoint — the URL A will POST federated events tooutbound_tokenToken A sends in the HMAC header when posting to Binbound_tokenToken A expects B to use when posting back to A (for bidirectional)scopesGlob patterns — only matching event types are forwarded
03 Configure Instance B to accept events from A
Instance B needs to know that Instance A is a trusted federation sender. Register A as a trusted source on B:
curl -s -X POST https://b.kite.example.com/api/federation/trusted-senders \
-H "Authorization: Bearer $KITE_B_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "instance-a",
"inbound_token": "'$TOKEN_B_INBOUND'"
}'This tells B to accept events carrying this HMAC signature — and only this signature. Events from unknown senders are rejected with a 401.
04 Verify federation is working
Send a test event to Instance A and verify it arrives at Instance B.
On Instance B — start listening
# On a machine with access to Instance B kite listen --instance https://b.kite.example.com --source kite
Trigger a Stripe test event on Instance A
# Send a test event directly to Instance A's hook endpoint
curl -s -X POST https://a.kite.example.com/hooks/{your_team_id}/stripe \
-H "Content-Type: application/json" \
-d '{"type": "payment_intent.succeeded", "data": {"object": {"id": "pi_test"}}}'Within seconds, you should see the event arrive on Instance B's listener with the federation extensions populated: kitefedorigin: "instance-a", kitefedhops: 1.
Dead-letter replay
If Instance B is temporarily unreachable, events queue in Instance A's outbox with exponential backoff (1s → 2s → 4s → ... max 5 min). After 10 failed attempts the entry is marked dead.
To replay dead-letter events to a specific peer:
curl -s -X POST https://a.kite.example.com/api/federation/peers/{peer_id}/replay-dead \
-H "Authorization: Bearer $KITE_A_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"limit": 100}'This re-queues up to limit dead entries for immediate retry. Check delivery status with the outbox endpoint — see the Federation API reference.