Postal Pigeon
In development

A doorbell for
your own server.

Postal Pigeon is a small service that lets self-hosted Hedgerow servers send push notifications to the Hedgerow iOS apps. It rings the bell on your iPhone, and it never learns what the ring is about.

Not public yet. Push is optional, and the apps work without it.

Open source, AGPL-3.0Built in RustPart of Hedgerow

Why Pigeon

Only one key can ring an iPhone app.

Apple only lets the holder of an app’s push key send notifications to that app. The Hedgerow iOS apps talk to servers that you host yourself, and those servers can’t hold the publisher’s key, because anyone who runs a server would then hold it too.

  • Apple’s rule

    Push notifications for an iOS app can only be sent by whoever holds that app’s Apple push key. Nobody else can ring it.

  • Your server can’t hold it

    Hedgerow servers are run by many different people. Handing every one of them the publisher’s key would be the end of keeping it safe.

  • So Pigeon rings for it

    Your server asks Pigeon to wake up one specific app install. Pigeon holds the key and asks Apple to do it. That is the whole job.

How it works

A doorbell, not a messenger.

The push says only “something changed, ask your server”. What changed is never put in the push. The app asks your own server, and your server tells it.

How a push travels Step 1: your server asks Postal Pigeon to send a push. Step 2: Postal Pigeon passes it to Apple. Step 3: Apple delivers it to the Hedgerow app on your iPhone. Dashed lines: the app registered its device with Postal Pigeon once and gave a handle to your server, and after a push it asks your server what changed. Your server self-hosted Postal Pigeon holds the push key Apple push service Your iPhone the Hedgerow app 1 2 3 registers its device, once hands over a handle, then fetches the details How a push travels Step 1: your server asks Postal Pigeon to send a push. Step 2: Postal Pigeon passes it to Apple. Step 3: Apple delivers it to the Hedgerow app on your iPhone. Dashed lines: the app registered its device with Postal Pigeon once and gave a handle to your server, and after a push it asks your server what changed. Your server self-hosted Postal Pigeon holds the push key Apple push service Your iPhone the Hedgerow app 1 2 3 Dashed: set-up and fetching the details
Solid lines are a push on its way. Dashed lines are the app talking to Pigeon once, to register its device, and to its own server, to hand over a handle and later fetch the details.

Once, when you connect a server

  1. The app gets its address from Apple and registers it with Pigeon directly. Pigeon gives it a device id and a private key that never leaves the phone.
  2. For each of your servers, the app asks Pigeon for a handle: an opaque code that lets one server ring this phone, and nobody else.
  3. The app gives the handle to that server over the connection it already has. Your server never learns the phone’s address, only the handle.

Each time something happens

  1. Your server asks Pigeon to send a push to a handle, naming only the kind of push and an opaque reference.
  2. Pigeon builds the push itself, with fixed generic text, and hands it to Apple.
  3. The app wakes up and asks its own server what changed. The details appear on your phone, written there, and never pass through Pigeon or Apple.

Fixed text, filled in on your phone. If the app can’t reach your server in time, the notification keeps its generic wording, such as “Something needs attention”. You still get the ring. Servers can’t make Pigeon display text of their choosing, so it can’t be used to put words in the app’s mouth.

Privacy

What the operator can and can’t see.

The official Pigeon is run by the Hedgerow maintainer. This is the plain-words version of what that means. The full privacy statement is in the design document.

  • What the operator can see

    • Your phone’s push address (Apple’s token), the app it belongs to and whether it is a test build. It doesn’t name you.
    • When pushes are sent, how often, and the date a handle was last used.
    • The internet address of your phone when the app registers, and of your server when it sends, while the request is handled.
    • How many handles a phone has, roughly how many servers it is connected to, but not which.
    • Which server product and version each server reports about itself.
  • What the operator can’t see

    • What happened. There is no content in a push, so there is nothing to read.
    • Your server’s name or address, in any stored form. Pigeon never calls your server and holds no key to it.
    • Your server’s API tokens, your data, your monitors, your vault.
    • Your name, e-mail address or an account. There are none.
    • What is on your phone.
  • Logs kept for 7 days

    The reverse proxy in front of Pigeon keeps access logs for at most seven days. Pigeon itself doesn’t log tokens, handles, credentials or client addresses.

  • What Apple sees

    The device token, the app, the time and the tiny content-free message, as it does for every iOS push. Apple’s own privacy terms apply.

  • What Pigeon never does

    Sell or share data, add analytics or advertising, build profiles, call your server, or send anything but a “something changed” signal.

The honest limit While a push is being sent, the operator’s system necessarily sees which server asked for which handle. Pigeon doesn’t store that pairing or write it to its logs, but a modified relay could. That is why the design says “as far as practical”, not “impossible”.

You stay in control Push is off by default on every server. You can turn it off in the app and on the server, cut off a single server from the app (Pigeon enforces it), or delete your device record and Pigeon forgets it at once.

Who uses it

iOS needs Pigeon. Android doesn’t.

