On this page

Mobile Push API for C SDK

Mobile Push Notifications connects PubNub channel traffic to Apple Push Notification service over HTTP/2 (APNS2) and Firebase Cloud Messaging (FCM). This page covers device registration only: associating a push token with one or more channels so that PubNub knows which devices to notify. pubnub_push_add_channels(), pubnub_push_remove_channels(), pubnub_push_list_channels(), and pubnub_push_remove_device() are the whole public API for this feature. No function anywhere in the SDK sends or builds a push notification.

To deliver a notification, publish a message whose JSON body contains a pn_apns and/or pn_fcm key, using the ordinary publish call. When PubNub finds one of those reserved keys in a published message, it looks up every device registered on that channel through the functions on this page and forwards the corresponding payload to APNs or FCM. The SDK does not validate or build the pn_apns/pn_fcm payload shape for you. Construct it yourself, as part of the JSON string you already pass to pubnub_publish():

#include <pubnub/client.h>
#include <pubnub/features/publish.h>
#include <pubnub/future.h>

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
pubnub_config_t cfg = pubnub_config_defaults();
cfg.publish_key = "demo";
cfg.subscribe_key = "demo";
cfg.user_id = "my_unique_user_id";

pubnub_context_t* ctx = pubnub_create(&cfg);
show all 41 lines

For the exact reserved-key payload shapes accepted by each provider, see Push Basics, iOS Mobile Push Notifications, and Android Mobile Push Notifications. Those pages describe a PubNub platform-wide convention, not something specific to this SDK.

Requires Mobile Push Notifications add-on

Every function on this page requires that Mobile Push Notifications is enabled for your key in the Admin Portal. See how to enable add-on features.

All four functions share #include <pubnub/features/push.h>. Each is gated behind the PUBNUB_ENABLE_PUSH_NOTIFICATIONS build flag, takes a context plus a const pointer to its own options struct, and returns a pubnub_future_t by value. Release it exactly once with pubnub_future_release(), whichever consumption style you use (cooperative polling, pubnub_await, or pubnub_async; see Status Events).

Add channels to a device

pubnub_push_add_channels() registers a device for push notifications on one or more channels.

Method(s)

#include <pubnub/features/push.h>

pubnub_future_t pubnub_push_add_channels(pubnub_context_t* ctx,
const pubnub_push_add_channels_opts_t* opts);
* required
ParameterDescription
device *
Type: const char*
Default:
Borrowed, NUL-terminated. Hexadecimal APNS device token or FCM registration token string. NULL or an empty string is rejected with PUBNUB_ERR_INVALID_ARGUMENT. No length limit is enforced.
gateway *
Type: pubnub_push_gateway_t
Default:
PUBNUB_PUSH_APNS2 or PUBNUB_PUSH_FCM.
channels *
Type: const char*
Default:
Borrowed, NUL-terminated. A single comma-separated list (e.g. "alerts,updates"), not an array. NULL or an empty string is rejected with PUBNUB_ERR_INVALID_ARGUMENT.
topic
Type: const char*
Default:
Borrowed, NUL-terminated. The APNs bundle identifier.
environment
Type: pubnub_push_environment_t
Default:
PUBNUB_PUSH_ENV_DEVELOPMENT
Ignored for FCM.
timeout_ms
Type: uint32_t
Default:
0 (inherits pubnub_config_t::transaction_timeout_ms)
Per-call timeout override.

Zero-initialize with PUBNUB_PUSH_ADD_CHANNELS_OPTS_INIT (expands to {0}).

C-family contract

  • Header#include <pubnub/features/push.h>
  • Typespubnub_push_add_channels_opts_t, pubnub_push_gateway_t, pubnub_push_environment_t
  • Prerequisite — an initialized context
  • Feature flagPUBNUB_ENABLE_PUSH_NOTIFICATIONS
  • Ownership / lifetimectx and opts are borrowed; device, channels, and topic are borrowed, caller-owned strings that must remain valid for the duration of the call
  • Blocking — never blocks; returns a pubnub_future_t immediately, possibly already in a terminal failed state (see below)
