Skip to main content

Push relay error codes (push-relay)

Answered by the central push relay (W3-RLY-01, ARCHITECTURE section 6) as application/problem+json (code, title, status, optional detail). The detail never contains device tokens, keys, caller details or payload content. The test every_relay_code_is_documented in relay/crates/push-relay-core/src/error.rs keeps this page and the code in step.

A push that reached APNs or FCM is never an error: POST /v1/push answers 200 with a result of accepted, invalid_token, rejected or failed, plus the upstream status and reason code (for example BadDeviceToken or UNREGISTERED). The codes below are for requests the relay refused before sending anything. Every refused push releases its idempotency key, so the PBX may retry it with the same key.

Push results (W3-RLY-02)​

Every push the relay sends upstream ends in exactly one result, returned in the push answer, stored for 30 days in relay_deliveries, readable later with POST /v1/receipts/query, and counted in mpbx_relay_pushes_total{platform,kind,result}. upstream_status and upstream_reason are those of the last attempt.

resultMeaningTypical upstream answersRetried by the relayWhat the PBX does (W3-PUSH-01)
acceptedAPNs or FCM accepted the push for delivery. Not yet proof that the phone got it: that is the receipt (delivered_at).APNs 200; FCM 200—Keep ringing; record the push id; mark delivered when a receipt arrives.
invalid_tokenThe device token is dead. The relay marks the device invalid; later pushes answer RELAY-DEVICE-INVALID until the app registers a new token.APNs 400 BadDeviceToken, 400 DeviceTokenNotForTopic, 410 Unregistered; FCM 404, UNREGISTERED, SENDER_ID_MISMATCH; FCM INVALID_TOKEN_FORMAT (local check)noMark the device degraded, tell the user, ring other devices.
rejectedAPNs or FCM refused the push for another permanent reason (payload, topic, our credentials after one refresh). Retrying the same push cannot help.APNs 400 other reasons, 403 ExpiredProviderToken / InvalidProviderToken twice; FCM 400 INVALID_ARGUMENT, 401 twice, THIRD_PARTY_AUTH_ERROR twice; relay-local provider_token, oauth_sign, oauth_failed (4xx)provider/OAuth token refreshed onceRing other devices; operators see mpbx_relay_pushes_total{result="rejected"}.
failedTransient failures until the retry budget ran out (3 attempts, 5 s for calls, 15 s for notifications).429, 500, 503; FCM QUOTA_EXCEEDED, UNAVAILABLE, INTERNAL; relay-local connect, timeout, oauth_connect, oauth_bodyyes, with jittered backoff and Retry-AfterRetry within the ring window with the same idempotency key, ring other devices in parallel.

upstream_reason is always an upstream or relay reason code from this table (at most 64 characters), never payload content.

Delivery receipts (W3-RLY-02)​

The app acknowledges each push with POST /v1/receipts {push_id, receipt} (payload fields p and r). A valid acknowledgement answers 204, also when it is a replay (it is recorded once). The PBX reads results and receipts with the signed POST /v1/receipts/query {push_ids} (at most 200 ids); ids of other instances, unknown ids and ids past the 30-day retention are absent.

