Federation Protocol Specification

Complete technical specification of the TapsIM Federation Protocol

Protocol Overview

The TapsIM Federation Protocol enables secure, real-time communication between independent Taps.IM servers using HTTP/2 streaming with NDJSON frame encoding. The protocol implements zero-knowledge message relay, ensuring servers cannot decrypt content while maintaining message integrity and ordering.

🌊

HTTP/2 Streaming

Long-lived bidirectional streams with h2c cleartext support for efficient frame exchange

📋

NDJSON Frames

Newline-delimited JSON with ULID identifiers and monotonic sequence numbers

🔄

Flow Control

CREDIT-based backpressure with configurable event and byte budgets

Transport Layer

HTTP/2 Requirements

type ServerConfig struct {
ListenAddr string
ReadTimeout time.Duration
WriteTimeout time.Duration
IdleTimeout time.Duration
H2CEnabled bool
}

✅ Required Features

  • HTTP/2 cleartext (h2c) for development
  • TLS 1.3 support for production
  • Long-lived streams with keepalive
  • Bidirectional communication

⚙️ Configuration

  • Max frame size: 16KB default
  • Connection timeout: 30s
  • Keepalive interval: 30s PING
  • Max concurrent streams: 100

Media Type Negotiation

📝 Content-Type Header

All federation endpoints must negotiate the correct media type for frame exchange:

Content-Type: application/x-ndjson; profile="_taps.v1.frames"

Frame Specification

Base Frame Structure

{
"type": "HELLO",
"id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
"origin": "server-alice",
"sequence": 1,
"group_id": "g!example",
"payload": {...}
}

📋 Required Fields

  • type - Frame type (enum)
  • id - ULID identifier
  • origin - Server identifier
  • sequence - Monotonic counter

🔍 Optional Fields

  • group_id - Target group (group frames only)
  • timestamp - UTC timestamp
  • payload - Frame-specific data

Frame Types

1. HELLO Frame

Establishes federation connection and exchanges server capabilities. Must be the first frame sent in any stream.

{
"type": "HELLO",
"id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
"origin": "server-alice",
"sequence": 1,
"payload": {
"server_id": "server-alice",
"version": "1.0.0-p9",
"capabilities": ["streaming", "backpressure", "keepalive"],
"supported_groups": ["*"],
"max_message_size": 1048576
}
}

🔧 HELLO Payload Fields

  • server_id - Unique server identifier
  • version - Protocol version (semantic versioning)
  • capabilities - Array of supported features
  • supported_groups - Group patterns or "*" for all
  • max_message_size - Maximum event size in bytes

2. CREDIT Frame

Implements flow control by granting the remote peer permission to send events. Essential for backpressure management.

{
"type": "CREDIT",
"id": "01ARZ3NDEKTSV4RRFFQ69G5FAW",
"origin": "server-bob",
"sequence": 2,
"payload": {
"events": 1000,
"bytes": 1048576,
"expires_at": "2025-08-21T23:50:00Z"
}
}

💳 Credit Management

  • Event credits: Number of EVENT frames allowed
  • Byte budget: Total payload bytes permitted
  • Expiration: Credits expire after timeout
  • Automatic renewal: Credits replenished periodically

3. EVENT Frame

Carries encrypted message content between federated servers. Content is treated as opaque ciphertext.

{
"type": "EVENT",
"id": "01ARZ3NDEKTSV4RRFFQ69G5FAX",
"origin": "server-alice",
"sequence": 3,
"group_id": "g!example",
"payload": {
"event_id": "01ARZ3NDEKTSV4RRFFQ69G5FAY",
"event_type": "m.room.message",
"sender": "alice",
"content": "base64-encoded-ciphertext",
"content_hash": "sha256-hash",
"signature": "ed25519-signature",
"depth": 42,
"prev_events": ["previous-event-id"]
}
}

🔒 Zero-Knowledge Handling

  • content field contains opaque ciphertext (base64-encoded)
  • • Servers CANNOT and MUST NOT decrypt content
  • content_hash provides integrity verification
  • signature provides authenticity without revealing content

4. ACK Frame

Acknowledges successful receipt and processing of EVENT frames. Enables reliable delivery guarantees.

{
"type": "ACK",
"id": "01ARZ3NDEKTSV4RRFFQ69G5FAZ",
"origin": "server-bob",
"sequence": 4,
"group_id": "g!example",
"payload": {
"acked_events": [
"01ARZ3NDEKTSV4RRFFQ69G5FAY"
],
"up_to_sequence": 3,
"processing_time_ms": 15
}
}

5. PING/PONG Frames

Implements keepalive mechanism to maintain stream connections and detect failures.

PING Frame

{
"type": "PING",
"id": "ping-ulid",
"origin": "server-alice",
"sequence": 5,
"payload": {
"timestamp": "2025-08-21T23:47:00Z"
}
}

PONG Frame

