Article

Sending Notification Requests to APNs

Send your remote notification payload and device token information to APNs.

Overview

When you have a notification to send to a user, your provider must construct a POST request and send it to APNs. Your request must include the following information:

  • The JSON payload that you want to send

  • The device token for the user's device

  • Request header fields specifying options for how to deliver the notification

  • For token-based authentication, your provider server's current authentication token

Upon receiving your server's POST request, APNs validates the request using either the provided authentication token or your server's certificate. If validation succeeds, APNs uses the provided device token to identify the user's device. It then tries to send your JSON payload to that device.

Establish a Connection to APNs

Use HTTP/2 and TLS 1.2 or later to establish a connection between your provider server and one of the following servers:

Use the production server for your shipping apps and the development server for testing. When sending many remote notifications, you can establish multiple connections to these servers to improve performance. For example, if you have multiple provider servers, each one can establish its own connection.

APNs allows multiple concurrent streams for each connection, but don't assume a specific number of streams. The exact number of streams varies based on server load and whether you use a provider certificate or an authentication token. For example, when using an authentication token, APNs allows only one stream until you post a request with a valid authentication token. APNs ignores HTTP/2 PRIORITY frames, so don't send them on your streams.

If your provider certificate is revoked, or if you revoke your authentication token, close all connections to APNs, fix the problem, and then open new connections. APNs may also terminate a connection by sending a GOAWAY frame. The payload of the GOAWAY frame includes JSON data with a reason key, indicating the reason for the connection termination. For a list of values for the reason key, see Table 5.

Create and Send a POST Request to APNs

To send a notification to a user’s device, construct and send a POST notification to APNs. Send this request over the connection you created using HTTP/2 and TLS. To construct your POST notification, you must already have the following pieces of information:

In addition to the preceding data, add the header fields in Table 1 to your request. Some header fields are required for delivering the notification. Other headers are optional or may be dependent on whether you are using token-based or certificate-based authentication.

Table 1

Header fields for your POST request

Header field

Description

:method

(Required) The value POST.

:path

(Required) The value /3/device/<device_token> where <device_token> is the hexadecimal bytes that identify the user’s device. Your app receives the bytes for this device token when registering for remote notifications; see Registering Your App with APNs.

authorization

(Required for token-based authentication) The value bearer <provider_token> where <provider_token> is the encrypted token that authorizes you to send notifications for the specified topic. APNs ignores this header if you use certificate-based authentication. For more information, see Establishing a Token-Based Connection to APNs.

apns-id

A canonical UUID that is the unique ID for the notification. If an error occurs when sending the notification, APNs includes this value when reporting the error to your server. Canonical UUIDs are 32 lowercase hexadecimal digits, displayed in five groups separated by hyphens in the form 8-4-4-4-12. For example: 123e4567-e89b-12d3-a456-42665544000. If you omit this header, APNs creates a UUID for you and returns it in its response.

apns-expiration

The date at which the notification is no longer valid. This value is a Unix epoch expressed in seconds (UTC). If the value is nonzero, APNs stores the notification and tries to deliver it at least once, repeating the attempt as needed until the specified date. If the value is 0, APNs attempts to deliver the notification only once and does not store the notification.

apns-priority

The priority of the notification. If you omit this header, APNs sets the notification priority to 10.

Specify 10 to send the notification immediately. A value of 10 is appropriate for notifications that trigger an alert, play a sound, or badge the app’s icon. It's an error to specify this priority for a notification whose payload contains the content-available key.

Specify 5 to send the notification based on power considerations on the user’s device. Use this priority for notifications whose payload includes the content-available key. Notifications with this priority might be grouped and delivered in bursts to the user’s device. They may also be throttled, and in some cases not delivered.

apns-topic

The topic of the notification. When using token-based authentication, specify the bundle ID of the app. When using certificate-based authentication, the topic is usually your app's bundle ID. However, the topic may also correspond to the bundle ID of an Apple Watch complication or a background VoIP service. Look in the (1.2.840.113635.100.6.3.6) extension of your certificate to identify the possible topics for your push notifications.

If you omit the header and your certificate does not contain multiple topics, APNs uses your certificate’s Subject as the default topic.

apns-collapse-id