APNS2 and FCM enforce the topic/environment rule in opposite directions

Setting gateway to PUBNUB_PUSH_APNS2 with topic == NULL fails synchronously with PUBNUB_ERR_INVALID_ARGUMENT. The function returns before any network request is sent, and pubnub_future_is_ready() is already true. The reverse is not an error. Setting topic and/or a non-default environment while gateway is PUBNUB_PUSH_FCM is accepted without complaint: the SDK silently ignores both fields and sends neither in the request. This asymmetry applies identically to every function on this page.

Sample code

#include <pubnub/client.h>
#include <pubnub/features/push.h>
#include <pubnub/future.h>
#include <pubnub/response.h>

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
pubnub_config_t cfg = pubnub_config_defaults();
cfg.subscribe_key = "demo";
cfg.user_id = "example-push-add";

pubnub_context_t* ctx = pubnub_create(&cfg);
show all 43 lines

Returns

There is no result struct or payload accessor for this operation. Success is signaled entirely by the future's status: pubnub_future_status(future) == PUBNUB_OK. On failure, call pubnub_response_error_message() (or pubnub_response_service_error() for full detail) before releasing the future. See Retrieving server error detail.

Other examples

Register an APNS2 device

topic is required whenever gateway is PUBNUB_PUSH_APNS2; environment defaults to PUBNUB_PUSH_ENV_DEVELOPMENT if left unset.

pubnub_future_t register_apns2_device(pubnub_context_t* ctx)
{
return pubnub_push_add_channels(ctx,
&(pubnub_push_add_channels_opts_t){
.device = "apns-hex-device-token",
.gateway = PUBNUB_PUSH_APNS2,
.channels = "alerts",
.topic = "com.example.myapp",
.environment = PUBNUB_PUSH_ENV_PRODUCTION,
});
}

List channels registered for a device

pubnub_push_list_channels() retrieves every channel currently registered for push notifications on a given device.

Method(s)

#include <pubnub/features/push.h>

pubnub_future_t pubnub_push_list_channels(pubnub_context_t* ctx,
const pubnub_push_list_channels_opts_t* opts);

pubnub_push_list_channels_result_t
pubnub_push_list_channels_result(pubnub_future_t future);

pubnub_string_view_t pubnub_push_list_channels_result_channel_at(pubnub_future_t future,
size_t index);
* required
ParameterDescription
device *
Type: const char*
Default:
Borrowed, NUL-terminated. NULL or an empty string is rejected with PUBNUB_ERR_INVALID_ARGUMENT.
gateway *
Type: pubnub_push_gateway_t
Default:
PUBNUB_PUSH_APNS2 or PUBNUB_PUSH_FCM.
topic
Type: const char*
Default:
Borrowed, NUL-terminated.
environment
Type: pubnub_push_environment_t
Default:
PUBNUB_PUSH_ENV_DEVELOPMENT
Ignored for FCM.
start
Type: const char*
Default:
NULL (first page)
Borrowed, NUL-terminated pagination cursor.
count
Type: uint16_t
Default:
0 (server default, typically 500)
Maximum 1000.
timeout_ms
Type: uint32_t
Default:
0 (inherits pubnub_config_t::transaction_timeout_ms)
Per-call timeout override.

Zero-initialize with PUBNUB_PUSH_LIST_CHANNELS_OPTS_INIT (expands to {0}).

C-family contract

  • Header#include <pubnub/features/push.h>
  • Typespubnub_push_list_channels_opts_t, pubnub_push_list_channels_result_t
  • Prerequisite — an initialized context
  • Feature flagPUBNUB_ENABLE_PUSH_NOTIFICATIONS
  • Ownership / lifetimectx and opts are borrowed; every pubnub_string_view_t returned by pubnub_push_list_channels_result_channel_at() is a non-NUL-terminated view into memory owned by the future, valid only until pubnub_future_release()
  • Blocking — never blocks; returns a pubnub_future_t immediately

