APNs (iOS push)

Appwin sends iOS push notifications with your Apple key, not its own. They therefore go out under your publisher identity, and you keep control if you change provider.

An APNs .p8 key works for every app of the same Apple team, and for both sandbox and production. One file is enough for several projects.

The Android side is on FCM.


1. Create the key

On developer.apple.com: Certificates, Identifiers & Profiles → Keys → +

  1. Name the key ("appwin push")
  2. Tick Apple Push Notifications service (APNs)
  3. Continue, then Register
  4. Download: the file AuthKey_XXXXXXXXXX.p8 downloads

The .p8 downloads only once. Apple does not regenerate it. Put it in your password manager before closing the tab - lose the file and you have to revoke the key and create another one.

Do not confuse this key with the App Store Connect API key: same .p8 format, same portal, two unrelated uses. This one must have APNs ticked.

2. Collect the identifiers

FieldWhere to find it
Key IDOn the key's page, or in the file name AuthKey_XXXXXXXXXX.p8
Team IDApple Developer → Membership details, or top right under the team name
Bundle IDXcode → Target → General → Bundle Identifier
Private keyThe contents of the .p8, headers included

The contents of the .p8 look like:

Plain text
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg...
-----END PRIVATE KEY-----

Paste it whole, BEGIN and END lines included. The simplest route is Import a file: Appwin reads the .p8 and derives the Key ID from its name, which saves retyping it.

The Bundle ID must match the App ID declared in Identifiers. A bundle that does not match gives sends that Apple accepts but never delivers.

3. Enter them in Appwin

Settings → Projects → your app → Integrations → Apple Push (APNs).

FieldValue
Key ID2X9R4HXF34
Team IDA1B2C3D4E5
Bundle IDcom.yourstudio.yourapp
Private Key (.p8)The file contents

Sandbox or production

The API picks Apple's server from a production flag stored with the integration: api.push.apple.com if true, api.sandbox.push.apple.com otherwise. The default is sandbox.

That flag is not exposed in the form yet. In practice, sends currently target the sandbox: a token obtained from an Xcode build arrives, a TestFlight or App Store token does not. That is the classic iOS push trap, and the number one reason for "the send went out, nothing arrived".


4. Register the device token

A key on the server side is not enough: every device has to declare its token after the user grants permission.

swift
import AppwinNotifications

func application(
  _ application: UIApplication,
  didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
  let token = deviceToken.map { String(format: "%02x", $0) }.joined()
  Task {
    try? await AppwinCore.registerPushToken(token, platform: "ios")
  }
}

The token arrives as Data: Appwin expects its hexadecimal form, hence the conversion above.


Checking

With no key configured, the API simulates the send and logs it instead of failing. That is deliberate - the rest of the product can be developed without keys at hand - but it also means a campaign can look like it went out with nothing sent.

Check the API logs: an APNs not configured - simulating delivery means the key is missing.


Troubleshooting

SymptomLikely cause
Send "succeeded", nothing receivedA production token, sent to the sandbox
BadDeviceTokenA token from one environment, the other environment's server
InvalidProviderTokenWrong Key ID or Team ID, or a truncated .p8
TopicDisallowedThe Bundle ID entered differs from the app's
Nothing goes out at allNo key: the API simulates and says so in its logs
Received in debug, not in TestFlightSame cause as the first row

Next