An identifier used to coalesce multiple notifications into a single notification for the user. Typically, each notification request causes a new notification to be displayed on the user’s device. When sending the same notification more than once, use the same value in this header to coalesce the requests. The value of this key must not exceed 64 bytes.

APNs requires the use of HPACK (header compression for HTTP/2), which prevents repeatedly storing header keys and values. APNs maintains a small dynamic table for HPACK. To avoid filling up that table, encode your headers in the following way—especially when using many streams:

  • Encode the :path and authorization values as a literal header fields without indexing.

  • Encode the apns-id, apns-expiration, and apns-collapse-id values differently based on whether this is an initial or subsequent request.

    • The first time you send these headers, encode them with incremental indexing to add the header fields to the dynamic table.

    • For subsequent requests, encode these headers as literal header fields without indexing.

  • Encode all other fields as literal header fields with incremental indexing.

Put the JSON payload with the notification’s content into the body of your request. The JSON payload must must not be compressed and is limited to a maximum size of 4KB (4096 bytes). For a Voice over Internet Protocol (VoIP) notification, the maximum size is 5KB (5120 bytes).

Listing 1 shows a sample request constructed with an authentication token.

Listing 1

A POST request with an authentication token.

HEADERS
  - END_STREAM
  + END_HEADERS
  :method = POST
  :scheme = https
  :path = /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0
  host = api.sandbox.push.apple.com
  authorization = bearer eyAia2lkIjogIjhZTDNHM1JSWDciIH0.eyAiaXNzIjogIkM4Nk5WOUpYM0QiLCAiaWF0I
		 jogIjE0NTkxNDM1ODA2NTAiIH0.MEYCIQDzqyahmH1rz1s-LFNkylXEa2lZ_aOCX4daxxTZkVEGzwIhALvkClnx5m5eAT6
		 Lxw7LZtEQcH6JENhJTMArwLf3sXwi
  apns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b
  apns-expiration = 0
  apns-priority = 10
  apns-topic = com.example.MyApp
DATA
  + END_STREAM
  { "aps" : { "alert" : "Hello" } }

Listing 2 shows a sample request constructed for a certificate. APNs uses the app's bundle ID as the default topic.

Listing 2

A POST request for a single topic

HEADERS
  - END_STREAM
  + END_HEADERS
  :method = POST
  :scheme = https
  :path = /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0
  host = api.sandbox.push.apple.com
  apns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b
  apns-expiration = 0
  apns-priority = 10
DATA
  + END_STREAM
  { "aps" : { "alert" : "Hello" } }

Handle the Response from APNs

APNs provides a response for each request that you make. Each response contains a header with fields indicating the status of the response. If the request was successful, the body of the response is empty. If an error occurred, the body contains a JSON dictionary with additional information about what happened.

Table 2 describes the meaning of the keys in the header response.

Table 2

Header keys

Header name

Value

apns-id

The same value found in the apns-id field of the request’s header. Use this value to identify the notification. If you don't specify an apns-id field in your request, APNs creates a new UUID and returns it in this header.

:status

The HTTP status code. For a list of possible values, see Table 3.

Table 3 lists the possible values in the :status header of the response.

Table 3

HTTP status codes

Status code

Description

200

Success.

400

Bad request.

403

There was an error with the certificate or with the provider’s authentication token.

405

The request used an invalid :method value. Only POST requests are supported.

410

The device token is no longer active for the topic.

413

The notification payload was too large.

429

The server received too many requests for the same device token.

500

Internal server error.

503

The server is shutting down and unavailable.

Table 4 lists the keys found in the JSON dictionary for unsuccessful requests. The JSON data might also be included in a GOAWAY frame when a connection is terminated.

Table 4

Response keys

Key

Description

reason

The error code (specified as a string) indicating the reason for the failure. For a list of possible values, see Table 5.

timestamp

The time at which APNs confirmed the token was no longer valid for the topic. This key is included only when the error in the :status field is 410.

Table 5 lists the possible error codes included in the reason key of a response’s JSON payload.

Table 5

Response error strings

Status code

Error string

Description

400

BadCollapseId

The collapse identifier exceeds the maximum allowed size.

400

BadDeviceToken

The specified device token is invalid. Verify that the request contains a valid token and that the token matches the environment.

