For organizations
What it's like to actually use fxe as a sending or receiving organization — from the first invite through day-to-day sends, receipts, and key recovery.
Joining a relay
You can't sign up for a relay yourself — it's invite-only. A relay operator hands you a single-use invite token, out of band (encrypted email, Signal, etc.).
- Open the relay's
/redeempage in a browser, or runfxe-client redeemon a workstation you trust. - Choose your organization's display name and which fax numbers it controls. Enter the admin email — that's the first person who can sign into the dashboard.
- Click Generate keys & redeem. Your browser (or the CLI) creates the org's identity, signing, and encryption keys locally. Nothing secret is uploaded — only public keys and signatures.
- Download
keys.zipand store it somewhere safe. It contains the private keys and the API key. The relay cannot regenerate these. - Click Set up passkey for admin login. You'll register a passkey on your device — that's how you'll sign in to the dashboard from now on.
What you hold afterwards
After redemption you have two related but distinct credentials:
A passkey
For humans signing in to the web UI. Lives on your phone, laptop, or hardware key. Each org admin enrolls their own.
A key bundle + API key
For machines: your fax gateway, billing system, or send/receive scripts. Used by the client SDK to encrypt outgoing faxes and decrypt incoming ones.
Sending a fax
- Your sending workstation asks the relay "who currently owns this fax number?"The relay returns the recipient org's public key bundle.
- Locally, the SDK generates a one-time content-encryption key, encrypts the file with it, wraps that key for the recipient's bundle, and signs the whole envelope.
- The signed envelope plus opaque ciphertext is uploaded to the relay, along with caller-ID (
from_numberand optionalfrom_name) and the dialed line (to_number). The relay enforces thatfrom_numberbelongs to your org andto_numberbelongs to the recipient org; mismatches are rejected. - The recipient is notified by webhook (preferred) or by polling, picks up the message, decrypts it, and signs a receipt. The relay deletes the ciphertext.
In practice, most orgs hook fxe up to their existing fax software or document workflow — the SDK is just a Python library, and signed-request authentication is straightforward to wire into any HTTP client.
application/pdfon the metadata, and most integrations render or archive them as PDFs on the other side. The relay itself doesn't inspect bodies (it's all ciphertext to the relay), but sending non-PDF content will leave recipients with files their workflow can't use. Convert TIFFs, faxes captured from PSTN, and other formats to PDF before sending.Testing your integration
Send a fax to +10000000000 any time. That number belongs to a built-in echo org: within a few seconds, it sends the same PDF back to you with from_number=+10000000000. Use it to verify your end-to-end send/receive wiring, webhook handling, decryption, and receipts before you coordinate with a real partner.
Coverage and PSTN fallback
fxe only routes between fax numbers that belong to member organizations. When you go to send, the lookup either returns a recipient key bundle (the number is on the network) or doesn't (it isn't).
For numbers that aren't covered, you still need a traditional PSTN fax route. Most integrations work like this:
- Ask the relay for the recipient's key bundle.
- If a bundle comes back, encrypt and send via fxe — no per-minute charges, instant delivery, signed receipt.
- If no bundle is found, fall back to your existing fax carrier. fxe doesn't try to dial PSTN itself — it's a relay between member orgs, not a fax gateway.
Coverage grows as more organizations join. If you regularly fax a specific partner who isn't on fxe yet, ask them to request an invite — the savings compound on high-volume lanes.
Receiving a fax
When a message lands for one of your fax numbers, the relay either:
- Calls your webhook with the message ID. Your code fetches the envelope, decrypts locally, posts a signed receipt, and the relay deletes the ciphertext.
- Waits to be polled. You can list pending messages via the API on whatever schedule you like.
Webhook payloads are signed by the relay and don't include plaintext — they're a "you've got mail" nudge, not the file itself.
Webhooks in practice
Each webhook endpoint you register has a per-endpoint shared secret. The relay POSTs JSON to your URL with these headers:
X-FXE-Timestamp— Unix seconds; reject if more than 5 min skewed.X-FXE-Signature: v1=<hex>— HMAC-SHA256 over"<timestamp>.<body>"using your secret.X-FXE-Event-Id— UUID; use as your idempotency key.X-FXE-Event-Type— see events below.
Events you can subscribe to:
message.received— new ciphertext queued for your org (recipient).message.delivered— recipient submitted a signed receipt (sender).message.expired— pending message hit TTL and was purged (both).org.user.added/org.user.removed— membership changes.bundle.rotated— new key bundle activated for your org.
Any non-2xx response is retried with exponential backoff: 30s, 2m, 10m, 1h, 6h, 24h. After six failures the delivery is marked dead and can be redelivered manually from the dashboard.
Rotating your key bundle
Your encryption bundle (ML-KEM + X25519 + per-bundle Ed25519) can be rotated at any time. You generate fresh keys, sign the new bundle with your identity key, and post it. The relay activates the new bundle and retires the old one. Old bundles are kept indefinitely so messages still in flight that wrapped a CEK to them can still be decrypted.
The identity key itself does not rotate — it's the root of trust. If you believe it's compromised, contact the operator; the org must be re-invited with a new identity.
Limits and what's not protected
- Max ciphertext size: 100 MiB per message. Larger uploads are rejected.
- Compromise of your client = plaintext access. The relay protects data in transit and at rest on its side, but if an attacker has code execution on your sending or receiving machine they can read messages there. Restrict access to
keys.zipand the workstations that hold it. - Metadata isn't private. The relay can see who you're sending to, when, and the ciphertext size. The contents are protected; the social graph isn't.
Managing the org day-to-day
Once you're signed in as an org admin, the dashboard lets you:
- Invite teammates as org admins or org users (they each enroll a passkey).
- Manage fax numbers, webhooks, and API key rotation.
- Browse the message log and a per-org audit trail.
If you lose your keys
There are two failure modes worth planning for:
- Lost passkey — recoverable. Click "Recover" on the login page; if your email is registered, a setup link is sent so you can enroll a new passkey. Existing org admins can also issue setup links from the dashboard.
- Lost
keys.zip— not recoverable from the relay. The org's identity and encryption keys exist only on your machines. If they're gone, the relay operator must invite the org again with a new identity. Treatkeys.ziplike a root CA: back it up, restrict access, and keep at least one offline copy.