Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time
March 31, 2022 12:05
March 31, 2022 12:12
March 31, 2022 12:12
March 31, 2022 12:12
February 15, 2017 12:55
February 16, 2022 14:07
January 11, 2023 09:42
January 13, 2020 09:55

Push Relay

CI License

This server accepts push requests via HTTP and relays those requests to the appropriate push backends.

Supported backends:

  • Google FCM
  • Apple APNs
  • Huawei HMS

Request Format

  • POST request to /push
  • Request body must use application/x-www-form-urlencoded encoding

Request keys:

  • type: Either fcm, hms or apns
  • token: The device push token
  • session: SHA256 hash of public permanent key of the initiator
  • version: Threema Web protocol version
  • affiliation (optional): An identifier for affiliating consecutive pushes
  • ttl (optional): The lifespan of a push message, defaults to 90 seconds
  • collapse_key: (optional) A parameter identifying a group of push messages that can be collapsed.
  • bundleid (APNs only): The bundle id to use
  • endpoint (APNs only): Either p (production) or s (sandbox)
  • appid (HMS only): Can be used to differentiate between multiple configs


curl -X POST -H "Origin: https://localhost" localhost:3000/push \
    -d "type=fcm&token=asdf&session=123deadbeef&version=3"
curl -X POST -H "Origin: https://localhost" localhost:3000/push \
    -d "type=apns&token=asdf&session=123deadbeef&version=3&"
curl -X POST -H "Origin: https://localhost" localhost:3000/push \
    -d "type=hms&appid=123456&token=asdf&session=123deadbeef&version=3"

Possible response codes:

  • HTTP 204 (No Content): Request was processed successfully
  • HTTP 400 (Bad Request): Invalid or missing POST parameters (including expired push tokens)
  • HTTP 500 (Internal Server Error): Processing of push request failed on the Push Relay server
  • HTTP 502 (Bad Gateway): Processing of push request failed on the FCM, HMS or APNs server

Push Payload

The payload format looks like this:

  • wcs: Webclient session (sha256 hash of the public permanent key of the initiator), string
  • wca: An optional identifier for affiliating consecutive pushes, string or null
  • wct: Unix epoch timestamp of the request in seconds, i64
  • wcv: Protocol version, u16


The FCM and HMS messages contain the payload data as specified above.


The APNs message contains a key "3mw" containing the payload data as specified above.


You need the Rust compiler. First, create a config.toml file that looks like this:

api_key = "your-api-key"

keyfile = "your-keyfile.p8"
key_id = "AB123456XY"
team_id = "CD987654YZ"

To support HMS as well, you need to add one or more named HMS config sections. The name should correspond to the App ID (and currently matches the Client ID).

client_id = "your-client-id"
client_secret = "your-client-secret"

client_id = "your-client-id"
client_secret = "your-client-secret"

If you want to log the pushes to InfluxDB, add the following section:

connection_string = ""
user = "foo"
pass = "bar"
db = "baz"

Then simply run

export RUST_LOG=push_relay=debug,hyper=info,a2=info
cargo run build and start the server in debug mode.


  • Always create a build in release mode: cargo build --release
  • Use a reverse proxy with proper TLS termination (e.g. Nginx)
  • Set RUST_LOG=info env variable


To run tests:

cargo test


To run lints:

$ rustup component add clippy
$ cargo clean && cargo clippy --all-targets


Licensed under either of

at your option.