Sample code

#include <pubnub/client.h>
#include <pubnub/features/push.h>
#include <pubnub/future.h>
#include <pubnub/response.h>

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
pubnub_config_t cfg = pubnub_config_defaults();
cfg.subscribe_key = "demo";
cfg.user_id = "example-push-list";

show all 50 lines

Returns

pubnub_push_list_channels_result(future) returns a pubnub_push_list_channels_result_t by value, zero-initialized if the future is invalid or not yet ready:

FieldTypeDescription
channel_count
uint32_t
Number of channels registered for push on this device.

pubnub_push_list_channels_result_channel_at(future, index) returns the channel name at the given zero-based index as a pubnub_string_view_t, or a zero-initialized (empty) view for an out-of-range index. Read every view you need before calling pubnub_future_release(). The view becomes invalid afterward.

Other examples

List channels with an asynchronous callback

#include <pubnub/client.h>
#include <pubnub/error.h>
#include <pubnub/features/push.h>
#include <pubnub/future.h>
#include <pubnub/response.h>

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

static volatile int s_done;

static void on_list_complete(pubnub_future_t future, pubnub_res_t status, void* user_data)
{
(void)user_data;
show all 70 lines

On threaded platforms, a background thread drives I/O while you wait for the callback; on embedded builds without threads, replace the wait with a loop that calls pubnub_process(ctx). The completion callback matches the SDK-wide pubnub_async_cb_t signature: void (*)(pubnub_future_t future, pubnub_res_t status, void* user_data).

Remove channels from a device

pubnub_push_remove_channels() unregisters a device from push notifications on the specific channels named in channels. The device stays registered on any channel not listed. To remove a device from every channel at once, use Remove a device entirely instead.

Method(s)

#include <pubnub/features/push.h>

pubnub_future_t
pubnub_push_remove_channels(pubnub_context_t* ctx,
const pubnub_push_remove_channels_opts_t* opts);
* required
ParameterDescription
device *
Type: const char*
Default:
Borrowed, NUL-terminated. NULL or an empty string is rejected with PUBNUB_ERR_INVALID_ARGUMENT.
gateway *
Type: pubnub_push_gateway_t
Default:
PUBNUB_PUSH_APNS2 or PUBNUB_PUSH_FCM.
channels *
Type: const char*
Default:
Borrowed, NUL-terminated. A single comma-separated list of the channels to unregister. NULL or an empty string is rejected with PUBNUB_ERR_INVALID_ARGUMENT.
topic
Type: const char*
Default:
Borrowed, NUL-terminated.
environment
Type: pubnub_push_environment_t
Default:
PUBNUB_PUSH_ENV_DEVELOPMENT
Ignored for FCM.
timeout_ms
Type: uint32_t
Default:
0 (inherits pubnub_config_t::transaction_timeout_ms)
Per-call timeout override.

Zero-initialize with PUBNUB_PUSH_REMOVE_CHANNELS_OPTS_INIT (expands to {0}). The same APNS2/FCM topic and environment rule described above applies here unchanged.

C-family contract

  • Header#include <pubnub/features/push.h>
  • Typespubnub_push_remove_channels_opts_t, pubnub_push_gateway_t, pubnub_push_environment_t
  • Prerequisite — an initialized context
  • Feature flagPUBNUB_ENABLE_PUSH_NOTIFICATIONS
  • Ownership / lifetimectx and opts are borrowed; device, channels, and topic are borrowed, caller-owned strings
  • Blocking — never blocks; returns a pubnub_future_t immediately

Sample code

This sample demonstrates APNS2, the only combination that requires topic:

#include <pubnub/client.h>
#include <pubnub/features/push.h>
#include <pubnub/future.h>
#include <pubnub/response.h>

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
pubnub_config_t cfg = pubnub_config_defaults();
cfg.subscribe_key = "demo";
cfg.user_id = "example-push-remove";

pubnub_context_t* ctx = pubnub_create(&cfg);
show all 45 lines

Returns

There is no result struct or payload accessor for this operation. Success is signaled entirely by the future's status: pubnub_future_status(future) == PUBNUB_OK.

Remove a device entirely

pubnub_push_remove_device() removes the device's push registration completely, for every channel it was ever registered on, regardless of which channels those were. There is no channels field on this operation's options struct at all. That absence is what makes it structurally different from Remove channels from a device: that function narrows a registration, this function erases it.

Method(s)

#include <pubnub/features/push.h>

pubnub_future_t pubnub_push_remove_device(pubnub_context_t* ctx,
const pubnub_push_remove_device_opts_t* opts);
* required
ParameterDescription
device *
Type: const char*
Default:
Borrowed, NUL-terminated. NULL or an empty string is rejected with PUBNUB_ERR_INVALID_ARGUMENT.
gateway *
Type: pubnub_push_gateway_t
Default:
PUBNUB_PUSH_APNS2 or PUBNUB_PUSH_FCM.
topic
Type: const char*
Default:
Borrowed, NUL-terminated.
environment
Type: pubnub_push_environment_t
Default:
PUBNUB_PUSH_ENV_DEVELOPMENT
Ignored for FCM.
timeout_ms
Type: uint32_t
Default:
0 (inherits pubnub_config_t::transaction_timeout_ms)
Per-call timeout override.

Zero-initialize with PUBNUB_PUSH_REMOVE_DEVICE_OPTS_INIT (expands to {0}). The same APNS2/FCM topic and environment rule described above applies here unchanged.

C-family contract

  • Header#include <pubnub/features/push.h>
  • Typespubnub_push_remove_device_opts_t, pubnub_push_gateway_t, pubnub_push_environment_t
  • Prerequisite — an initialized context
  • Feature flagPUBNUB_ENABLE_PUSH_NOTIFICATIONS
  • Ownership / lifetimectx and opts are borrowed; device and topic are borrowed, caller-owned strings
  • Blocking — never blocks; returns a pubnub_future_t immediately

Sample code

#include <pubnub/client.h>
#include <pubnub/features/push.h>
#include <pubnub/future.h>
#include <pubnub/response.h>

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
pubnub_config_t cfg = pubnub_config_defaults();
cfg.subscribe_key = "demo";
cfg.user_id = "example-push-remove-device";

pubnub_context_t* ctx = pubnub_create(&cfg);
show all 42 lines

Returns

There is no result struct or payload accessor for this operation. Success is signaled entirely by the future's status: pubnub_future_status(future) == PUBNUB_OK.

Error handling

pubnub_res_t is the single status type shared across every feature in this SDK, including Mobile Push. There are no per-feature error accessors. For the full result-code catalog and the pubnub_response_service_error() pattern for server-side error detail, see Status Events.

Behaviors specific to the four functions on this page:

  • opts == NULL, an invalid or uninitialized ctx, a NULL/empty device, or (on pubnub_push_add_channels/pubnub_push_remove_channels) a NULL/empty channels all fail immediately with PUBNUB_ERR_INVALID_ARGUMENT, readable via pubnub_future_status() without polling, awaiting, or sending any request.
  • gateway == PUBNUB_PUSH_APNS2 with topic == NULL fails the same way, on all four functions. See the APNS2/FCM rule above.
  • On the wire, an HTTP status of 400 or higher maps to PUBNUB_ERR_SERVER, as does a 200 response whose body reports a logical failure. The exact wire shape that triggers this on a 200 response (for example, add_channels/remove_channels/remove_device probing the leading status digit of an array-shaped body) is an internal parsing detail, not a public contract, and could change without notice. Don't rely on it: call pubnub_response_service_error() for normalized detail regardless of which case produced it.