Apple Push Notifications (APNs)
APNs (Apple Push Notification service) is a built-in Norq push provider
for iOS direct delivery. It builds requests for
POST https://api.push.apple.com/3/device/{token} (production) or
POST https://api.sandbox.push.apple.com/3/device/{token} (sandbox).
Configuration
providers:
apns:
config:
keyId: AB1234CDEF # 10-char Key ID
teamId: TEAM123ABC # 10-char Team ID
bundleId: com.example.MyApp # iOS bundle identifier
keyPath: ./secrets/AuthKey_AB1234CDEF.p8
# OR inline / env var:
# keyPem: ${APNS_KEY_PEM}
# Optional — defaults to sandbox
production: true
routing:
push: apns
# OR push.ios specificallykeyId, teamId, bundleId are required, plus exactly one of
keyPath (file path) or keyPem (inline / env var). production
defaults to false (sandbox).
Environment-variable fallback
If providers.apns is not declared, Norq registers APNs when these env
vars are set:
| Var | Required |
|---|---|
NORQ_APNS_KEY_ID |
yes |
NORQ_APNS_TEAM_ID |
yes |
NORQ_APNS_BUNDLE_ID |
yes |
NORQ_APNS_KEY_PATH |
one of these two |
NORQ_APNS_KEY_PEM |
one of these two |
NORQ_APNS_PRODUCTION |
optional (default false) |
Per-token environment override
Push tokens may carry an environment field ("sandbox" or
"production") on each recipient — the per-token value overrides the
provider-level production flag for that single message. Useful for
clients that ship TestFlight builds (sandbox) and App Store builds
(production) in parallel and store both flavours of token. Any value
other than "sandbox" or "production" errors with
push/invalid-environment.
Capabilities
- Channels: push (
iosonly — APNs has no Android or web concept). - Batching: none. APNs is one HTTP/2 stream per token.
apns-topicheader: auto-set from the configuredbundleId.
CLI cannot deliver
The norq CLI binary cannot send via APNs — Apple’s gateway
requires HTTP/2 (the Norq CLI is HTTP/1.1 only via ureq) and the
ES256 JWT signing flow is not bundled. Calling norq send while
routed to APNs short-circuits with provider/cli-http2-required.
SDKs (Node, Python, Go, Java, Ruby) use HTTP/2-capable runtime
clients and sign tokens in-process.
Request shape
-
Body:
application/json. APS payload:{ "aps": { "alert": { "title": "...", "body": "..." }, "sound": "default", "badge": 1, "interruption-level": "active" } } -
Auth: signed ES256 JWT in the
Authorization: Bearer <jwt>header. Norq emitsAuth::AppleJwt { key_id, team_id, p8_pem }; the SDK signs with the p8 key per request (cached for ≤1h per Apple’s spec). -
Required headers:
apns-topic: <bundleId>. Per-message headers likeapns-priority,apns-push-type,apns-collapse-id,apns-expirationflow through from the push template frontmatter when set. -
Endpoint:
POST https://api.push.apple.com/3/device/{token}(production) orhttps://api.sandbox.push.apple.com/3/device/{token}(sandbox). -
Success:
200(no body). Norq does not extract a message ID from the response — theapns-idheader exists in the APNs response butResponseHints.message_id_headeris not set for this provider. Theapns-idheader IS used as a deduplication key when supplied in the request viaidempotency_key(see the Idempotency table in the Providers overview). -
Retry: defaults — 429 + 5xx (500, 502, 503, 504), 2 retries, 500ms backoff.