Server Discovery API
Server discovery enables clients and servers to automatically discover capabilities, configuration, and operational status of Cryptid servers. This follows the .well-known standard (RFC 5785) used by many federated protocols.
Base URL
Section titled “Base URL”All Cryptid API endpoints are relative to the server’s base URL:
https://chat.example.comURL Structure:
-
Protocol:
https://(TLS required, no HTTP) -
Domain: Server’s fully qualified domain name
-
No path prefix (API endpoints start at root)
Example URLs:
-
Device announcement:
https://chat.example.com/v1/announce -
WebSocket stream:
wss://chat.example.com/v1/stream -
Server discovery:
https://chat.example.com/.well-known/cryptid
Server Capabilities
Section titled “Server Capabilities”Discover server capabilities, configuration, and federation parameters. This endpoint is publicly accessible (no authentication required) and is used by:
-
Clients choosing which server to connect to
-
Servers discovering federation capabilities of remote servers
-
Monitoring tools checking server availability
Standard: Follows RFC 5785 (.well-known URI) convention used by protocols like Matrix, Mastodon, and WebFinger.
Endpoint
Section titled “Endpoint”GET /.well-known/cryptidRequest
Section titled “Request”GET /.well-known/cryptid HTTP/1.1Host: server.example.comResponse (200 OK)
Section titled “Response (200 OK)”{ "protocol_version": "1.0", "server_name": "server.example.com", "federation_enabled": true, "supported_features": ["mls_messaging", "websocket_streaming", "offline_queuing"], "rate_limits": { "federated_messages_per_minute": 1000, "announcements_per_hour": 24, "infopackage_uploads_per_hour": 10, "infopackage_uploads_per_day": 50 }, "message_limits": { "max_message_size": 10485760, "max_retention_days": 30 }, "websocket": { "enabled": true, "max_connections_per_device": 1, "max_message_backlog": 1000, "keepalive_interval_seconds": 30, "connection_timeout_seconds": 300 }, "certificate_fingerprint": "blake3:a1b2c3d4e5f6172839..."}Response Fields:
-
protocol_version: Cryptid protocol version this server implements (semantic versioning)- Clients should check compatibility (e.g., reject servers with incompatible major versions)
-
server_name: Server’s canonical domain name (must match DNS)- Used for device address validation (e.g.,
device_id@server_name)
- Used for device address validation (e.g.,
-
federation_enabled: Whether this server accepts federated messages from other serverstrue: Server accepts federation requests at/federation/v1/*false: Server is isolated (no cross-server messaging)
-
supported_features: Array of optional features this server implementsmls_messaging: MLS-encrypted messaging (required)websocket_streaming: Real-time WebSocket deliveryoffline_queuing: Stores messages for offline devices- Future:
relay_network, etc.
-
rate_limits: Server’s rate limiting policiesfederated_messages_per_minute: Max messages/minute in federation requestsannouncements_per_hour: Max device announcements per hour per addressinfopackage_uploads_per_hour: Max InfoPackage uploads per hour per userinfopackage_uploads_per_day: Max InfoPackage uploads per day per user
-
message_limits: Message storage and size constraintsmax_message_size: Maximum message size in bytes (default: 10MB)max_retention_days: How long unacknowledged messages are kept (default: 30 days)
-
websocket: WebSocket streaming configuration (ifwebsocket_streamingfeature is supported)enabled: Whether WebSocket streaming is availablemax_connections_per_device: Maximum concurrent WebSocket connections per device (typically 1)max_message_backlog: Maximum queued messages delivered on connection (typically 1000)keepalive_interval_seconds: Recommended ping interval in seconds (typically 30)connection_timeout_seconds: Maximum idle time before connection is closed (typically 300)
-
certificate_fingerprint: Blake3 fingerprint of server’s TLS certificate- Used for certificate pinning and trust-on-first-use (TOFU)
- Format:
blake3: prefix + lowercase hex (64 characters)
Use Cases
Section titled “Use Cases”Client Server Selection
Section titled “Client Server Selection”async fn choose_server(candidates: Vec<String>) -> Result<String> { for domain in candidates { let caps = discover_server(&domain).await?;
// Check requirements if caps.protocol_version.starts_with("1.") && caps.supported_features.contains(&"websocket_streaming".to_string()) { return Ok(domain); } }
Err(anyhow!("No compatible server found"))}Federation Compatibility Check
Section titled “Federation Compatibility Check”async fn can_federate_with(domain: &str) -> Result<bool> { let caps = discover_server(domain).await?;
if !caps.federation_enabled { return Ok(false); }
// Check protocol version compatibility if caps.protocol_version.starts_with("1.") { return Ok(true); }
Ok(false)}Certificate Pinning
Section titled “Certificate Pinning”async fn verify_server_certificate(domain: &str, observed_fingerprint: &str) -> Result<()> { let caps = discover_server(domain).await?;
if caps.certificate_fingerprint != observed_fingerprint { return Err(anyhow!("Certificate fingerprint mismatch! Possible MITM attack!")); }
Ok(())}Error Responses
Section titled “Error Responses”404 Not Found
Section titled “404 Not Found”Server does not implement Cryptid or has disabled discovery.
{ "error": "ENDPOINT_NOT_FOUND", "message": "Server does not support Cryptid protocol"}503 Service Unavailable
Section titled “503 Service Unavailable”Server is operational but is temporarily not accepting new connections.
{ "error": "SERVER_UNAVAILABLE", "message": "Server temporarily unavailable"}Health Check
Section titled “Health Check”Check server operational status and uptime. Used by monitoring tools, load balancers, and administrators.
Use Cases:
-
Load balancer health checks
-
Monitoring/alerting systems
-
Admin dashboards
-
Client fallback logic (try different server if unhealthy)
Endpoint
Section titled “Endpoint”GET /v1/healthRequest
Section titled “Request”GET /v1/health HTTP/1.1Response (200 OK)
Section titled “Response (200 OK)”{ "status": "healthy", "timestamp": 1759000000, "version": "1.0.0", "uptime": 2592000}Response Fields:
-
status: Server health statushealthy: Server fully operationaldegraded: Server operational but experiencing issues (e.g., high load, partial service)unhealthy: Server experiencing critical issues (still responding but unreliable)
-
timestamp: Current server Unix timestamp- Used for client clock synchronization validation
-
version: Server software version (semantic versioning)- Format:
major.minor.patch(e.g.,1.2.3) - Useful for debugging and compatibility tracking
- Format:
-
uptime: Server uptime in seconds since last restart- Example:
2592000= 30 days
- Example:
Response Status Codes
Section titled “Response Status Codes”200 OK: Server is healthy and operational
503 Service Unavailable: Server is unhealthy or under maintenance
{ "status": "unhealthy", "timestamp": 1759000000, "version": "1.0.0", "uptime": 3600, "details": "Database connection failed"}Load balancers should remove servers from rotation upon a 503.
Important Notes
Section titled “Important Notes”Caching Server Capabilities
Section titled “Caching Server Capabilities”Server capabilities change infrequently and should be cached.
struct ServerCapabilitiesCache { cache: HashMap<String, (ServerCapabilities, Instant)>, ttl: Duration,}
impl ServerCapabilitiesCache { async fn get(&mut self, domain: &str) -> Result<ServerCapabilities> { if let Some((caps, cached_at)) = self.cache.get(domain) { if cached_at.elapsed() < self.ttl { return Ok(caps.clone()); } }
// Cache miss or expired, fetch new let caps = discover_server(domain).await?; self.cache.insert(domain.to_string(), (caps.clone(), Instant::now()));
Ok(caps) }}Recommended TTL: 1h for server capabilities, 30s for health checks.
DNS and HTTPS Requirements
Section titled “DNS and HTTPS Requirements”Cryptid servers MUST:
-
Have valid DNS records pointing to their domain
-
Use TLS 1.3+ with valid certificates (no self-signed in production)
-
Serve
.well-known/cryptidover HTTPS (no HTTP fallback)
This prevents:
-
DNS spoofing attacks
-
Man-in-the-middle attacks
-
Impersonation of legitimate servers
Certificate Fingerprint Validation
Section titled “Certificate Fingerprint Validation”The certificate_fingerprint field enables Trust on First Use (TOFU):
-
Client connects to server for first time
-
Client records certificate fingerprint from
.well-known/cryptid -
On subsequent connections, client verifies fingerprint hasn’t changed
-
If changed, client alerts user (possible MITM or legitimate rotation)
Why Blake3?
- Faster computation on mobile devices
- Same 256-bit security as SHA-256
- Consistent with Cryptid’s use of Blake3 for all hashing operations
Calculating fingerprint:
use blake3;
fn calculate_fingerprint(cert_der: &[u8]) -> String { let hash = blake3::hash(cert_der); format!("blake3:{}", hex::encode(hash.as_bytes()))}Rate Limit Discovery
Section titled “Rate Limit Discovery”Clients SHOULD respect advertised rate limits from server capabilities.