R Relay ← Back to relay docs

Getting push credentials (APNs .p8 and Firebase service account)

A tenant needs these to receive push notifications — the wake-up that rings a call or shows a chat notification when the app is backgrounded or killed. Chat and calling both work over the live WebSocket without any of this; push only matters for the "app isn't open right now" case. Both credential types are entered in the admin panel under Configuration → APNs (iOS) and Configuration → Firebase Cloud Messaging (Android), by a tenant admin or a super admin configuring the tenant directly.

Neither of these is a Relay-specific concept — they're the same credentials any push-enabled iOS or Android app needs, from Apple and Google directly. If your team already has them for another app, you can reuse the same Apple Developer account / Firebase project, or create a second key scoped to just this app — either works.


1. APNs .p8 key (iOS)

What you need first

Steps

  1. Go to developer.apple.com/accountCertificates, Identifiers & ProfilesKeys (left sidebar).
  2. Click the + button to register a new key.
  3. Give it a name (e.g. "Relay push key" — the name is just for your own reference, it has no effect on how it works).
  4. Check Apple Push Notifications service (APNs), then click ContinueRegister.
  5. Click Download. The file is named AuthKey_XXXXXXXXXX.p8 (the 10 characters before .p8 are the Key ID — you'll need it, but you don't have to remember it: the admin panel reads it straight out of the filename when you upload it, as long as you don't rename the file).
  6. This is the only time Apple lets you download this file. If you lose it, you have to revoke the key and generate a new one — there's no "download again" later. Keep a copy somewhere your team can find it (a password manager or secrets vault, not Slack).
  7. Note your Team ID — visible on the same Keys page (top right, under your name/org) or on Membership details. It's a 10-character alphanumeric string, different from the Key ID.

What goes where in the admin panel

Apple gives you Enter as Notes
The downloaded AuthKey_XXXXXXXXXX.p8 file Upload .p8 key file… Upload the file directly — the admin panel reads the Key ID from the filename and the key itself from the file contents. Don't rename it before uploading, or paste its contents into a text field; drop the original file in.
Team ID (from the Keys page / Membership details) Team ID 10-character string, e.g. A1B2C3D4E5.
Your app's bundle ID Bundle ID (APNs topic) Must exactly match the bundle ID the shipped app uses — a mismatch means APNs silently drops every push.
Try the APNs sandbox host first checkbox Turn this on while testing with a development-signed build (Xcode Debug builds, TestFlight internal builds signed with a Development provisioning profile use the sandbox APNs environment). Turn it off for App Store / TestFlight external / Ad Hoc builds, which use the production APNs environment. If you're not sure which you're running, Relay's push sender already retries the other environment automatically on a specific "wrong environment" error from Apple — this checkbox only controls which one it tries first, so getting it wrong costs you one extra round-trip, not a broken push.

One key, multiple apps

A single .p8 key is not tied to one app — it's tied to your Apple Developer account. The topic (bundle ID) field is what scopes a given push to a specific app, so if you have several apps under one Apple Developer account, you can reuse the same .p8 key across several Relay tenants and just set each tenant's topic to that tenant's own bundle ID.

Revoking a key

If a .p8 key leaks (checked into a public repo, shared insecurely), revoke it immediately from the same Keys page in the Apple Developer portal, then generate a new one and re-upload it in the admin panel. Revoking takes effect for all apps using that key, so if you shared one key across multiple tenants, you'll need to update all of them.


2. Firebase service account JSON (Android)

What you need first

Steps

  1. Go to console.firebase.google.com → select your project → the gear icon (top left) → Project settings.
  2. Open the Service accounts tab.
  3. Under "Firebase Admin SDK", click Generate new private key. Confirm the dialog.
  4. A JSON file downloads immediately (something like myapp-firebase-adminsdk-abc123-1234567890.json). Unlike the APNs key, you can generate a new one later if you lose this one — old keys aren't invalidated by generating a new one, though it's good practice to delete unused ones from that same page.

What goes where in the admin panel

Just upload the whole downloaded JSON file under Upload service-account JSON key… — the admin panel reads everything it needs (project_id, client_email, private_key) straight out of the file, so there's nothing to copy or retype by hand and no risk of a paste error breaking the key's line breaks (a common way this goes wrong if you ever do it manually — a private key with \n escapes mangled by a text editor won't verify).

Field inside the JSON Shown in the admin panel as
project_id Firebase project ID (read-only display, confirms you uploaded the right project)
client_email Service account email (read-only display)
private_key Stored encrypted, never displayed again — re-upload the file if you need to rotate it

This is a server credential — treat it like one

This file grants send-on-behalf-of-this-project access to Firebase Cloud Messaging — anyone who has it can send push notifications as your app. It is uploaded to the Relay service (encrypted at rest with RELAY_SECRETS_KEY) and never sent to any client app. Don't commit it to a repository, don't attach it to a support ticket, don't paste it into a chat message — if it leaks, delete that service account key from Firebase Console → Project settings → Service accounts, then generate a new one and re-upload it in the admin panel.

google-services.json is a different file — you don't need it here

Don't confuse the service account key above (server-side, what Relay needs) with google-services.json (client-side, what your Android app build needs so the Firebase SDK inside it knows which project to talk to). Your Android app still needs its own google-services.json dropped into its module and the google-services Gradle plugin applied — that's a normal Android/Firebase setup step, unrelated to what you upload in the Relay admin panel. See packages/android/app-demo/README.md's push section for exactly what that looks like in a real app module.


Testing without real push (what already works, and what doesn't)

Chat and calling both work fully over the live WebSocket connection while both apps are foregrounded and connected — none of the above is required to try that (see sample-apps/web-demo, sample-apps/ios-demo, and packages/android/app-demo). What you specifically can't verify without the real credentials above (and, for iOS, a physical device — the Simulator has no APNs connection at all) is the wake-up-a-backgrounded-app path: an incoming call ringing CallKit from a cold start, or a chat push arriving while the app isn't running. Each demo app's README says so explicitly rather than pretending that part works when it hasn't actually been exercised.