Parlane

Relay self-hosting

Direct connections need no relay at all: your server talks straight to the app over HTTPS, your LAN, or a tailnet. The relay is optional plumbing for push notifications. Your HTTP/MCP server still needs to be reachable from the phone. Leave push off and direct connections still work.

Your serverany language, any hostdirect, by defaultHTTPS / LAN / tailnetParlaneon your phoneRelay (optional, self-hostable)E2E-encrypted routing, no model or chat contentopen source, AGPL-3.0our thin APNs / FCM gatewaypush trigger only, content-opaque

Turning on push

Push is off until you ask for it, and asking is one line. To enable push notifications you must declare surfaces.push.relay: true in your manifest. Without it there is no push. That one flag wires the app to the Parlane-operated hosted relay automatically. The hosted relay is the default and stays invisible to you: you do not configure a relay URL. Only set surfaces.push.relayUrl in the rare case you are overriding the host. You never supply Apple credentials.

The simplest way to pair the relay is at connect time, in a single scan. Your server pre-mints a pairing token (POST /pair/prepare) and adds it, with the relay URL, to the connect QR as extra relay and pair params; scanning that one QR both connects the app and pairs the relay, with no Settings trip and no code to read across. This is the recommended setup for push. If your server doesn't pair at connect time, the app falls back to manual pairing in Settings (the handshake below). It still works; it isn't as smooth.

What the app uses today

The iOS app uses the hosted relay for pairing and push. Chat, dashboards, voice and actions connect directly to your HTTP/MCP server, which must be reachable from the phone. Push does not require a WebSocket connection.

The reference relay also has a WebSocket transport and offline envelope queue for custom clients. The current iOS app does not consume that tunnel or queue; pairing with the relay does not make a private backend reachable. The hosted App Runner service is an HTTP push service; its deployment does not provide the reference WebSocket tunnel.

How pairing works (the manual handshake)

This is the fallback path the one-scan connect flow above automates for you; read it to understand what happens under the hood, or to run pairing from Settings when a connect QR didn't carry the relay.

Pairing links one app to one server through the relay, and it takes three calls. The app starts it by registering its public key and getting a short single-use code (POST /pair/start). Your server claims that code with its own public key (POST /pair) and gets back a server id and a transport-auth secret. The app polls until the claim lands (GET /pair/status) and receives its own secret plus your server's public key. From that point each side derives the encryption keys on its own. The relay stores public keys, routing ids and transport-auth secrets; it does not receive the private content-encryption keys. There is no code to paste into the relay's config.

After pairing, the app registers its push token. Your server callsPOST /notify with the sealed payload and a small visible hint (title and body) for the banner. Every 200 response has the same shape:delivered, deviceCount, andtransport are always present, and a note field appears only when deviceCount is 0. Zero eligible devices usually means notifications are off or the installation needs registering again. Push is included with Free in the next release. The note says so in user-ready words, so relay it to your user instead of reporting a failure. The full request and response shapes are in the integration kit (the relay section) and in the relay README.

What the relay sees

Sealed envelopes use X25519 and XChaCha20-Poly1305 and remain opaque to the relay. Notification previews are separate: the relay and Apple receive titles, bodies, deep links, and action metadata. Use generic previews for sensitive events. Notification text and encrypted payloads are not logged.

An opt-in private-preview protocol is available in the release-candidate source. It requires updated sender, relay and iPhone implementations and is not available in build 75. Standard integrations keep their existing request format.

Self-hosting it

The relay is open source under AGPL-3.0 and ships as a single Docker container. The full source is on GitHub:github.com/parlane-ai/relay, so you can read exactly what it does, including the "what it can't see" claims above, and run your own.

illustrative, final image name TBD
docker run -p 8787:8787 -v relay-data:/data \
  -e PUBLIC_URL=https://relay.example.com \
  -e DB_PATH=/data/relay.db \
  parlane/relay:latest

One container, no external services: all state is a single SQLite file atDB_PATH. PUBLIC_URL is the address the relay hands out during pairing. Keys are exchanged during pairing (see above), and the relay stores routing information and transport-auth secrets. TheAPNS_* variables in the README configure an APNs key for yourown Apple team; they cannot sign push for the Parlaneapp (see the limit below). Self-hosting is useful for auditing and custom transport clients, rather than the current app's direct HTTP/MCP connection.

SQLite requires one writer and a persistent volume. Do not place its live database on an ephemeral or independently scaled container filesystem. The hosted relay uses DynamoDB transactions for routing, pairing and registration. Existing connections were migrated before the updated service began accepting traffic.

The one honest limit: self-hosting can't deliver push

Apple only delivers push to the Parlane app when it's signed with Parlane's own APNs key, for its fixed bundle id, and that key can't ship inside an open-source repository. So a self-hosted relay can serve custom transport clients but cannot deliver push to theParlane app. Push always routes through the Parlane-operated hosted relay, which owns the only key that can reach the app. Developers never supply Apple credentials (no .p8, Key ID, or Team ID): you send a push by calling POST /notify on the hosted relay and it does the Apple hop for you. If you don't need push, you don't need the hosted relay at all: direct connections skip this whole path.

Hosted relay

Don't want to run your own? The hosted relay is the Pro tier. See pricing.