Encryption modes

Two deployment modes share one API shape and one envelope on the wire. What changes is who encrypts — the relay (Mode A) or the sender (Mode B).

Mode A: server-assisted (self-hosted default)

  • The sender posts plaintext over HTTPS.
  • The relay encrypts to the device's public key at receipt.
  • The relay reads the contents in memory while delivering; nothing is persisted, and delivery records expire via the janitor.
  • Suited to self-hosted deployments on hardware you control.

Mode B: sender-encrypted (zero-knowledge)

  • The sender encrypts locally to the device's public key before the request (X25519 ephemeral sender key + ChaCha20-Poly1305, protocol v2).
  • The relay validates the envelope's structure and routing fields only: version, message_id, device_id, key_version, sender_key, nonce, ciphertext, created_at, ttl, priority.
  • Prelay Cloud rejects plaintext with 403 zero_knowledge_required; Mode A is a self-hosted default, never a Cloud one.
  • The private half of the device key lives only in the device's Android Keystore.

What the relay sees in Mode B

FieldMode A (server sees)Mode B (plain on the wire)
title, message, actionsyes (encrypts them itself)sealed inside ciphertext
device_id, routingyesyes
priorityyesyes — delivery metadata, not content; it only lifts FCM priority
created_at, ttlyesyes (server-side validation inputs, §8)
key_version, sender_key, noncerelay-generatedyes

What the server enforces in Mode B anyway

The zero-knowledge boundary does not turn the relay into a dumb pipe. It still validates everything it can without reading:

  • message_id must be a canonical lowercase UUIDv7 and unique — the replay-protection anchor (§8); a duplicate gets 409 duplicate_message.
  • created_at must sit inside the server's clock-skew window (PRELAY_CLOCK_SKEW); a ttl above the 604800-second (7-day) maximum is rejected with 400.
  • key_version mismatch gets 409 stale_key, so a key rotation sends the sender back to fetch fresh keys.
  • unknown version/algorithm values get 400.
Mode B senders validate their own contents

The server validates Mode A contents; in Mode B it cannot. So the sender-side rules — message size caps, valid actions (open_url needs an https URL, labels ≤ 24 chars), notification-counting — move to the sender. The device trusts its own keypair, the relay trusts nothing: an out-of-spec Mode B envelope either fails the server's schema checks unsigned, or opens on the phone looking broken.

Which one?

  • Your own hardware: Mode A is fine and simpler.
  • A server you don't fully trust: Mode B. Prelay Cloud always speaks Mode B.

On this page