400

BadExpirationDate

The apns-expiration value is invalid.

400

BadMessageId

The apns-id value is invalid.

400

BadPriority

The apns-priority value is invalid.

400

BadTopic

The apns-topic is invalid.

400

DeviceTokenNotForTopic

The device token doesn't match the specified topic.

400

DuplicateHeaders

One or more headers are repeated.

400

IdleTimeout

Idle time out.

400

MissingDeviceToken

The device token isn't specified in the request :path. Verify that the :path header contains the device token.

400

MissingTopic

The apns-topic header of the request isn't specified and is required. The apns-topic header is mandatory when the client is connected using a certificate that supports multiple topics.

400

PayloadEmpty

The message payload is empty.

400

TopicDisallowed

Pushing to this topic is not allowed.

403

BadCertificate

The certificate is invalid.

403

BadCertificateEnvironment

The client certificate is for the wrong environment.

403

ExpiredProviderToken

The provider token is stale and a new token should be generated.

403

Forbidden

The specified action is not allowed.

403

InvalidProviderToken

The provider token is not valid, or the token signature cannot be verified.

403

MissingProviderToken

No provider certificate was used to connect to APNs, and the authorization header is missing or no provider token is specified.

404

BadPath

The request contained an invalid :path value.

405

MethodNotAllowed

The specified :method isn't POST.

410

Unregistered

The device token is inactive for the specified topic.

413

PayloadTooLarge

The message payload is too large. For information about the allowed payload size, see Create and Send a POST Request to APNs.

429

TooManyProviderTokenUpdates

The provider’s authentication token is being updated too often. Update the authentication token no more than once every 20 minutes.

429

TooManyRequests

Too many requests were made consecutively to the same device token.

500

InternalServerError

An internal server error occurred.

503

ServiceUnavailable

The service is unavailable.

503

Shutdown

The APNs server is shutting down.

Listing 3 shows a sample response for a successful push request.

HEADERS
  + END_STREAM
  + END_HEADERS
  apns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b
  :status = 200

Listing 4 shows a sample response when an error occurs.

HEADERS
  - END_STREAM
  + END_HEADERS
  :status = 400
  content-type = application/json
  apns-id: <a_UUID>
DATA
  + END_STREAM
  { "reason" : "BadDeviceToken" }

Troubleshoot Problems

During testing, if you find that push notifications sent by your provider server are not being received by your test devices, examine the following possible causes:

  • Make sure that your provider server has an up-to-date device token for your test device. Each time your app launches, it should request its current token and forward that token to your provider server. You should also implement the appropriate failure handler methods to determine if APNs reported an error. See Registering Your App with APNs.

  • Check for errors returned by APNs. When failures occur, APNs reports an appropriate error back to your provider server. See Handle the Response from APNs.

  • Check to see if you are sending requests to the same device too quickly. APNs queues only one notification at a time for each device, and the device must acknowledge receipt of the notification before APNs dequeues it. If you send multiple notification requests in a very short period of time, each new request might overwrite the previous request.

  • Check to see if silent notifications are being throttled. APNs sends a limited number of silent notifications—notifications with the content-available key—per day. In addition, if the device has already exceeded its power budget for the day, silent notifications are not sent again until the power budget resets, which happens once a day. These limits are disabled when testing your app from Xcode. See Pushing Updates to Your App Silently.

  • Make sure you have the needed certificates installed on your provider server. If your provider server doesn't have the proper certificates for TLS/SSL validation, it cannot connect to APNs. For certificate-based connections, your provider server must also have the certificate you obtained from Apple. See Establishing a Certificate-Based Connection to APNs.

  • Check the firewall settings of your server and devices. To send notifications, your provider server must allow inbound and outbound TCP packets over port 443 for HTTP/2 connections, or port 2195 when using the binary interface. Devices connecting to APNs over Wi-Fi need to allow inbound and outbound TCP packets over port 5223, falling back to port 443 if port 5223 is unavailable. Computers running macOS must also allow inbound and outbound TCP traffic on port 80.

See Also

Server Tasks

Generating a Remote Notification

Send notifications to the user’s device with a JSON payload.

Pushing Updates to Your App Silently

Deliver silent notifications and wake up your app in the background on the user's device.