Skip to content

Device Management API

Device announcements create temporary routing mappings that allow servers to deliver messages to devices. Unlike traditional systems, Cryptid servers store no permanent device records; All mappings expire automatically after 24-48 hours.

Devices must periodically re-announce themselves to maintain message delivery. This approach ensures that server compromise reveals minimal metadata, as inactive devices are automatically forgotten.

Cryptid separates device identity from message routing:

Device ID (Permanent)

  • Blake3 hash of Ed25519 public key: device_id = Blake3(public_key)
  • Used for MLS group membership and message signing
  • Cannot be changed without creating a new device
  • Example: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2 (64 hex chars)

Delivery Address (Rotatable)

  • UUIDv4 prefix + server domain: {uuid_v4}@{server}
  • Generated by the server during device announcement
  • Used only for routing messages to devices
  • Can be rotated freely for privacy without affecting group membership
  • Example: a1b2c3d4-e5f6-4728-9394-a5b6c7d8e9f1@chat.example.com

When announcing a device:

  1. Device sends its permanent device_id (for authentication)
  2. Server generates a new UUIDv4 delivery address prefix
  3. Server maps the delivery address to the device ID internally for 24 hours

Creates a temporary delivery mapping and issues a JWT access token. The server generates a unique delivery address for routing and performs only basic timestamp validation. Signature verification is the recipient’s responsibility, maintaining the minimal-trust model.

POST /v1/announce
POST /v1/announce HTTP/1.1
Content-Type: application/json
{
"device_id": "6df9a6cbb41be1bf4575ce6a57886d1aa3e57e65ba9de29bc5810fadba40a6ea",
"announcement_signature": "ed25519_signature_over_device_id_and_timestamp",
"timestamp": 1759695461,
"storage_preferences": {
"max_retention_days": 30,
"offline_message_limit": 1000
}
}

Parameters:

  • device_id: Blake3 hash of device’s Ed25519 public key (32 bytes, 64 hex characters)

  • announcement_signature: Ed25519 signature over device_id and timestamp

  • timestamp: Unix timestamp (prevents replay attacks)

  • storage_preferences: Optional message storage settings

{
"assigned_address": "2eafc575-6217-4338-96b8-f71a52c22f6a@chat.example.com",
"access_token": "jwt_access_token",
"expires_at": 1759695599,
"server_capabilities": {
"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..."
},
"next_announcement_required": 1759696000
}

Response Fields:

  • assigned_address: The server-generated delivery address (UUIDv4 prefix + server domain)

  • access_token: JWT Bearer token for authenticated endpoints (expires with mapping)

  • expires_at: Unix timestamp when the delivery mapping expires

  • server_capabilities: Server limits and features for client configuration

  • next_announcement_required: Recommended time for next keepalive announcement

Extends the delivery mapping expiration. Devices should call this endpoint before their current mapping expires (typically every 20-24 hours) to ensure continuous message delivery. This is a lightweight keepalive that doesn’t require re-uploading storage preferences.

The device must provide its currently assigned delivery address to extend the mapping.

PUT /v1/announce
PUT /v1/announce HTTP/1.1
Authorization: Bearer {access_token}
Content-Type: application/json
{
"device_id": "6df9a6cbb41be1bf4575ce6a57886d1aa3e57e65ba9de29bc5810fadba40a6ea",
"announcement_signature": "ed25519_signature_over_device_id_and_timestamp",
"timestamp": 1759696179
}
{
"expires_at": 1759697179,
"next_announcement_required": 1759699999
}

Explicitly removes the device from the server’s routing table. While mappings expire automatically, explicit deregistration ensures immediate cleanup and prevents queuing messages for devices that are intentionally going offline.

DELETE /v1/announce
DELETE /v1/announce HTTP/1.1
Authorization: Bearer {access_token}
Content-Type: application/json
{
"device_id": "6df9a6cbb41be1bf4575ce6a57886d1aa3e57e65ba9de29bc5810fadba40a6ea",
"deregistration_signature": "ed25519_signature_over_device_id_and_timestamp",
"timestamp": 1759699999
}
{
"status": "deregistered"
}

The server validates that signatures are properly formatted but does not verify their cryptographic correctness. Recipients must verify signatures themselves using the sender’s public key. This prevents the server from making trust decisions.

All device mappings expire after 24 hours by default. Queued messages expire according to max_retention_days (default: 30 days). No manual cleanup is required.

Each time a device announces itself (POST /v1/announce), the server generates a fresh delivery address.

To rotate addresses for privacy:

  1. Wait for current mapping to expire naturally, OR
  2. Call DELETE /v1/announce to deregister
  3. Call POST /v1/announce to get a new delivery address

The device ID remains constant across all address rotations.

Device announcements are limited to 24 per hour per address. This allows for legitimate network reconnections while preventing announcement spam.

  1. Device generates Ed25519 keypair locally.

  2. Device derives device ID: device_id = Blake3(public_key).

  3. POST /v1/announce with device_id -> Server assigns delivery address and returns JWT token.

  4. Device stores assigned_delivery_address for future announcements.

  5. Uses access_token for all subsequent API calls.

  6. PUT /v1/announce every 20 hours with current_delivery_address (keepalive).

  7. DELETE /v1/announce with current_delivery_address when going offline (optional).

  8. POST /v1/announce again to get a new delivery address (rotates for privacy).