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 .token

Save 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 .token

Save 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 to
  • outbound_tokenToken A sends in the HMAC header when posting to B
  • inbound_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.

Next steps