C++Windows C++Windows C++Posix C++Windows C++ Configuration API Reference for Realtime Apps

Windows C++ complete API reference for building Realtime Applications on PubNub, including basic usage and sample code.

This documents the preprocessor definitions (macros) which are configuration options of C-core, which are kept in the pubnub_config.h header file. This header file is different for each platform. For some platforms, the definitions that "don't make sense" may be omitted from the header file.

Any definitions that you may find in pubnub_config.h, that are not listed here, should not be changed by the user.

Maximum number of PubNub contexts that can be used at the same time. It is used only if the contexts are statically allocated. The default on hosted platforms (POSIX, Windows…) is to use dynamically allocated contexts, so this is ignored. This is selected by linking in the "context allocation module" that you wish to use (static or dynamic).

A context is used to publish messages or subscribe to (get) them.

Each context can consume (for our purposes) a significant amount of memory, so don't put some number that is never going to be achieved here.

A typical configuration may consist of a single pubnub context for channel subscription and another pubnub context that will periodically publish messages about device status (with timeout lower than message generation frequency). This only needs two contexts.

Another typical setup may have a single subscription context and maintain a pool of contexts for each publish call triggered by an external event (e.g. a button push). This would need N+1 contexts, N being the number of external events.

Of course, there is nothing wrong with having just one context, but you can't publish and subscribe at the same time on the same context. This isn't as bad as it sounds, but may be a source of headaches (lost messages, etc).

Size, in octets, of the HTTP buffer. This is a major component of the memory size of the whole Pubnub context, but it is also an upper bound on URL-encoded form of published message, so if you need to construct big messages, you may need to raise this. So, if you need to publish only messages of up to 2Kb size, you don't need more than, say 2500 PUBNUB_BUF_MAXLEN. But, if you need to publish messages larger than 2Kb size, you would need a bigger buffer.

It is designed to be "settable" from the compiler options, with the value in the header being the default. But, it's perfectly fine to not set it in the compiler options but change its ("default") value in here.

Set to false (0) to use a static buffer and then set its size via PUBNUB_REPLY_MAXLEN. Set to true (anything !=0) to use a dynamic buffer, that is, dynamically try to allocate as much memory as needed for the buffer.

Default on hosted platforms (Windows, POSIX…) is to use dynamic reply buffer. But, be warned, this can be a lot of data, megabytes, even. If you don't really have that much memory to spare, you may be better of with the static reply butt. OTOH, if the reply is too long for your statically allocated buffer, your transaction will, effectively, fail. So, this is a trade-off that is specific to your application.

This is only significant if PUBNUB_DYNAMIC_REPLY_BUFFER is true. In that case it defines the size, in octets, of the reply buffer. It will hold the whole (HTTP) body of the reply, not the (HTTP) headers.

Replies of API calls longer than this will be discarded and an error will be reported. Specifically, this may cause lost messages returned by subscribe if too many too large messages got queued on the Pubnub server.

This is the string of the DNS hostname of the Pubnub network. In general, you should not change this. Also, if thus configured (see PUBNUB_ORIGIN_SETTABLE), you can change the origin at runtime.

But, in the case that you do need to change it at compile time, but not at runtime and want to save some RAM in the context, it's OK to change this macro.

If true (!=0), user will be able to change the origin at runtime. This incurs a small "memory penalty", of keeping the runtime origin in the context. This is the default, as the "penalty" is small.

If false (==0), user will not be able to change the origin at runtime. Use this if you need to squeeze the RAM memory footprint of C-core.

Duration of the transaction timeout set during context initialization, in milliseconds. Timeout duration in the context can be changed by the user after initialization (at runtime).

This is only used if timers support is used, which is the default on hosted platforms (POSIX, Windows…).

The size of the stack (in kilobytes) for the "polling" thread, when using the callback interface. We don't need much, so, if you want to conserve memory, you can try small values. It's hard to say what is the minimum, as it depends on the OS functions we call, but, you probably shouldn't try less than 64 KB.

Set to 0 to use the default stack size.

This is ignored when using the sync interface.

Set to true (!=0) to enable the proxy support. This is the default on hosted platforms (Windows, POSIX…). To actually use your proxy, you need to set proxy parameters (host, port, protocol….) with the appropriate C-core APIs.