CodeHTTPMeaningWhat to do
RELAY-AUTH-MISSING401A signature header (x-mpbx-instance or x-mpbx-public-key, x-mpbx-timestamp, x-mpbx-nonce, x-mpbx-signature) is missing or malformed.Use mpbx-push-relay-client, which signs every request (mpbx-relay-sig-v1).
RELAY-AUTH-SKEW401The request timestamp is more than 300 s away from the relay clock (the detail gives the relay time), or it is older than the relay's replay epoch: the request was signed before a region failover or a Valkey restart (W10-RLY-01).Fix the PBX host clock (NTP). After a failover, sign the request again (the PBX does on every retry).
RELAY-AUTH-REPLAY401The nonce was already used by this instance within the last 10 minutes: a replayed or duplicated request.Send each request with a fresh nonce (the client does). Retrying a push uses the same idempotency key, not the same nonce.
RELAY-AUTH-INVALID401The signature does not verify, or the instance id is unknown (the two are not distinguished on purpose).Check that MPBX_RELAY_INSTANCE_KEY is the key that was enrolled. If the key was replaced without a rotation, enroll again (the new key gets a new instance id); rotate with POST /v1/instances/rotate-key to keep the devices. A key rotation whose proof of the new key does not verify also answers this code.
RELAY-ENROLL-CODE-REQUIRED403This relay accepts enrollments only with an activation code (MPBX_RELAY_ENROLLMENT=code_required).Ask MonoPbx for an activation code and run the manual activation.
RELAY-ENROLL-CODE-INVALID403The activation code is unknown, already used or expired. Codes are single use.Ask for a new code (push-relay activation-code create on the relay).
RELAY-ENTITLEMENT-EXPIRED403The entitlement was revoked and its 30-day grace period is over. Push is refused explicitly, never dropped silently.Contact MonoPbx. During the grace period pushes keep flowing and every answer carries x-mpbx-entitlement: grace; ends=....
RELAY-BAD-REQUEST400The body is not valid JSON for the endpoint, or a field is invalid (for example a call push without call_uuid, a token of the wrong shape, an iOS push without the matching token). The detail names the field.Fix the request.
RELAY-BODY-TOO-LARGE413The body is larger than 16 KiB.Requests are small; this is a client bug.
RELAY-DEVICE-NOT-FOUND404The push_ref does not exist for this instance (it may belong to another instance, which is not revealed), or the endpoint does not exist.Register the device again and store the new push_ref.
RELAY-DEVICE-INVALID410APNs or FCM reported the device token as invalid earlier, so the relay stopped using it.The app must send a fresh token; register it again (same device_id keeps the push_ref).
RELAY-DEVICE-LIMIT409The instance already has the maximum number of registered devices (20 000 by default).Delete devices that are gone (DELETE /v1/devices/{push_ref}).
RELAY-IDEMPOTENCY-CONFLICT409The idempotency key was already used with a different request body.Use a new key for a different push (the client uses <call_uuid>:<kind>:<push_ref>).
RELAY-IDEMPOTENCY-IN-FLIGHT409A request with the same idempotency key is still being sent.Wait for the first answer; retry after Retry-After.
RELAY-RATE-LIMITED429The per-instance push rate (20/s, burst 200), device operations (600/min) or enrollment attempts (10/min per address) were exceeded.Retry after Retry-After.
RELAY-QUOTA-DAILY429The per-instance daily hard limit (100 000 pushes per UTC day by default) was reached.Retry after Retry-After (next UTC day) or contact MonoPbx.
RELAY-QUOTA-DEVICE429More than 30 pushes to one device in a minute.Retry after Retry-After; check the PBX for a push loop.
RELAY-PLATFORM-UNAVAILABLE503The relay has no APNs (iOS) or FCM (Android) credentials configured, or no Web Push key-encryption key (MPBX_RELAY_WEB_PUSH_KEK_PATH, browsers). Also printed by push-relay serve when a configured key cannot be loaded.Operator: set MPBX_RELAY_APNS_* or MPBX_RELAY_FCM_* (docs/guides/push-relay.md).
RELAY-WEB-ENDPOINT-REFUSED422A browser (web) device registration whose Web Push endpoint the relay will not POST to (W6-RLY-WEB, SSRF guard): not https, an IP address instead of a host name, user information or a port other than 443 in the URL, a host that is not one of the known push services (MPBX_RELAY_WEB_PUSH_HOSTS), or a subscription key of the wrong size. The same check runs again before every push, and a host that resolves to a private, loopback or link-local address is refused then.PBX: tell the user this browser's push service is not supported (calls still ring while MonoPbx is open). Operator: add the push service's host suffix to MPBX_RELAY_WEB_PUSH_HOSTS only if it is a real public push service.
RELAY-RECEIPT-INVALID401The receipt token does not match the push id, or the push id is not a relay push id. Tokens are bound to one push.App: send the p and r values of the push exactly as received.
RELAY-RECEIPT-EXPIRED410The push is more than 25 hours old; it can no longer be acknowledged.Nothing; drop the acknowledgement.
RELAY-RECEIPTS-UNAVAILABLE503The relay has no receipt key (MPBX_RELAY_RECEIPT_KEY_PATH), so pushes carry no receipt token.Operator: configure the key (docs/guides/push-relay.md). The PBX treats accepted as the last known state.
RELAY-UNAVAILABLE503The relay database or Valkey is unavailable.Retry; the PBX keeps ringing live devices meanwhile (ARCHITECTURE 11.3).
RELAY-INTERNAL500An unexpected relay error (logged on the relay).Retry; report if it persists.