{
"type": "PONG",
"id": "pong-ulid",
"origin": "server-bob",
"sequence": 6,
"payload": {
"ping_id": "ping-ulid",
"rtt_ms": 25
}
}

Federation Endpoints

GET /_taps/federation/caps

Returns server capabilities and supported protocol versions. Used for capability negotiation.

Request

GET /_taps/federation/caps HTTP/2
Accept: application/json
X-Federation-Origin: server-alice

Response

{
"version": "1.0.0-p9",
"server_id": "server-bob",
"capabilities": [
"streaming", "backpressure",
"keepalive", "anti-entropy"
]
}

GET /_taps/federation/keys/current

Returns the server's current federation signing key for message verification.

{
"key_id": "server-bob-key-a1b2c3d4",
"public_key": "ed25519-public-key-base64",
"algorithm": "ed25519",
"valid_from": "2025-08-21T00:00:00Z",
"valid_to": "2025-08-22T00:00:00Z"
}

POST /_taps/federation/encrypted-groups/{groupId}/stream

Establishes bidirectional streaming connection for real-time frame exchange within a specific group.

🌊 Streaming Protocol

  1. 1. Connection: Client establishes HTTP/2 stream with POST request
  2. 2. Handshake: Both peers exchange HELLO frames with capabilities
  3. 3. Credit Grant: Peers exchange CREDIT frames to enable flow control
  4. 4. Message Flow: EVENT frames flow bidirectionally within credit limits
  5. 5. Acknowledgment: ACK frames confirm successful processing
  6. 6. Keepalive: PING/PONG frames maintain connection health
POST /_taps/federation/encrypted-groups/g!example/stream HTTP/2
Content-Type: application/x-ndjson; profile="_taps.v1.frames"
X-Federation-Origin: server-alice
X-Stream-Version: 1.0

POST /_taps/federation/encrypted-groups/{groupId}/send

One-shot endpoint for sending single events without establishing a persistent stream.

⚡ Use Cases

  • • Low-frequency messaging where streaming overhead isn't justified
  • • One-off notifications or alerts
  • • Testing and debugging federation connectivity
  • • Batch processing scenarios

Anti-Entropy Mechanisms

State Synchronization

Federation servers implement anti-entropy mechanisms to detect and repair inconsistencies in distributed state, ensuring eventual consistency across the network.

GET /_taps/federation/encrypted-groups/{groupId}/digest

Returns a cryptographic digest of the group's current state for comparison with peers.

{
"group_id": "g!example",
"state_hash": "sha256-hash-of-sorted-events",
"event_count": 42,
"latest_event": "01ARZ3NDEKTSV4RRFFQ69G5FAY",
"vector_clock": {
"server-alice": 25,
"server-bob": 17
},
"timestamp": "2025-08-21T23:47:00Z"
}

POST /_taps/federation/encrypted-groups/{groupId}/checkpoint

Exchanges checkpoint data to repair detected inconsistencies between peer states.

🔄 Repair Process
  1. 1. Detection: Digest comparison reveals state mismatch
  2. 2. Request: Peer requests checkpoint data for missing events
  3. 3. Response: Server provides event data and Merkle proofs
  4. 4. Verification: Receiving peer verifies event authenticity
  5. 5. Integration: Missing events integrated into local state

Error Handling

HTTP Status Codes

✅ Success Codes

  • 200 OK: Request successful
  • 201 Created: Resource created
  • 204 No Content: Successful, no response body

❌ Error Codes

  • 400 Bad Request: Invalid frame format
  • 401 Unauthorized: Invalid credentials
  • 403 Forbidden: Insufficient permissions
  • 404 Not Found: Group does not exist
  • 413 Payload Too Large: Frame exceeds size limit
  • 429 Too Many Requests: Rate limit exceeded
  • 500 Internal Server Error: Server error

NACK Frame (Error Response)

Used to signal errors in frame processing and provide debugging information.

{
"type": "NACK",
"id": "01ARZ3NDEKTSV4RRFFQ69G5FB0",
"origin": "server-bob",
"sequence": 7,
"payload": {
"error_code": "INVALID_SIGNATURE",
"error_message": "Event signature verification failed",
"failed_frame_id": "01ARZ3NDEKTSV4RRFFQ69G5FAY",
"retry_after_ms": 1000
}
}

Implementation Guidelines

🔧 Best Practices

  • ULID Generation: Use monotonic ULIDs for frame ordering
  • Sequence Numbers: Maintain per-stream monotonic counters
  • Frame Size Limits: Enforce maximum 16KB frame size
  • Timeout Handling: Implement graceful timeout and retry logic
  • Connection Pooling: Reuse HTTP/2 connections where possible

⚠️ Security Considerations

  • Content Opacity: Never attempt to decrypt EVENT content
  • Signature Verification: Always verify Ed25519 signatures
  • Rate Limiting: Implement adaptive rate limiting
  • Input Validation: Validate all incoming frame data
  • TLS in Production: Always use TLS 1.3 in production

Related Documentation