Set to false (==0) to disable the proxy support. This can provide for significant code savings, which may be important if you wish the cut down the code/flash footprint.

Keep in mind that, depending on how you build C-core, this may not be enough. That is, you might also need to not compile and link the proxy modules. This is illustrated in the sample makefiles.

The maximum length (in characters) of the host name of the proxy that will be saved in the Pubnub context. Set this according to your proxy (or your "possible future proxies"). It's one "proxy hostname" per context, so, don't put kilobytes here "just in case", unless you know you can spare RAM.

Set to true (!=0) to use only the Publish and Subscribe transactions. Set to false to use all the available Pubnub transactions - this is the default on hosted (POSIX, Windows…) platforms.

This can provide for significant code size savings, if you don’t need anything more than publish and subscribes, which may be important if you wish the cut down the code/flash footprint.

Keep in mind that this is not "fully self contained". If you try to compile modules that are not needed when PUBNUB_ONLY_PUBSUB is true, you’ll get a warning. If you actually link them, you will only save the code memory if your linker discards modules that are not used - in general, that is what linkers do, but it depends on your linker and the options you pass to it.

This is designed to be set via compiler options, with the value in the header file being the default. But, there is nothing wrong with setting it in the header itself.

We recommend you use the Makefiles as a starting point in your own projects (whether they are based on Make or some other build tool / system or IDE).

The Makefile to build for Windows C++ is available at windows.mk. Please take a look at /cpp/README.md for general info about the repo layout & contents.

The Makefile for Windows C++ with SSL/TLS (via OpenSSL) is available at windows_openssl.mk in the repo. See README.md for info on how to build w/OpenSSL on Windows C++ and other OpenSSL related data.

To include the PubNub Windows C++ headers into your app, you must include pubnub.hpp:

#include "pubnub.hpp"

Once the header has been included, its easy to make calls to the PubNub service via the Windows C++ API. The PubNub Windows C++ API is very flexible, supporting many different calling patterns. As such, before we dive in to actual coding samples, its important to go over the different types of calling patterns provided by the PubNub Windows C++ client's futures support.

The pubnub::futres class name is a portmanteau, blending C++ future with enum pubnub_res. It was purposely not named pubnub::future to avoid namespacing conflicts.

Both POSIX and Windows C++ SDKs use the pubnub::futres class, based on the std::future class (introduced in C++ 11) which provides a way to track the outcome of an operation asynchronously. Every operation that the SDK initiates with PubNub Data Stream Network returns a futures object. This object allows to track the progress and completion of the operation via the status identifiers.

There are several ways to use futures synchronously:

  • Single await() or get()
  • Separated start_await() and end_await()
  • Your own last_result() loop

The pubnub::futres::await() method, similar to the pubnub_await() function from the C sync interface, is used to await the outcome of a transaction/operation. Since its function is the same as std::future<>::get(), we provide a synonym, and you can call pubnub::futres::get() with the same effect.