Pigeon exists because of how Apple’s push service works. Elsewhere, and whenever you would rather not use it, everything keeps working.

  • The Hedgerow iOS apps

    The Hedgerow app, for your own Vigilant Vole, Keen Kestrel and Wise Wren, and later Faithful Ferret, use Pigeon to get pushes from your servers.

  • Android uses UnifiedPush

    Android builds get pushes through a distributor you choose, such as ntfy, and your server talks to it directly. Pigeon isn’t involved at all.

  • Off by default

    Push is optional on every server. Without it, the apps update when you open them, when you pull to refresh, and when iOS refreshes them in the background.

  • Run your own

    The push key belongs to the official apps. If you build your own version of an app, you run your own Pigeon with your own Apple developer account. The code is open for that reason.

Limits and fair use

Free to use, with sensible limits.

The official Pigeon is free, and there are no supporter tiers planned. The limits keep it usable for everyone and keep Apple happy with the shared push key. These are starting values and will be tuned from real use.

  • Per connection

    Notifications
    6 an hour
    Silent refreshes
    30 an hour

    One server can ring one phone at most this often.

  • Per phone

    Notifications
    30 an hour
    Silent refreshes
    120 an hour

    All your servers together, so one busy server can’t drown out the rest.

  • Per server

    New server
    600 an hour
    Established server
    6,000 an hour

    A server becomes established after seven days without hitting a limit.

  • Size and batching

    Request size
    2 KiB
    Phones per request
    up to 25

    Bursts should be batched, for example one notification per incident rather than per check.

  • Fair use

    Send only to phones whose owners gave your server a handle, and only “something changed” signals. No bulk or promotional sending.

  • No guarantee

    Apple’s push service doesn’t guarantee delivery, and neither does Pigeon. The apps never rely on push alone.

  • Misuse has limits too

    Servers that keep hitting limits are suspended, and you can cut off a single server from the app at any time. An abuse contact will be published when Pigeon opens.

For server developers

A small, plain API.

Pigeon speaks JSON over HTTPS under /v1. A server registers itself with a small proof of work and no sign-up, then sends pushes to the handles its users gave it. A server can send nothing to anyone who hasn’t given it a handle.

  • Open registration, no approval step.
  • A request names up to 25 handles, a kind (alert or sync) and an opaque reference.
  • The answer has one result per handle: accepted, duplicate, gone, limited or unavailable.
  • Pigeon never receives your server’s address, and your server never receives a phone’s address.
  • Changes within /v1 are additive only. A breaking change gets /v2, served alongside for at least a year.

The full API and the design are in the docs folder of the repository. The API is not final until the first release.

// Sent by your server. Content-free by design.
POST /v1/push
Authorization: Bearer <instance credential>

{
  "event_id": "7f6c8e0e-…",
  "handles": ["hrh_…"],
  "kind": "alert",
  "ref": "inc_9f3a1c",
  "ttl": 3600
}

// The answer, one result per handle
{ "results": [ { "status": "accepted" } ] }

Status

In development, not public yet.

The design and threat model are written and published, and the relay is being built. There is nothing to sign up for or install yet, and there are no dates: each step is done when it works.

  1. Done

    Design and threat model

    The API, how phones and servers register, what is stored and for how long, the limits, key handling and the privacy statement, all published.

  2. Now

    Building the relay

    One small Rust service with a SQLite database, behind a TLS proxy, with a health endpoint and an admin command line.

  3. Then

    Hedgerow app and servers switch it on

    The Hedgerow iOS app and the servers get push support, off by default, and are tested end to end with real devices.

  4. Then

    The official Pigeon opens

    With the API description, a conformance test suite and an abuse contact published alongside it.

Questions.

  • Can I use it now?

    Not yet. It is in development and the official relay isn’t public. Watch or star the repository to hear about progress.

  • Do I need it?

    Only if you want push notifications on an iPhone from your own Hedgerow servers. On Android you don’t, and on iOS push is optional: without it the apps update when you open them.

  • What happens if Pigeon is down?

    Nothing breaks. Push is a speed-up, never a requirement. The apps keep working against your servers, and your servers’ other alert channels, such as e-mail, chat and webhooks, aren’t delayed. Pushes resume when Pigeon is back.

  • Does it store my notifications?

    There is nothing to store. A push carries no content and isn’t kept: if Pigeon can’t hand it to Apple, it is dropped, not queued for later. Pigeon keeps only a sealed device token, opaque handles and small counters.

  • Can I run my own Pigeon?

    Yes. It is open source and meant to be run as one small container. Because only the holder of an app’s push key can ring that app, a relay of your own is useful with your own build of the app and your own Apple developer account.

  • Is it open source?

    Yes, under the GNU AGPL-3.0-only. Contributions aren’t open yet. Please report security problems privately, as described in the security policy.

  • Has it been audited?

    No external audit is funded. The design keeps the relay small and content-free on purpose, so a mistake in it costs as little as possible, and the threat model is public for anyone to check.