Norq

Expo Push

Expo Push Service is a built-in Norq push provider for React Native / Expo apps. It builds requests for the POST https://exp.host/--/api/v2/push/send endpoint and accepts ExponentPushToken[xxx] device tokens (not native FCM/APNs tokens).

Configuration

providers:
  expo:
    config:
      # Optional — anonymous mode works but with stricter rate limits
      accessToken: ${EXPO_ACCESS_TOKEN}
routing:
  push: expo
  # OR per-platform:
  # push:
  #   ios: expo
  #   android: expo

accessToken is optional. Without it, Expo accepts unauthenticated requests at lower rate limits. The token may be provided via env-var ref (${VAR}), file path, or inline literal — the standard secret value forms.

Environment-variable fallback

If providers.expo is not declared, Norq registers Expo when either of these env vars is set:

Var Required
NORQ_EXPO_ACCESS_TOKEN one of these two
NORQ_EXPO_ENABLED one of these two

NORQ_EXPO_ACCESS_TOKEN registers an authenticated Expo provider. NORQ_EXPO_ENABLED (any value) registers an anonymous Expo provider — useful in local dev or testing when no API key is available.

Capabilities

  • Channels: push (ios + android only — Expo’s push service does not handle web tokens. Web-push routing must use the Web Push provider).
  • Token shape: Expo uses its own opaque tokens of the form ExponentPushToken[xxx]. These are not the native APNs device tokens or FCM registration tokens — Expo’s service relays internally.
  • Batching: Norq sends one message per prepare_send call (no native batch endpoint is used). However, Expo’s /push/send endpoint requires an array body even for a single message — Norq always wraps the message in an array before sending.
  • CLI: works. Expo uses Bearer auth (or anonymous) and plain HTTP/1.1, so the norq CLI binary can deliver Expo push without needing OAuth2 or HTTP/2 dependencies.

Per-platform overrides

The push template’s ios: and android: frontmatter blocks both flow through to Expo’s per-message fields (e.g. badge, sound, channelId, priority). Non-numeric badge values that fail to coerce error with the appropriate validation code at compile time.

Request shape

  • Body: application/json — always an array of message objects:

    [
      {
        "to": "ExponentPushToken[xxx]",
        "title": "...",
        "body": "...",
        "data": { ... },
        "badge": 1,
        "sound": "default"
      }
    ]
  • Auth: Authorization: Bearer <accessToken> when configured; Auth::None when running anonymously.

  • Endpoint: POST https://exp.host/--/api/v2/push/send.

  • Success: 200. Norq extracts the receipt ID from $.data[0].id (Expo returns a per-message data array of receipts).

  • Retry: defaults — 429 + 5xx, 2 retries, 500ms backoff.