pubnub::context pb("demo", "demo");
pubnub::futres f = pb.publish("hello_world", "\"Here I am!\"");
if (PNR_OK == f.await()) {
	std::cout << "Published OK" << std::endl;
pubnub::futres f = pb.publish("hello_world", "\"Stuck in the middle\"");
if (PNR_OK == f.get()) {
	std::cout << "Published OK (again)" << std::endl;

You don't have to await at once. You can start the await, and finish later. This is useful if you are working with more than one context, so you start an operation on one context, then start the await on that context, proceed to start an operation on another context and then end the started await.

pubnub::context pb("demo", "demo");
pubnub::context pbsub("demo", "demo");
pbsub.subscribe("hello_world").await();  // connect
pubnub::futres fsub = pbsub.subscribe("hello_world");
pubnub::futres f = pb.publish("hello_world", "\"with you!\"");
if (PNR_OK == f.await()) {
	std::cout << "Published OK" << std::endl;
if (PNR_OK == fsub.end_await()) {
	std::cout << "Received messages:" << std::endl;
	for (auto &&msg : pbsub.get_all()) {
		std::cout << msg << std::endl;

You don't have to use the await() functions. You can call last_result() in a loop and perform other operations. If you aren't doing other operations, this pattern won't be that useful for you -- in that case, just call await().

pubnub::context pb("demo", "demo");
pubnub::futres f = pb.publish("hello_world", "\"Waiting for Godot\"");
for (;;) {
	pubnub_res result = f.last_result();
	if (result() == PNR_STARTED) {
		// Do something while we wait
	else if (PNR_OK == f.get()) {
		std::cout << "Published OK" << std::endl;

All asynchronous logic is built upon pubnub::futres::then() (similar to what is available in some future libraries, and proposed for addition to C++17). There are several ways to use futures asynchronously:

  • Using futures with a callback
  • Using futures with a lambda
  • Using futures with a function object

By providing a free function or a static class method, you'll be using the C++ client similarly to that of the C callback interface.

static void on_publish(pubnub::context &pb, pubnub_res result)
	if (PNR_OK == result) {
          std::cout << "Published OK" << std::endl;

int main(int argc, char *argv[])
	pubnub::context pb("demo", "demo");
	pubnub::futres f = pb.publish("hello_world", "\"Don't call us\"");
	return 0;

Instead of a function, you can also pass a lambda to pubnub::futres::then:

pubnub::context pb("demo", "demo");
pubnub::futres f = pb.publish("hello_world", "\"Lambda\"");
f.then([=](pubnub::context &pb, pubnub_res result) {
	if (PNR_OK == result) {
		std::cout << "Published OK" << std::endl;
	pubnub::futres f2 = pb.publish("hello_world", "\"the ultimate\"");
	f2.then([=](pubnub::context &pb, pubnub_res result) {
		if (PNR_OK == result) {
			std::cout << "Published OK (nested)" << std::endl;

You can pass a callable object to pubnub::futres::then() - that is, an object of a class with an overloaded function call operator:

class bean_counter {
	int beans;
		bean_counter() : beans(0) {}
		void operator()(pubnub::context &pb, pubnub_res result) {
			if (PNR_OK == result) {
	      		std::cout << "Published " << beans << " beans" << std::endl;

int main(int argc, char *argv[])
	pubnub::context pb("demo", "demo");
	bean_counter hermes_conrad;
	for (int i = 0; i < 1000; ++i) {
		pubnub::futres f = pb.publish("hello_world", "\"Stamp\"");
	return 0;

Since std::function<> is a generic function object, if you have one, just pass it to pubnub::futres::then:

void planet_express(std::function<void(pubnub::context&,pubnub_res)> parcel)
	pubnub::context pb("demo", "demo");
	pubnub::futres f = pb.publish("hello_world", "\"Deliver\"");

This client uses dynamic memory allocation for the Pubnub contexts, but the usage is the same as for any other Pubnub C client - always use pubnub_alloc() to create a context (and check its return value) and always use pubnub_free() to dispose of a context.

#include "pubnub_alloc.h"
#include <stdio.h>
int main()
    pubnub_t *ctx = pubnub_alloc();
    if (NULL == ctx) {
        puts("Couldn't allocate a Pubnub context");
        return -1;
    /* Do something with ctx… 
        and then: */
    return 0

We only provide one timer - the (total) transaction timer. In general, it is started when a transaction is started and stopped when a transaction is finished. If it expires, the transaction will be cancelled. Keep in mind that this canceling is local, so, for example, if you already published a message, but, for some reason, the HTTP response didn't arrive in time, this canceling will not revoke the publish - it will just stop the wait for response.

If the transaction timer expires, the outcome of the transaction will be timeout - different than when you cancel a transaction yourself.

The actual duration of the timer is at least as long as you set it. It could be significantly higher, depending on various platform issues. But, in general, it will be close to what you set.

You should set the timer after initializing the context and before starting a transaction. The duration you set will be used for all subsequent transactions, regardless of their type (i.e. for publish and subscribe and all other).

C-core supports thread-safe operation, though, for performance, you may think about not using it. To use thread-safety support, define the preprocessor symbol PUBNUB_THREADSAFE (just define it, the value does not matter).

Thread safety is internal. Just because you can access the pubnub context through the Pubnub C-core SDK API from different threads safely, doesn't mean you're off the hook for your own data that is related to a context. For example, if you're using the callback interface and signalling an event from it to other (worker) thread(s), you have to synchronise that data transfer yourself.

If you compiled thread-safety support in, you are free to access the same context from different threads, pretty much in any way you wish. However, there are some advised guidelines you should follow:

  • If you're using the sync blocking interface, threads that come to wait on the context may wait a long time, so try to avoid it (also, re-think your whole need for a thread-safe C-core)
  • If you're using the sync non-blocking interface by calling pubnub_await, things are pretty much the same as for sync blocking interface
  • If you're using the sync non-blocking interface and avoid pubnub_await, waiting threads will not block so long, but, pretty much the only useful thing you can do is cancel a transaction from another thread.
  • Using the sync interface, it's perfectly fine to call pubnub_await or pubnub_last_result in different threads, but, you probably shouldn't do that, as it will make debugging harder.
  • If you're using the callback interface, it's perfectly fine to call pubnub functions from your callback, but, you should avoid doing that, except for some helper functions. Following this guideline will make your debugging, thus life, a lot easier

If you compile without thread-safety support, obviously, you will have an SDK which is not thread safe - that is, it is not safe to use a single context from more than one thread at the same time. So, if you're using such SDK configuration in a multithreaded code, which, on WINDOWS, you likely are, then:

  1. If at all possible, use a single context from only one thread - the one that created it
  2. If 1. is not possible, provide some synchronization yourself, for example, using pthread condition variables, or just mutexes, or some higher abstraction, like message queues
  3. As a special case, if you're using the callback interface, you can start a transaction in one thread and then don't touch the context from that thread any more - use it only in the callback. This is safe.
Keep in mind that it is perfectly safe to use different contexts from different threads at the same time. To each (thread) its own (context).

Keep in mind that it is perfectly safe to use different contexts from different threads at the same time. To each (thread) its own (context).

The Windows C++ SDK operates as a set of transactions. A transaction is initiated by the client SDK and is defined as a single message exchange between the SDK and PubNub service. Every interaction that the client SDK initiates with PubNub is sequenced as a series of transactions which ultimately results in a PubNub service-specific operation.

The SDK provides a set of status and event identifiers which can help developers interact with the library. The status identifier codes are returned as part of the SDK's API invocation. These are used by the developer to check for status of transactions or for detecting normal / abnormal conditions in an API call. Some of the commonly used status codes are as follows.

  1. PNR_OK : Success, the transaction finished successfully
  2. PNR_STARTED : The previously initiated transaction has started.
  3. PNR_IN_PROGRESS : Indicates that the previous transaction with PubNub service is still in progress.

Refer to the API docs for a complete list of status identifiers supported by the library.

Events refer to the PubNub REST operations which are initiated by the client SDK. The most common example of events are subscribe and publish. A client subscribing for a channel is a subscribe event and a client publishing a message on a channel is a publish event.

Some of the common event identifiers are as follows:

  1. PBTT_SUBSCRIBE : Subscriber operation
  2. PBTT_PUBLISH : Publish operation

Refer to the API docs for a complete list of operations supported by the SDK.

This SDK provides sync and callback (notification) interfaces for retrieving the outcome of a Pubnub request/transaction/operation.

The sync interface works like this:

  1. Start a transaction (say, publish - using pubnub_publish())
  2. Either pubnub_await() the outcome, or use your own loop in which you check if (PNR_STARTED != pubnub_last_result())
  3. Handle the outcome as you wish

This is illustrated in the Hello World example below (which is the same for any platform that supports sync interface).

The callback interface is somewhat more flexible, uses less CPU resources, but is, in general, a little harder to use. One way to use it is to emulate the sync interface:

  1. Create a callback function (my_callback) per the prototype required by pubnub_register_callback()
  2. In my_callback(), use a condition variable to signal that outcome was received
  3. Set the callback via pubnub_register_callback()
  4. Start a transaction (say, publish - using pubnub_publish())
  5. Wait on the condition variable (the same one used in my_callback)
  6. Handle the outcome as you wish

This is illustrated in the Hello World example below, using pthreads condition variable. Obviously, on platforms that don't support pthreads you will use some similar API (for example, SetEvent/WaitForSingleObject on Windows).

There are other ways to use the callback interface, like the state machine or similar, where the callback will handle the outcome of a transaction but will also start the next Pubnub transaction, or do other stuff that it needs to do. This is very application specific, so we don't provide an example here.

This function is used for initializing the PubNub Client API context. This function must be called before attempting to utilize any API functionality in order to establish account level credentials such as publish_key and subscribe_key.
To Initialize Pubnub you can use the following method(s) in the Windows C++ SDK:
  1. ParameterTypeRequiredDescription
    publish_keystd::stringYesSpecifies the required publish_key to be used only when publishing messages to a channel. This key can not be specified if the client will not publish data to any channel, just use an empty string in this case.
    subscribe_keystd::stringYesSpecifies the required subscribe_key to be used for subscribing to a channel.
pubnub::context pn("my_pubkey", "my_subkey");

pn.set_ssl_options(pubnub::useSSL | pubnub::reduceSecurityOnError|pubnub::ignoreSecureConnectionRequirement);
It returns the Pubnub instance for invoking PubNub APIs like publish(), subscribe(), history(), here_now(), etc.
  1. pubnub::context pn("my_pubkey", "my_subkey");
  2. In the case where a client will only read messages and never publish to a channel, you can simply omit the publish_key when initializing the client:
    pubnub::context pn("", "my_subkey");
  3. Set a custom UUID to identify your users.
    pubnub::context pn("myPublishKey", "mySubscribeKey");
  4. This examples demonstrates how to enable PubNub Transport Layer Encryption with SSL. Just initialize the client with 1st set to true. The hard work is done, now the PubNub API takes care of the rest. Just subscribe and publish as usual and you are good to go.

    pubnub::context pn("my_pubkey", "my_subkey");
    pn.set_ssl_options(pubnub::useSSL | pubnub::reduceSecurityOnError|pubnub::ignoreSecureConnectionRequirement);
These functions are used to set/get a user ID on the fly.
To set/get UUID you can use the following method(s) in Windows C++ SDK
  1. ParameterTypeRequiredDescription
    uuidstd::string const &YesUUID
std::string uuid("myUniqueUUID");
std::cout << pn.uuid() << std::endl;
  1. Get UUID returns the following output:
    std::string const&It's an empty string if UUID is not set.
  1.  pubnub::context pn("demo", "demo");
      struct Pubnub_UUID uuid;
      std::string channel_name;
      if (0 == pubnub_generate_uuid_v4_random(&uuid)) {
        channel_name = pubnub_uuid_to_string(&uuid).uuid;
      pubnub_res res = pn.subscribe(channel_name).await();
      if (res != PNR_OK) {
        std::cout << "Failed to subscribe, error " << res << std::endl;
      } else {
        std::string msg = pn.get();
        std::string channel = pn.get_channel();
        while (msg != "") {
          std::cout << "Got message: " << msg << " on channel " << channel << std::endl;
          std::string msg = pn.get();
          std::string channel = pn.get_channel();
  2. pubnub::context pn("myPublishKey", "mySubscribeKey");
    struct Pubnub_UUID uuid;
    std::string random_uuid;
    if (0 == pubnub_generate_uuid_v4_random(&uuid)) {
      random_uuid = pubnub_uuid_to_string(&uuid).uuid;
  3. pubnub::context pn("demo", "demo");
    struct Pubnub_UUID uuid;
    std::string auth_key;
    if (0 == pubnub_generate_uuid_v4_random(&uuid)) {
      auth_key = pubnub_uuid_to_string(&uuid).uuid;
Setter and getter for users auth key.
  1. ParameterTypeRequiredDescription
    auth_keystd::string const &YesNew auth key.
  2. auth();
std::string auth_key = pn.auth();
Get Auth key returns the current authentication key.

Sets the origin to be used for the context. If setting of the origin is not enabled, this will fail. It may also fail if it detects an invalid origin. To reset to the default origin, pass an empty string.

To set the origin for a Pubnub context use:
  1. ParameterTypeRequiredDescription
    Originstd::string const&YesThe origin to use for the context. If empty, the default origin will be set

To set the origin to the European data center explicitly:

int0: success, -1: fail
Sets the SSL options for a context.
  1. ParameterTypeRequiredDescription
    optpubnub::ssl_optYesSpecifies bitwise option:
    • pubnub::useSSL
    • pubnub::ignoreSecureConnectionRequirement
pn.set_ssl_options(pubnub:useSSL | pubnub::ignoreSecureConnectionRequirement);