---
source_url: https://www.pubnub.com/docs/sdks/unity/api-reference/publish-and-subscribe
title: Publish/Subscribe API for Unity SDK
updated_at: 2026-06-05T11:13:33.605Z
sdk_name: PubNub Unity SDK
sdk_version: v9.3.0
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Publish/Subscribe API for Unity SDK

PubNub Unity SDK, use the latest version: v9.3.0

PubNub delivers messages worldwide in less than 30 ms. Send a message to one recipient or broadcast to thousands of subscribers.

For higher-level conceptual details on publishing and subscribing, refer to [Connection Management](https://www.pubnub.com/docs/general/setup/connection-management) and to [Publish Messages](https://www.pubnub.com/docs/general/messages/publish).

## Publish

`publish()` sends a message to all channel subscribers. PubNub replicates the message across its points of presence and delivers it to all subscribed clients on that channel.

### Prerequisites and limitations

* You must [initialize PubNub](https://www.pubnub.com/docs/sdks/unity/api-reference/configuration#configuration) with the `publishKey`.
* You don't have to be subscribed to a channel to publish to it.
* You cannot publish to multiple channels simultaneously.

### Security

Secure messages with Transport Layer Security (TLS) or Secure Sockets Layer (SSL) by setting `ssl` to `true` during [initialization](https://www.pubnub.com/docs/sdks/unity/api-reference/configuration#configuration). You can also [encrypt](https://www.pubnub.com/docs/sdks/unity/api-reference/configuration#cryptomodule) messages.

### Message data

The message can contain any JavaScript Object Notation (JSON)-serializable data (objects, arrays, integers, strings). Avoid Unity-specific classes or functions. Strings can include any UTF‑8 characters.

:::warning Don't JSON serialize
You should not JSON serialize the `message` and `meta` parameters when sending signals, messages, or files as the serialization is automatic. Pass the full object as the message/meta payload and let PubNub handle everything.
:::

### Size

The maximum message size is 32 KiB, including the channel name and the escaped characters. Aim for under 1,800 bytes for optimal performance.

If your message exceeds the limit, you'll receive a `Message Too Large` error. To learn more or calculate payload size, see [Message size limits](https://www.pubnub.com/docs/general/messages/publish#message-size-limit).

:::tip Need larger messages?
Our platform is optimized for payloads up to 32 KiB. PubNub supports larger messages, but increasing the limit requires a verification of compatibility with your use case.
Talk to [our team](https://www.pubnub.com/company/contact-sales/) to discuss increasing the message size limit for your use case.
:::

### Publish rate

You can publish as fast as bandwidth allows. There is a [soft throughput limit](https://www.pubnub.com/docs/general/setup/limits) because messages may drop if subscribers can't keep up.

For example, publishing 200 messages at once may cause the first 100 to drop if a subscriber hasn't received any yet. The in-memory queue stores only 100 messages.

### Message serialization

Sending structures with circular references (like Vector3) may cause issues depending on your JSON library settings. In those cases, you can use the `GetJsonSafe()` extension method included in the PubNub namespace.

```csharp
pubnub.Publish().Channel(defaultChannel).Message(transform.GetJsonSafe()).Execute((a, b) => { });
pubnub.Publish().Channel(defaultChannel).Message(transform.position.GetJsonSafe()).Execute((a, b) => { });
pubnub.Publish().Channel(defaultChannel).Message(transform.localRotation.GetJsonSafe()).Execute((a, b) => { });
```

### Custom message type

You can optionally provide the `CustomMessageType` parameter to add your business-specific label or category to the message, for example `text`, `action`, or `poll`.

### Best practices

* Publish to a channel serially (not concurrently).
* Verify a success return code (for example, `[1,"Sent","136074940..."]`).
* Publish the next message only after a success return code.
* On failure (`[0,"blah","<timetoken>"]`), retry.
* Keep the in-memory queue under 100 messages to avoid drops.
* Throttle bursts to meet latency needs (for example, no more than 5 messages per second).

### Method(s)

To `Publish a message` you can use the following method(s) in the Unity SDK:

```csharp
pubnub.Publish()
    .Message(object)
    .Channel(string)
    .ShouldStore(bool)
    .Meta(Dictionary<string, object>)
    .UsePOST(bool)
    .Ttl(int)
    .QueryParam(Dictionary<string,object>)
    .CustomMessageType(string)
    .Execute(System.Action<PNPublishResult, PNStatus>)
```

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| Message | object | Yes |  | The payload. |
| Channel | string | Yes |  | Destination of the `Message` (channel ID). |
| ShouldStore | bool | Optional |  | Store in history. If `ShouldStore` is not specified, then the history configuration on the key is used. |
| Meta | Dictionary<string, | Optional |  | `Meta` data object which can be used with the filtering ability. |
| UsePOST | bool | Optional |  | Use POST to `Publish`. |
| Ttl | int | Optional |  | Set a per message time to live in storage. If ShouldStore = true, and Ttl = 0, the message is stored with no expiry time., If ShouldStore = true and Ttl = X (X is an Integer value), the message is stored with an expiry time of X hours unless you have message retention set to Unlimited on your keyset configuration in the Admin Portal., If ShouldStore = false, the Ttl parameter is ignored., If Ttl is not specified, then expiration of the message defaults back to the expiry value for the key. |
| QueryParam | Dictionary<string, | Optional |  | Dictionary `object` to pass name/value pairs as query `string` params with PubNub URL request for debug purpose. |
| CustomMessageType | string | Optional |  | A case-sensitive, alphanumeric string from 3 to 50 characters describing the business-specific label or category of the message. Dashes `-` and underscores `_` are allowed. The value cannot start with special characters or the string `pn_` or `pn-`. Examples: `text`, `action`, `poll`. |
| Sync | Command | Optional |  | Block the thread, exception thrown if something goes wrong. |
| Async | PNCallback | Optional |  | PNCallback of type PNPublishResult. |
| Execute | System.Action | Optional |  | `System.Action` of type `PNPublishResult`. |
| ExecuteAsync | None | Optional |  | Returns `Task<PNResult<PNPublishResult>>`. |

### Sample code

#### Publish a message to a channel

:::tip Reference code
This example is a self-contained code snippet ready to be run. It includes necessary imports and executes methods with console logging. Use it as a reference when working with other examples in this document.
:::

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

try
{
    // Publishing a message to a channel
    Dictionary<string, float> position = new Dictionary<string, float>
    {
        { "lat", 32F },
        { "lng", 32F }
    };

    Debug.Log("before pub: " + pubnub.JsonPluggableLibrary.SerializeToJsonString(position));

    PNResult<PNPublishResult> publishResponse = await pubnub.Publish()
        .Message(position)
        .Channel("my_channel")
        .CustomMessageType("text-message")
        .ExecuteAsync();

    PNPublishResult publishResult = publishResponse.Result;
    PNStatus status = publishResponse.Status;

    if (!status.Error)
    {
        Debug.Log("pub timetoken: " + publishResult.Timetoken.ToString());
        Debug.Log("pub status code : " + status.StatusCode.ToString());
    }
    else
    {
        Debug.LogError("Error occurred: " + pubnub.JsonPluggableLibrary.SerializeToJsonString(status));
    }
}
catch (Exception ex)
{
    Debug.LogError($"Request cannot be executed due to error: {ex.Message}");
}
```

:::note Subscribe to the channel
Before running the above publish example, either using the [Debug Console](https://www.pubnub.com/docs/console/) or in a separate script running in a separate terminal window, [subscribe to the same channel](#subscribe) that is being published to.
:::

### Returns

The `Publish()` operation returns a `PNResult<PNPublishResult>` which contains the following properties:

| Property Name | Type | Description |
| --- | --- | --- |
| `Result` | PNPublishResult | Returns a `PNPublishResult` object. |
| `Status` | `PNStatus` | Returns a `PNStatus` object. |

`PNPublishResult` contains the following properties:

| Property Name | Type | Description |
| --- | --- | --- |
| `Timetoken` | long | Returns a `long` representation of the timetoken when the message was published. |

### Other examples

#### Publish a message to a channel synchronously

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

//Publishing Dictionary
Dictionary<string, float> position = new Dictionary<string, float>();
position.Add("lat", 32F);
position.Add("lng", 32F);

Debug.Log("before pub: " + pubnub.JsonPluggableLibrary.SerializeToJsonString(position));

pubnub.Publish()
    .Message(position)
    .Channel("my_channel")
    .CustomMessageType("text-message")
    .Execute(new PNPublishResultExt(
        (result, status) =>
        {
            Debug.Log("pub timetoken: " + result.Timetoken.ToString());
            Debug.Log("pub status code : " + status.StatusCode.ToString());
        }
    ));
```

#### Publish with metadata

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

string[] arrayMessage = new string[]
{
    "hello",
    "there"
};

pubnub.Publish()
    .Message(arrayMessage.ToList())
    .Channel("suchChannel")
    .ShouldStore(true)
    .Meta(new Dictionary<string, object>() { { "someKey", "someValue" } })
    .UsePOST(true)
    .CustomMessageType("text-message")
    .Execute(new PNPublishResultExt(
        (result, status) =>
        {
            // handle publish result, status always present, result if successful
            // status.Error to see if error happened
        }
    ));
```

#### Store the published message for 10 hours

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

var publishResult = await pubnub.Publish()
    .Channel("coolChannel")
    .Message("test")
    .ShouldStore(true)
    .Ttl(10)
    .ExecuteAsync();
```

#### Publishing messages for receipt on FCM and APNS associated devices, sample payload

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

public class MobilePayload
{
    public Dictionary<string, object> pn_apns;
    public Dictionary<string, object> pn_gcm;
    public Dictionary<string, object> full_game;
}

public static void PublishMobilePayload()
{
    Dictionary<string, object> apnsData = new Dictionary<string, object>();
    apnsData.Add("aps", new Dictionary<string, object>()
    {
        { "alert", "Game update 49ers touchdown" },
        { "badge", 2 }
    });
    apnsData.Add("teams", new string[] { "49ers", "raiders" });
    apnsData.Add("score", new int[] { 7, 0 });

    Dictionary<string, object> gcmData = new Dictionary<string, object>();
    gcmData.Add("data", new Dictionary<string, object>()
    {
        {
            "summary", "Game update 49ers touchdown"
        },
        {
            "teams", new string[] { "49ers", "raiders" }
        },
        {
            "score", new int[] { 7, 0 }
        },
        {
            "lastplay", "5yd run up the middle"
        },
    });

    MobilePayload mobilePayload = new MobilePayload();
    mobilePayload.pn_apns = apnsData;
    mobilePayload.pn_gcm = gcmData;
    mobilePayload.full_game = new Dictionary<string, object>()
    {
        { "date", "2014.05.20" },
        { "foobar", "Data that is not pertinent to devices" }
    };

    pubnub.Publish()
        .Message(mobilePayload)
        .Channel("my_channel")
        .ShouldStore(true)
        .CustomMessageType("text-message")
        .Execute(new PNPublishResultExt(
            (result, status) =>
            {
                // Check whether request successfully completed or not.
                if (status.Error)
                {
                    // something bad happened.
                    Debug.Log(
                        $"error while publishing: {pubnub.JsonPluggableLibrary.SerializeToJsonString(status)}");
                }
                else
                {
                    Debug.Log($"published with timetoken: {result.Timetoken}");
                }
            }
        ));
}
```

For more details, refer to [Mobile Push](https://www.pubnub.com/docs/general/push/send).

## Fire

The fire endpoint sends a message to Functions event handlers and [Illuminate](https://www.pubnub.com/docs/illuminate/business-objects/external-data-sources). The message goes directly to handlers registered on the target channel and triggers their execution. The handler can read the request body. Messages sent via `fire()` aren't replicated to subscribers and aren't stored in history.

### Method(s)

To `Fire a message` you can use the following method(s) in the Unity SDK:

```csharp
pubnub.Fire()
    .Message(object)
    .Channel(string)
    .Meta(Dictionary<string, object>)
    .UsePOST(bool)
    .QueryParam(Dictionary<string,object>)
    .Execute(System.Action<PNPublishResult, PNStatus>)
```

| Parameter | Description |
| --- | --- |
| `Message` *Type: object | The payload. |
| `Channel` *Type: string | Destination of the `message` (channel ID). |
| `Meta`Type: Dictionary`<string, object>` | `Meta` data object which can be used with the filtering ability. |
| `UsePOST`Type: bool | Use POST to `Publish`. |
| `QueryParam`Type: Dictionary`<string, object>` | Dictionary `object` to pass name/value pairs as query `string` params with PubNub URL request for debug purpose. |
| `Sync`Type: Command | Block the thread, exception thrown if something goes wrong. |
| AsyncType: PNCallback | PNCallback of type PNPublishResult |
| `Execute`Type: `System.Action` | `System.Action` of type `PNPublishResult` |
| `ExecuteAsync`Type: None | Returns `Task<PNResult<PNPublishResult>>`. |

### Sample code

#### Fire a message to a channel

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

string[] arrMessage = new string[]
{
    "hello",
    "there"
};

pubnub.Fire()
    .Message(arrMessage.ToList())
    .Channel("my-channel")
    .UsePOST(true)
    .Execute(new PNPublishResultExt(
        (result, status) =>
        {
            if (status.Error)
            {
                Debug.Log(
                    $"error while publishing: {pubnub.JsonPluggableLibrary.SerializeToJsonString(status)}");
            }
            else
            {
                Debug.Log($"published with timetoken: {result.Timetoken}");
            }
        }
    ));
```

## Signal

The `signal()` function sends a signal to all subscribers of a channel.

By default, signals are limited to a message payload size of `64` bytes. This limit applies only to the payload, and not to the URI or headers. If you require a larger payload size, please [contact support](https://www.pubnub.com/docs/mailto:support@pubnub.com).

### Method(s)

To `Signal a message` you can use the following method(s) in the Unity SDK:

```csharp
pubnub.Signal()
    .Message(object)
    .Channel(string)
    .CustomMessageType(string)
    .Execute(System.Action<PNPublishResult, PNStatus>)
```

| Parameter | Description |
| --- | --- |
| `Message` *Type: object | The payload. |
| `Channel` *Type: string | Destination of the `Message` (channel ID). |
| `CustomMessageType`Type: string | A case-sensitive, alphanumeric string from 3 to 50 characters describing the business-specific label or category of the message. Dashes `-` and underscores `_` are allowed. The value cannot start with special characters or the string `pn_` or `pn-`. Examples: `text`, `action`, `poll`. |
| `Execute`Type: `System.Action` | `System.Action` of type `PNPublishResult`. |
| `ExecuteAsync`Type: None | Returns `Task<PNResult<PNPublishResult>>`. |

### Sample code

#### Signal a message to a channel

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

Dictionary<string, string> myMessage = new Dictionary<string, string>();
myMessage.Add("msg", "Hello Signals");

pubnub.Signal()
    .Message(myMessage)
    .Channel("foo")
    .CustomMessageType("text-message")
    .Execute(new PNPublishResultExt((result, status) =>
    {
        if (status.Error)
        {
            Debug.Log(status.ErrorData.Information);
        }
        else
        {
            Debug.Log(result.Timetoken);
        }
    }));
```

### Response

| Property Name | Type | Description |
| --- | --- | --- |
| `Timetoken` | long | Returns a `long` representation of the timetoken when the message was signaled. |

## Subscribe

Subscribe opens a TCP socket and listens for messages and events on a specified entity or set of entities. Set `subscribeKey` during [initialization](https://www.pubnub.com/docs/sdks/unity/api-reference/configuration).

:::tip Conceptual overview
For more general information about subscriptions, refer to [Subscriptions](https://www.pubnub.com/docs/general/channels/subscribe).
:::

Entities are [first-class citizens](https://en.wikipedia.org/wiki/First-class_citizen) that expose their APIs. You can subscribe using the PubNub client or directly on a specific entity:

* [Channel](#create-channels)
* [ChannelGroup](#create-channel-groups)
* [UserMetadata](#create-user-metadata)
* [ChannelMetadata](#create-channel-metadata)

After `subscribe()`, the client receives new messages. Configure [automaticRetry](https://www.pubnub.com/docs/sdks/unity/api-reference/configuration#initializers) to reconnect and fetch available messages after a disconnect.

### Subscription scope

Subscriptions let you attach listeners for specific real-time update types. Your app receives messages and events through those listeners. There are two types:

* [Subscription](#create-a-subscription): created from an entity and scoped to that entity (for example, a particular channel)
* [SubscriptionSet](#create-a-subscription-set): created from the PubNub client and scoped to the client (for example, all subscriptions created on a single `pubnub` object). A set can include one or more subscriptions.

The event listener is a single point through which your app receives all the messages, signals, and events in the entities you subscribed to. For information on adding event listeners, refer to [Event listeners](#event-listeners).

### Create a subscription

An entity-level `Subscription` allows you to receive messages and events for only that entity for which it was created. Using multiple entity-level `Subscription`s is useful for handling various message/event types differently in each channel.

:::warning Keep a strong reference
You should keep a strong reference to every created subscription/subscription set because they must stay in memory to listen for updates. If you were to create a `Subscription`/`SubscriptionSet` and not keep a strong reference to it, Automatic Reference Counting (ARC) could deallocate the `Subscription` as soon as your code finishes executing.
:::

```csharp
// entity-based, local-scoped
Channel firstChannel = pubnub.Channel("first");

Subscription subscription = firstChannel.Subscription(SubscriptionOptions options);
```

| Parameter | Description |
| --- | --- |
| `options`Type: `SubscriptionOptions` | `Subscription` [behavior configuration](#subscriptionoptions). |

### Create a subscription set

A client-level `SubscriptionSet` allows you to receive messages and events for all entities. A single `SubscriptionSet` is useful for similarly handling various message/event types in each channel.

:::warning Keep a strong reference
You should keep a strong reference to every created subscription/subscription set because they must stay in memory to listen for updates. If you were to create a `Subscription`/`SubscriptionSet` and not keep a strong reference to it, Automatic Reference Counting (ARC) could deallocate the `Subscription` as soon as your code finishes executing.
:::

```csharp
// client-based, general-scoped
SubscriptionSet subscriptionSet = pubnub.SubscriptionSet(
   channels: string[],
   channelGroups: string[],
   options: SubscriptionOptions
)
```

| Parameter | Description |
| --- | --- |
| `channels` *Type: `string[]` | One or more channels to create a subscription of. Either `channels` or `channelGroups` is required. |
| `channelGroups` *Type: `string[]` | One or more channels to create a subscription of. Either `channels` or `channelGroups` is required. |
| `options`Type: `SubscriptionOptions` | `Subscription` [behavior configuration](#subscriptionoptions). |

:::tip Add/remove sets
You can add and remove subscriptions to create new sets. Refer to the [Other examples](#other-examples-1) section for more information.
:::

#### SubscriptionOptions

`SubscriptionOptions` is an enum. Available properties include:

| Option | Description |
| --- | --- |
| `ReceivePresenceEvents` | Whether presence updates for `userId`s should be delivered through the listener streams. For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel). |

### Method(s)

`Subscription` and `SubscriptionSet` use the same `subscribe<object>()` method.

#### Subscribe

To subscribe, you can use the following method in the Unity SDK:

```csharp
subscription.Subscribe<object>(SubscriptionCursor cursor)
```

| Parameter | Description |
| --- | --- |
| `cursor`Type: `SubscriptionCursor` | Cursor from which to return any available cached messages. Message retrieval with cursor is not guaranteed and should only be considered a best-effort service. A cursor consists of a timetoken and region: `cursor: { Timetoken: long?; Region: int? }` If you pass any primitive type, the SDK converts them into `SubscriptionCursor` but if their value is not a 17-digit number or a string with numeric characters, the provided value will be ignored. |

##### Sample code

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

Subscription subscription1 = pubnub.Channel("channelName").Subscription();
subscription1.Subscribe<object>();

SubscriptionSet subscriptionSet = pubnub.SubscriptionSet(
    new string[] { "channel1", "channel2" },
    new string[] { "channel_group_1", "channel_group_2" },
    SubscriptionOptions.ReceivePresenceEvents
);

subscriptionSet.Subscribe<object>();
```

##### Other examples

###### Create a subscription set from 2 individual subscriptions

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

// Create a subscription from a channel entity
Subscription subscription1 = pubnub.Channel("channelName").Subscription();

// Create a subscription from a channel group entity
Subscription subscription2 = pubnub.ChannelGroup("channelGroupName").Subscription();

// create a subscription set from individual entities
SubscriptionSet subscriptionSet = subscription1.Add(subscription2);

subscriptionSet.Subscribe<object>();
```

##### Returns

The `subscribe()` method doesn't have a return value.

## Entities

Entities are subscribable objects for which you can receive real-time updates (messages, events, etc).

* [ChannelRepresentation](#create-channels)
* [ChannelGroupRepresentation](#create-channel-groups)
* [UserMetadataRepresentation](#create-user-metadata)
* [ChannelMetadataRepresentation](#create-channel-metadata)

### Create channels

This method returns a local `Channel` entity.

```csharp
pubnub.Channel(String)
```

| Parameter | Description |
| --- | --- |
| `Channel` *Type: `String` | The ID of the [channel](https://www.pubnub.com/docs/general/channels/overview) to create a subscription of. |

#### Sample code

```csharp
var channel = pubnub.Channel("channelName");

// Listener to add relevant callbacks to
SubscribeCallbackListener channelListener = new SubscribeCallbackListener();

channel.Subscription().AddListener(channelListener);
channel.Subscription().Subscribe<object>();
```

### Create channel groups

This method returns a local `ChannelGroup` entity.

```csharp
pubnub.ChannelGroup(String)
```

| Parameter | Description |
| --- | --- |
| `ChannelGroup` *Type: `String` | The name of the [channel group](https://www.pubnub.com/docs/general/channels/subscribe#channel-groups) to create a subscription of. |

#### Sample code

```csharp
var channelGroup = pubnub.ChannelGroup("channelGroupName");

// Listener to add relevant callbacks to
SubscribeCallbackListener channelGroupListener = new SubscribeCallbackListener();

channelGroup.Subscription().AddListener(channelGroupListener);
channelGroup.Subscription().Subscribe<object>();
```

### Create channel metadata

This method returns a local `ChannelMetadata` entity.

```csharp
pubnub.ChannelMetadata(String)
```

| Parameter | Description |
| --- | --- |
| `ChannelMetadata` *Type: `String` | The String identifier of the [channel metadata](https://www.pubnub.com/docs/general/metadata/channel-metadata) object to create a subscription of. |

#### Sample code

```csharp
var channelMetadata = pubnub.ChannelMetadata("channelMetadata");

// Listener to add relevant callbacks to
SubscribeCallbackListener channelMetadataListener = new SubscribeCallbackListener();

channelMetadata.Subscription().AddListener(channelMetadataListener);
channelMetadata.Subscription().Subscribe<object>();
```

### Create user metadata

This method returns a local `UserMetadata` entity.

```csharp
pubnub.UserMetadata(String)
```

| Parameter | Description |
| --- | --- |
| `UserMetadata` *Type: `String` | The String identifier of the [user metadata](https://www.pubnub.com/docs/general/metadata/users-metadata) object to create a subscription of. |

#### Sample code

```csharp
var userMetadata = pubnub.UserMetadata("userMetadata");

// Listener to add relevant callbacks to
SubscribeCallbackListener userMetadataListener = new SubscribeCallbackListener();

userMetadata.Subscription().AddListener(userMetadataListener);
userMetadata.Subscription().Subscribe<object>();
```

## Event listeners

Messages and events are received in your app using a listener. This listener allows a single point to receive all messages, signals, and events.

You can attach listeners to the instances of [Subscription](#create-a-subscription), [SubscriptionSet](#create-a-subscription-set), and, in the case of the connection status, the PubNub client.

:::note No built-in event throttling
The PubNub SDK delivers every incoming event to your listener as it arrives — there is no built-in throttling or rate-limiting on the subscriber side. If you need to control how often your application processes events, wrap your listener callback with a throttle or debounce utility from your language or framework ecosystem.
To reduce the number of messages delivered to your client in the first place, use [Subscribe Filters](https://www.pubnub.com/docs/general/channels/subscribe-filters) to filter messages server-side before they reach your listener.
:::

### Add listeners

You can implement multiple listeners with the `onEvent` closure or register an event-specific listener that receives only a selected type, like `message` or `file`.

#### Method(s)

```csharp
// Adding listener.
pubnub.AddListener(new SubscribeCallbackListener(
    delegate(Pubnub pnObj, PNMessageResult<object> pubMsg)
    {
        Debug.Log(pubnub.JsonPluggableLibrary.SerializeToJsonString(pubMsg));
        var channelName = pubMsg.Channel;
        var channelGroupName = pubMsg.Subscription;
        var pubTT = pubMsg.Timetoken;
        var msg = pubMsg.Message;
        var publisher = pubMsg.Publisher;
    },
    delegate(Pubnub pnObj, PNPresenceEventResult presenceEvnt)
    {
        Debug.Log(pubnub.JsonPluggableLibrary.SerializeToJsonString(presenceEvnt));
        var action = presenceEvnt.Event; // Can be join, leave, state-change or timeout
        var channelName = presenceEvnt.Channel; // The channel for which the message belongs
        var occupancy = presenceEvnt.Occupancy; // No. of users connected with the channel
        var state = presenceEvnt.State; // User State
        var channelGroupName =
            presenceEvnt.Subscription; //  The channel group or wildcard subscription match (if exists)
        var publishTime = presenceEvnt.Timestamp; // Publish timetoken
        var timetoken = presenceEvnt.Timetoken; // Current timetoken
        var uuid = presenceEvnt.Uuid; // UUIDs of users who are connected with the channel
    },
    delegate(Pubnub pnObj, PNSignalResult<object> signalMsg)
    {
        Debug.Log(pubnub.JsonPluggableLibrary.SerializeToJsonString(signalMsg));
        var channelName = signalMsg.Channel; // The channel for which the signal belongs
        var channelGroupName =
            signalMsg.Subscription; // The channel group or wildcard subscription match (if exists)
        var pubTT = signalMsg.Timetoken; // Publish timetoken
        var msg = signalMsg.Message; // The Payload
        var publisher = signalMsg.Publisher; //The Publisher
    },
    delegate(Pubnub pnObj, PNObjectEventResult objectEventObj)
    {
        var channelName = objectEventObj.Channel; // Channel
        var channelMetadata = objectEventObj.ChannelMetadata; //Channel Metadata
        var uidMetadata = objectEventObj.UuidMetadata; // UUID metadata
        var evnt = objectEventObj.Event; // Event
        var type = objectEventObj.Type; // Event type
        if (objectEventObj.Type == "uuid")
        {
            /* got uuid metadata related event. */
        }
        else if (objectEventObj.Type == "channel")
        {
            /* got channel metadata related event. */
        }
        else if (objectEventObj.Type == "membership")
        {
            /* got membership related event. */
        }

        Debug.Log(pubnub.JsonPluggableLibrary.SerializeToJsonString(objectEventObj));
    },
    delegate(Pubnub pnObj, PNMessageActionEventResult msgActionEvent)
    {
        //handle message action
        var channelName = msgActionEvent.Channel; // The channel for which the message belongs
        var msgEvent = msgActionEvent.Action; // message action added or removed
        var msgActionType = msgActionEvent.Event; // message action type
        var messageTimetoken = msgActionEvent.MessageTimetoken; // The timetoken of the original message
        var actionTimetoken = msgActionEvent.ActionTimetoken; //The timetoken of the message action
    },
    delegate(Pubnub pnObj, PNFileEventResult fileEvent)
    {
        //handle file message event
        var channelName = fileEvent.Channel;
        var chanelGroupName = fileEvent.Subscription;
        var fieldId = (fileEvent.File != null) ? fileEvent.File.Id : null;
        var fileName = (fileEvent.File != null) ? fileEvent.File.Name : null;
        var fileUrl = (fileEvent.File != null) ? fileEvent.File.Url : null;
        var fileMessage = fileEvent.Message;
        var filePublisher = fileEvent.Publisher;
        var filePubTT = fileEvent.Timetoken;
    },
    delegate(Pubnub pnObj, PNStatus pnStatus)
    {
        Debug.Log($"{pnStatus.Operation} {pnStatus.Category} {pnStatus.StatusCode}");
        var affectedChannelGroups =
            pnStatus.AffectedChannelGroups; // The channel groups affected in the operation, of type array.
        var affectedChannels =
            pnStatus.AffectedChannels; // The channels affected in the operation, of type array.
        var category = pnStatus.Category; //Returns PNConnectedCategory
        var operation = pnStatus.Operation; //Returns PNSubscribeOperation
    }
));

//Add listener to receive Signal messages
SubscribeCallbackListener signalSubscribeCallback = new SubscribeCallbackListener();
signalSubscribeCallback.onSignal += delegate (Pubnub pubnubObj, PNSignalResult<object> message) {
  // Handle new signal message stored in message.Message
 };
signalSubscribeCallback.onStatus += delegate (Pubnub pubnubObj, PNStatus status) {
  // the status object returned is always related to subscribe but could contain
  // information about subscribe, heartbeat, or errors
 };
pubnub.AddListener(signalSubscribeCallback);

//Add listener to receive Events
SubscribeCallbackListener eventListener = new SubscribeCallbackListener();
eventListener.onObject += delegate(Pubnub pnObj, PNObjectEventResult objectEvent) {
 string channelMetadataId = objectEvent.Channel; // The channel
 string uuidMetadataId = objectEvent.UuidMetadata.Uuid; // The UUID
 string objEvent = objectEvent.Event; // The event name that occurred
 string eventType = objectEvent.Type; // The event type that occurred
 PNUuidMetadataResult uuidMetadata = objectEvent.UuidMetadata; // UuidMetadata
 PNChannelMetadataResult channelMetadata = objectEvent.ChannelMetadata; // ChannelMetadata
};
pubnub.AddListener(eventListener);
```

```csharp
public class DevSubscribeCallback : SubscribeCallback
{
    public override void Message<T>(Pubnub pubnub, PNMessageResult<T> message)
    {
        // Handle new message stored in message.Message
    }

    public override void Presence(Pubnub pubnub, PNPresenceEventResult presence)
    {
        // handle incoming presence data
    }

    public override void Signal<T>(Pubnub pubnub, PNSignalResult<T> signal)
    {
        // Handle new signal message stored in signal.Message
    }

    public override void Status(Pubnub pubnub, PNStatus status)
    {
        // the status object returned is always related to subscribe but could contain
        // information about subscribe, heartbeat, or errors
        // use the PNOperationType to switch on different options
        switch (status.Operation)
        {
            // let's combine unsubscribe and subscribe handling for ease of use
            case PNOperationType.PNSubscribeOperation:
            case PNOperationType.PNUnsubscribeOperation:
                // note: subscribe statuses never have traditional
                // errors, they just have categories to represent the
                // different issues or successes that occur as part of subscribe
                switch (status.Category)
                {
                    case PNStatusCategory.PNConnectedCategory:
                        // this is expected for a subscribe, this means there is no error or issue whatsoever
                        break;
                    case PNStatusCategory.PNReconnectedCategory:
                        // this usually occurs if subscribe temporarily fails but reconnects. This means
                        // there was an error but there is no longer any issue
                        break;
                    case PNStatusCategory.PNDisconnectedCategory:
                        // this is the expected category for an unsubscribe. This means there
                        // was no error in unsubscribing from everything
                        break;
                    case PNStatusCategory.PNUnexpectedDisconnectCategory:
                        // this is usually an issue with the internet connection, this is an error, handle appropriately
                        break;
                    case PNStatusCategory.PNAccessDeniedCategory:
                        // this means that Access Manager does allow this client to subscribe to this
                        // channel and channel group configuration. This is another explicit error
                        break;
                    default:
                        // More errors can be directly specified by creating explicit cases for other
                        // error categories of `PNStatusCategory` such as `PNTimeoutCategory` or `PNMalformedFilterExpressionCategory` or `PNDecryptionErrorCategory`
                        break;
                }

                break;
            case PNOperationType.PNHeartbeatOperation:
                // heartbeat operations can in fact have errors, so it is important to check first for an error.
                if (status.Error)
                {
                    // There was an error with the heartbeat operation, handle here
                }
                else
                {
                    // heartbeat operation was successful
                }

                break;
            default:
                // Encountered unknown status type
                break;
        }
    }

    public override void ObjectEvent(Pubnub pubnub, PNObjectEventResult objectEvent)
    {
        // handle incoming user, space and membership event data
    }

    public override void MessageAction(Pubnub pubnub, PNMessageActionEventResult messageAction)
    {
        // handle incoming message action events
    }

    public override void File(Pubnub pubnub, PNFileEventResult fileEvent)
    {
        // handle incoming file messages
    }
}

public static void AddListenerMethod2()
{
    // Usage of the above listener
    DevSubscribeCallback regularListener = new DevSubscribeCallback();
    pubnub.AddListener(regularListener);
}
```

#### Sample code

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

Subscription subscription1 = pubnub.Channel("channelName").Subscription();

SubscriptionSet subscriptionSet = pubnub.SubscriptionSet(
    new string[] { "channel1", "channel2" },
    new string[] { "channel_group_1", "channel_group_2" },
    SubscriptionOptions.ReceivePresenceEvents
);

SubscribeCallbackListener eventListener = new SubscribeCallbackListener();
eventListener.onMessage += delegate(Pubnub pn, PNMessageResult<object> messageEvent) {
 Debug.Log($"received message {messageEvent.Message}");
};
eventListener.onPresence += delegate(Pubnub pn, PNPresenceEventResult e) { Debug.Log("Presence event"); };
eventListener.onStatus += delegate(Pubnub pn, PNStatus s) { Debug.Log("Status event"); };

subscription1.AddListener(eventListener);
subscriptionSet.onSignal += (Pubnub pn, PNSignalResult<object> signalEvent) =>
{
    Debug.Log($"Message received {signalEvent.Message}");
};

subscription1.Subscribe<object>();
subscriptionSet.Subscribe<object>();
```

### Add connection status listener

The PubNub client has a listener dedicated to handling connection status updates.

:::warning Client scope
This listener is only available on the PubNub object.
:::

#### Method(s)

```csharp
pubnub.AddListener(listener)
```

#### Sample code

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

SubscribeCallbackListener eventListener = new SubscribeCallbackListener();
eventListener.onStatus += delegate(Pubnub pn, PNStatus e) { Debug.Log("Status event"); };

pubnub.AddListener(eventListener);
```

#### Returns

The subscription status. For information about available statuses, refer to [SDK statuses](https://www.pubnub.com/docs/general/setup/connection-management#sdk-statuses).

## Unsubscribe

Stop receiving real-time updates from a [Subscription](#create-a-subscription) or a [SubscriptionSet](#create-a-subscription-set).

### Method(s)

```csharp
subscription.Unsubscribe<object>()

subscriptionSet.Unsubscribe<object>()
```

### Sample code

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

Subscription subscription1 = pubnub.Channel("channelName").Subscription();

SubscriptionSet subscriptionSet = pubnub.SubscriptionSet(
    new string[] { "channel1", "channel2" },
    new string[] { "channel_group_1", "channel_group_2" },
    SubscriptionOptions.ReceivePresenceEvents
);

subscription1.Subscribe<object>();
subscriptionSet.Subscribe<object>();

subscription1.Unsubscribe<object>();
subscriptionSet.Unsubscribe<object>();
```

### Returns

None

## Unsubscribe all

Stop receiving real-time updates from all data streams and remove the entities associated with them.

:::warning Client scope
This method is only available on the PubNub object.
:::

### Method(s)

```csharp
pubnub.UnsubscribeAll<object>()
```

### Sample code

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

pubnub.UnsubscribeAll<string>();
```

### Returns

None

## Subscribe (old)

:::warning Not recommended
The use of this method is discouraged. Use [Subscribe](#subscribe) instead.
:::

#### Receive messages (old)

Your app receives messages and events via event listeners. The event listener is a single point through which your app receives all the messages, signals, and events that are sent in any channel you are subscribed to.

For more information about adding a listener, refer to the [Unity SDK event listeners](https://www.pubnub.com/docs/sdks/unity/status-events).

#### Description (old)

This function causes the client to create an open TCP socket to the PubNub Real-Time Network and begin listening for messages on a specified `channel` ID. To subscribe to a `channel` ID the client must send the appropriate `SubscribeKey` at initialization.

By default a newly subscribed client will only receive messages published to the channel after the `Subscribe()` call completes. If a client gets disconnected from a channel, it can automatically attempt to reconnect to that `channel` ID and retrieve any available messages that were missed during that period. This can be achieved by setting `ReconnectionPolicy` to `PNReconnectionPolicy.LINEAR`, when [initializing](https://www.pubnub.com//docs/sdks/unity/api-reference/configuration#initialization) the client.

:::warning Unsubscribing from all channels
**Unsubscribing** from all channels, and then **subscribing** to a new channel Y is not the same as subscribing to channel Y and then unsubscribing from the previously-subscribed channel(s). Unsubscribing from all channels resets the last-received `timetoken` and thus, there could be some gaps in the subscription that may lead to message loss.
:::

#### Method(s) (old)

To `Subscribe to a channel` you can use the following method(s) in the Unity SDK:

```csharp
pubnub.Subscribe<string>()
    .Channels(Array|List<string>)
    .ChannelGroups(Array|List<string>)
    .WithTimetoken(long)
    .WithPresence()
    .QueryParam(Dictionary<string,object>)
    .Execute(System.Action<PNPublishResult, PNStatus>)
```

| Parameter | Description |
| --- | --- |
| `Channels`Type: Array or `List<string>` | Subscribe to `Channels`, Either `Channels` or `ChannelGroups` is required. |
| `ChannelGroups`Type: Array or `List<string>` | Subscribe to `ChannelGroups`, Either `Channels` or `ChannelGroups` is required. |
| `WithTimetoken`Type: long | Pass a `Timetoken`. |
| `WithPresence`Type: Command | Also subscribe to related presence information. |
| `QueryParam`Type: Dictionary`<string, object>` | Dictionary `object` to pass name/value pairs as query `string` params with PubNub URL request for debug purpose. |
| `Execute`Type: `System.Action` | `System.Action` of type `PNPublishResult`. |

#### Sample code (old)

Subscribe to a channel:

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

pubnub.Subscribe<string>()
    .Channels(new string[]
    {
        // subscribe to channels
        "my_channel"
    })
    .Execute();
```

:::note Event listeners
The response of the call is handled by adding a Listener. Please see the [Listeners section](https://www.pubnub.com/docs/sdks/unity#add-event-listeners) for more details. Listeners should be added before calling the method.
:::

#### Returns (old)

:::note PNMessageResult
`PNMessageResult<T>` is returned in the [Listeners](https://www.pubnub.com/docs/sdks/unity#add-event-listeners)
:::

The `Subscribe()` operation returns a `PNStatus` which contains the following operations:

| Property Name | Type | Description |
| --- | --- | --- |
| `Category` | `PNStatusCategory` | See the [Unity SDK listener categories](https://www.pubnub.com/docs/sdks/unity/status-events). |
| `Error` | bool | This is `true` if an error occurred in the execution of the operation. |
| `ErrorData` | PNErrorData | Error data of the exception (if `Error` is `true`) |
| `StatusCode` | int | Status code of the execution. |
| `Operation` | PNOperationType | Operation type of the request. |
| `AffectedChannels` | List`<string>` | A list of affected channels in the operation. |
| `AffectedChannelGroups` | List`<string>` | A list of affected channel groups in the operation. |

The `Subscribe()` operation returns a `PNMessageResult<T>` for messages which contains the following operations:

| Property Name | Type | Description |
| --- | --- | --- |
| `Message` | object | The message sent on the `channel` ID. |
| `Subscription` | string | The `channel group` or wildcard subscription match (if exists). |
| `Channel` | string | The `channel` ID for which the message belongs. |
| `Timetoken` | long | `Timetoken` for the message. |
| `UserMetadata` | object | User `metadata`. |

The `Subscribe()` operation returns a `PNPresenceEventResult` from presence which contains the following operations:

| Property Name | Type | Description |
| --- | --- | --- |
| `Event` | string | Events like `join`, `leave`, `timeout`, `state-change`, `interval`. |
| `Uuid` | string | `UUID` for the event. |
| `Timestamp` | long | `Timestamp` for the event. |
| `Occupancy` | int | Current `occupancy`. |
| `State` | Dictionary | `State` of the `UUID`. |
| `Subscription` | string | The `channel group` or wildcard subscription match (if exists). |
| `Channel` | string | The `channel` ID for which the message belongs. |
| `Timetoken` | long | `Timetoken` of the message. |
| `UserMetadata` | object | User `metadata`. |
| `Join` | string[] | List of channels when the event is `interval`. |
| `Timeout` | string[] | List of channels when the event is `interval`. |
| `Leave` | string[] | List of channels when the event is `interval`. |
| `HereNowRefresh` | bool | Flag to indicate whether `HereNow` fetch is needed. |

#### Other examples (old)

Basic subscribe with logging

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    // subscribeKey from admin panel
    SubscribeKey = "my_subkey", // required
    // publishKey from admin panel (only required if publishing)
    PublishKey = "my_pubkey",
    // logging level declaration
    LogLevel = PubnubLogLevel.Debug
};

Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

pubnub.Subscribe<string>()
    .Channels(new string[]
    {
        // subscribe to channels
        "my_channel"
    })
    .Execute();
```

Subscribing to multiple channels

It's possible to subscribe to more than one channel using the [Multiplexing](https://www.pubnub.com/docs/general/channels/subscribe#channel-multiplexing) feature. The example shows how to do that using an array to specify the channel names.

:::note Alternative subscription methods
You can also use [Wildcard Subscribe](https://www.pubnub.com/docs/general/channels/subscribe#wildcard-subscribe) and [Channel Groups](https://www.pubnub.com/docs/general/channels/subscribe#channel-groups) to subscribe to multiple channels at a time. To use these features, the *Stream Controller* add-on must be enabled on your keyset in the [Admin Portal](https://admin.pubnub.com).
:::

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

pubnub.Subscribe<string>()
    .Channels(new string[]
    {
        // subscribe to channels information
        "my_channel1",
        "my_channel2"
    })
    .Execute();
```

##### Subscribing to a Presence channel (old)

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/). For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

For any given channel there is an associated Presence channel. You can subscribe directly to the channel by appending `-pnpres` to the channel name. For example the channel named `my_channel` would have the presence channel named `my_channel-pnpres`.

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

pubnub.Subscribe<string>()
    .Channels(new string[]
    {
        // subscribe to channels
        "my_channel"
    })
    .WithPresence() // also subscribe to related presence information
    .Execute();
```

##### Sample Responses (old)

##### Join event (old)

```json
{
    "Event": "join",
    "Uuid": "175c2c67-b2a9-470d-8f4b-1db94f90e39e",
    "Timestamp": 1345546797,
    "Occupancy": 2,
    "State": null,
    "Channel":" my_channel",
    "Subscription": "",
    "Timetoken": 15034141109823424,
    "UserMetadata": null,
    "Join": null,
    "Timeout": null,
    "Leave": null,
    "HereNowRefresh": false
}
```

##### Leave event (old)

```json
{
    "Event": "leave",
    "Uuid": "175c2c67-b2a9-470d-8f4b-1db94f90e39e",
    "Timestamp": 1345546797,
    "Occupancy": 1,
    "State": null,
    "Channel": "my_channel",
    "Subscription": "",
    "Timetoken": 15034141109823424,
    "UserMetadata": null,
    "Join": null,
    "Timeout": null,
    "Leave": null,
    "HereNowRefresh": false
}
```

##### Timeout event (old)

```json
{
    "Event": "timeout",
    "Uuid": "175c2c67-b2a9-470d-8f4b-1db94f90e39e",
    "Timestamp": 1345546797,
    "Occupancy": 0,
    "State": null,
    "Channel": "my_channel",
    "Subscription": "",
    "Timetoken": 15034141109823424,
    "UserMetadata": null,
    "Join": null,
    "Timeout": null,
    "Leave": null,
    "HereNowRefresh": false
}
```

##### State change event (old)

```json
{
    "Event": "state-change",
    "Uuid": "175c2c67-b2a9-470d-8f4b-1db94f90e39e",
    "Timestamp": 1345546797,
    "Occupancy": 1,
    "State": {
        "isTyping": true
    },
    "Channel": "my_channel",
    "Subscription": "",
    "Timetoken": 15034141109823424,
    "UserMetadata": null,
    "Join": null,
    "Timeout": null,
    "Leave": null,
    "HereNowRefresh": false
}
```

##### Interval event (old)

```json
{
    "Event": "interval",
    "Uuid": "175c2c67-b2a9-470d-8f4b-1db94f90e39e",
    "Timestamp": 1345546797,
    "Occupancy": 2,
    "State": null,
    "Channel": "my_channel",
    "Subscription": "",
    "Timetoken": 15034141109823424,
    "UserMetadata": null,
    "Join": null,
    "Timeout": null,
    "Leave": null,
    "HereNowRefresh": false
}
```

When a channel is in interval mode with `presence_deltas` `pnconfig` flag enabled, the interval message may also include the following fields which contain an array of changed UUIDs since the last interval message.

* joined
* left
* timed out

For example, this interval message indicates there were 2 new UUIDs that joined and 1 timed out UUID since the last interval:

```json
{
    "Event": "interval",
    "Uuid": "175c2c67-b2a9-470d-8f4b-1db94f90e39e",
    "Timestamp": <unix timestamp>,
    "Occupancy": <# users in channel>,
    "State": null,
    "Channel": "my_channel",
    "Subscription": "",
    "Timetoken": 15034141109823424,
    "UserMetadata": null,
    "Join": ["uuid2", "uuid3"],
    "Timeout": ["uuid1"],
    "Leave": null,
    "HereNowRefresh": false
}
```

If the full interval message is greater than `30 KB` (since the max publish payload is `∼32 KiB`), none of the extra fields will be present. Instead there will be a `here_now_refresh` boolean field set to `true`. This indicates to the user that they should do a `hereNow` request to get the complete list of users present in the channel.

```json
{
    "Event": "interval",
    "Uuid": "175c2c67-b2a9-470d-8f4b-1db94f90e39e",
    "Timestamp": <unix timestamp>,
    "Occupancy": <# users in channel>,
    "State": null,
    "Channel": "my_channel",
    "Subscription": "",
    "Timetoken": 15034141109823424,
    "UserMetadata": null,
    "Join": null,
    "Timeout": null,
    "Leave": null,
    "HereNowRefresh": true
}
```

##### Wildcard subscribe to channels (old)

:::note Requires Stream Controller add-on
This method requires that the *Stream Controller* add-on is enabled for your key in the [Admin Portal](https://admin.pubnub.com/) (with Enable Wildcard Subscribe checked). Read the [support page](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) on enabling add-on features on your keys.
:::

Wildcard subscribes allow the client to subscribe to multiple channels using wildcard. For example, if you subscribe to `a.*` you will get all messages for `a.b`, `a.c`, `a.x`. The `*` portion refers to any part of the channel string name after the `dot (.)`.

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

pubnub.Subscribe<string>()
    .Channels(new string[]
    {
        // subscribe to channels information
        "foo.*"
    })
    .Execute();
```

:::note Wildcard grants and revokes
Only one level (`a.*`) of using wildcards is supported. If you grant on `*` or `a.b.*`, the grant will treat `*` or `a.b.*` as a single channel named either `*` or `a.b.*`. You can also revoke permissions from multiple channels using wildcards but only if you previously granted permissions using the same wildcards. Wildcard revokes, similarly to grants, only work one level deep, like `a.*`.
:::

##### Subscribing with state (old)

:::warning Requires Presence
This method requires that the Presence add-on is [enabled](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) for your key in the [Admin Portal](https://admin.pubnub.com/). For information on how to receive presence events and what those events are, refer to [Presence Events](https://www.pubnub.com/docs/general/presence/presence-events#subscribe-to-presence-channel).
:::

:::note Required User ID
Always set the `UUID` to uniquely identify the user or device that connects to PubNub. This `UUID` should be persisted, and should remain unchanged for the lifetime of the user or the device. If you don't set the `UUID`, you won't be able to connect to PubNub.
:::

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

var listener = new SubscribeCallbackListener();
listener.onStatus += (pubnubObj, status) =>
{
 if (status.Category == PNStatusCategory.PNConnectedCategory)
 {
  Dictionary<string, object> data = new Dictionary<string, object>();
  data.Add("FieldA", "Awesome");
  data.Add("FieldB", 10);

  pubnub.SetPresenceState()
   .Channels(new string[] { "awesomeChannel" })
   .ChannelGroups(new string[] { "awesomeChannelGroup" })
   .State(data)
   .Execute(new PNSetStateResultExt(
    (r, s) =>
    {
     // handle set state response
    }
   ));
 }
};
pubnub.AddListener(listener);

pubnub.Subscribe<string>()
    .Channels(new string[]
    {
        "awesomeChannel"
    })
    .Execute();
```

##### Subscribe to a channel group (old)

:::note Requires Stream Controller add-on
This method requires that the *Stream Controller* add-on is enabled for your key in the [Admin Portal](https://admin.pubnub.com/). Read the [support page](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) on enabling add-on features on your keys.
:::

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

pubnub.Subscribe<string>()
    .Channels(new string[]
    {
        // subscribe to channels
        "ch1",
        "ch2"
    })
    .ChannelGroups(new string[]
    {
        // subscribe to channel groups
        "cg1",
        "cg2"
    })
    .WithTimetoken(1337L) // optional, pass a timetoken
    .WithPresence() // also subscribe to related presence information
    .Execute();
```

##### Subscribe to the Presence channel of a channel group (old)

:::note Requires Stream Controller and Presence add-ons
This method requires both the *Stream Controller* and *Presence* add-ons are enabled for your key in the [Admin Portal](https://admin.pubnub.com/). Read the [support page](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) on enabling add-on features on your keys.
:::

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

pubnub.Subscribe<string>()
    .ChannelGroups(new string[]
    {
        // subscribe to channel groups
        "cg1",
        "cg2"
    })
    .WithTimetoken(1337L) // optional, pass a timetoken
    .WithPresence() // also subscribe to related presence information
    .Execute();
```

##### Subscribe with a custom type (old)

Unity supports subscribing with custom types. However only one type of message can be subscribed for a given channel. If you want to subscribe different types of messages for the same channel, then subscribing using the generic type as `string` is the recommended option.

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

public class Phone
{
    public string Number { get; set; }
    public string Extenion { get; set; }

    [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
    public PhoneType PhoneType { get; set; }
}

public enum PhoneType
{
    Home,
    Mobile,
    Work
}

public static void SubscribeWithCustomType()
{
    Phone myPhone = new Phone()
    {
        Number = "111-222-2222",
        PhoneType = PhoneType.Mobile,
        Extenion = "11"
    };

    pubnub.Publish()
        .Message(myPhone)
        .Channel("my_channel")
        .ShouldStore(true)
        .Execute(new PNPublishResultExt(
            (result, status) =>
            {
                // Check whether request successfully completed or not.
                if (status.Error)
                {
                    // something bad happened.
                    Debug.Log("error happened while publishing: " +
                                      pubnub.JsonPluggableLibrary.SerializeToJsonString(status));
                }
                else
                {
                    Debug.Log("publish worked! timetoken: " + result.Timetoken.ToString());
                }
            }
        ));

    SubscribeCallbackListener objectListenerSubscribeCallack = new SubscribeCallbackListener();
    objectListenerSubscribeCallack.onMessage += (pubnubObj, message) => {
     //message.Message gives the Phone object because you subscribed to type Phone during subscribe.
    };

    pubnub.AddListener(objectListenerSubscribeCallack);
    pubnub.Subscribe<Phone>()
        .Channels(new string[]
        {
            "my_channel" // subscribe to channels
        })
        .Execute();

    //If you are subscribing to multiple message types, then
    SubscribeCallbackListener stringListenerSubscribeCallback = new SubscribeCallbackListener();
    stringListenerSubscribeCallback.onMessage += (pubnubObj, message) => {
     //message.Message gives the string object because you subscribed to type "string" during subscribe.
     string phoneStringMessage = message.Message.ToString(); //this is your string message
     //using pluggable JSON library from the Pubnub instance, but you can use any form of JSON deserialization you wish
     var deserializedMessage = pubnub.JsonPluggableLibrary.DeserializeToObject<Phone>(phoneStringMessage);
    };

    pubnub.AddListener(stringListenerSubscribeCallback);
    pubnub.Subscribe<string>()
        .Channels(new string[]
        {
            "my_channel" // subscribe to channels
        })
        .Execute();
}
```

#### Event listeners (old)

You can be notified of connectivity status, message and presence notifications via the listeners.

Listeners should be added before calling the method.

##### Add listeners (old)

```csharp
using PubnubApi;
using PubnubApi.Unity;

pubnub = new Pubnub(pnConfiguration);
var listener = new SubscribeCallbackListener();
pubnub.AddListener(listener);

listener.onStatus += OnPnStatus;
listener.onMessage += OnPnMessage;
listener.onPresence += OnPnPresence;
listener.onFile += OnPnFile;
listener.onObject += OnPnObject;
listener.onSignal += OnPnSignal;
listener.onMessageAction += OnPnMessageAction;

private void OnPnMessageAction(Pubnub pn, PNMessageActionEventResult result) {
    Debug.Log(result.Channel);
}

private void OnPnSignal(Pubnub pn, PNSignalResult<object> result) {
    Debug.Log(result.Channel);
}

private void OnPnObject(Pubnub pn, PNObjectEventResult result) {
    Debug.Log(result.Channel);
}

private void OnPnFile(Pubnub pn, PNFileEventResult result) {
    Debug.Log(result.Channel);
}

private void OnPnPresence(Pubnub pn, PNPresenceEventResult result) {
    Debug.Log(result.Event);
}

private void OnPnStatus(Pubnub pn, PNStatus status) {
    Debug.Log(status.Category == PNStatusCategory.PNConnectedCategory ? "Connected" : "Not connected");
}

private void OnPnMessage(Pubnub pn, PNMessageResult<object> result) {
    Debug.Log($"Message received: {result.Message}");
}
```

##### Removing listeners (old)

```csharp
protected override void OnDestroy() {
    // Use OnDestroy to clean up, e.g. unsubscribe from listeners.
    listener.onStatus -= OnPnStatus;
    listener.onMessage -= OnPnMessage;
    listener.onPresence -= OnPnPresence;
    listener.onFile -= OnPnFile;
    listener.onObject -= OnPnObject;
    listener.onSignal -= OnPnSignal;
    listener.onMessageAction -= OnPnMessageAction;
    
    base.OnDestroy();
}
```

##### Listener status events (old)

| Category | Description |
| --- | --- |
| `PNNetworkIssuesCategory` | A subscribe event experienced connection issues when running. |
| `PNReconnectedCategory` | SDK was able to reconnect to pubnub. |
| `PNConnectedCategory` | SDK subscribed with a new mix of channels (fired every time the `channel` / `channel group` mix changed). |
| `PNAcknowledgmentCategory` | An API call was successful. This status has additional details based on the type of the successful operation. |
| `PNAccessDeniedCategory` | Request failed because of access error (active Access Manager). `status.AffectedChannels` or `status.AffectedChannelGroups` contain list of channels and/or groups to which user with specified `auth` key doesn't have access. |
| `PNTimeoutCategory` | Used API didn't receive a response from server in time. |
| `PNDisconnectedCategory` | Client unsubscribed from specified real-time data channels. |
| `PNUnexpectedDisconnectCategory` | Subscribe loop failed and at this moment client is disconnected from real-time data channels. This could due to the machine or device is not connected to Internet or this has been lost, your ISP (Internet Service Provider) is having to troubles or perhaps or the SDK is behind of a proxy. |
| `PNBadRequestCategory` | Request cannot be completed as not all required values have been passed (like `subscribe key`, `publish key`) or passed values are of unexpected data type. |
| `PNMalformedFilterExpressionCategory` | Subscription request cannot be processed as the passed filter expression is malformed and cannot be evaluated. |
| `PNMalformedResponseCategory` | Request received in response non-JSON data. It can be because of an error message from the proxy server (if applicable). |
| `PNDecryptionErrorCategory` | Message Persistence API may return this status category in case if some messages can't be decrypted. |
| `PNTLSConnectionFailedCategory` | TLS handshake issues. In most cases is because of poor network quality and packets loss and delays. |
| `PNRequestMessageCountExceededCategory` | This status event will be fired each time the client receives more messages than the value of *RequestMessageCountThreshold*, set in `PNConfiguration`. |
| `PNReconnectionAttemptsExhausted` | In case of network disconnect the PubNub client SDK will attempt to reconnect a finite number of times after which this status is sent and the re-connection attempts will stop. |
| `PNUnknownCategory` | PubNub SDK returns this error for SDK exceptions or when server responds with an error. |

## Unsubscribe (old)

:::warning Not recommended
The use of this method is discouraged. Use [Unsubscribe](#unsubscribe) instead.
:::

When subscribed to a single channel, this function causes the client to issue a `leave` from the `channel` and close any open socket to the PubNub Network. For multiplexed channels, the specified `channel`(s) will be removed and the socket remains open until there are no more channels remaining in the list.

:::warning Unsubscribing from all channels
**Unsubscribing** from all channels, and then **subscribing** to a new channel Y is not the same as subscribing to channel Y and then unsubscribing from the previously-subscribed channel(s). Unsubscribing from all channels resets the last-received `timetoken` and thus, there could be some gaps in the subscription that may lead to message loss.
:::

#### Method(s) (old)

To `Unsubscribe from a channel` you can use the following method(s) in the Unity SDK:

```csharp
pubnub.Unsubscribe<string>()
    .Channels(Array)
    .ChannelGroups(Array)
    .QueryParam(Dictionary<string,object>)
    .Execute()
```

| Parameter | Description |
| --- | --- |
| `Channels`Type: Array | Unsubscribe to `channels`, Either `Channels` or `ChannelGroups` is required |
| `ChannelGroups`Type: Array | Unsubscribe to channel groups, Either `channels` or `channelGroup` is required |
| `QueryParam`Type: Dictionary`<string, object>` | Dictionary `object` to pass name/value pairs as query `string` params with PubNub URL request for debug purpose. |
| `Execute` *Type: Command | Command that will `execute` `Unsubscribe`. |

#### Sample code (old)

Unsubscribe from a channel:

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

pubnub.Unsubscribe<string>()
    .Channels(new string[]
    {
        "my_channel"
    })
    .Execute();
```

:::note Event listeners
The response of the call is handled by adding a Listener. Please see the [Listeners section](https://www.pubnub.com/docs/sdks/unity#add-event-listeners) for more details. Listeners should be added before calling the method.
:::

#### Returns (old)

None

#### Other examples (old)

##### Unsubscribing from multiple channels (old)

:::note Requires Stream Controller add-on
This method requires that the *Stream Controller* add-on is enabled for your key in the [Admin Portal](https://admin.pubnub.com/). Read the [support page](https://support.pubnub.com/hc/en-us/articles/360051974791-How-do-I-enable-add-on-features-for-my-keys-) on enabling add-on features on your keys.
:::

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

pubnub.Unsubscribe<string>()
    .Channels(new string[]
    {
        "ch1",
        "ch2",
        "ch3"
    })
    .ChannelGroups(new string[]
    {
        "cg1",
        "cg2",
        "cg3"
    })
    .Execute();
```

##### Example response (old)

```json
{
    "Category": "PNDisconnectedCategory",
    "ErrorData": null,
    "Error": false,
    "StatusCode": 200,
    "Operation": "PNUnsubscribeOperation",
    "TlsEnabled": false,
    "Uuid": null,
    "AuthKey": null,
    "Origin": "ps.pndsn.com",
    "ClientRequest": null,
    "AffectedChannels": ["ch1","ch2","ch3"],
    "AffectedChannelGroups": ["cg1","cg2","cg3"]
}
```

##### Unsubscribe from a channel group (old)

```csharp
using PubnubApi;

// Configuration
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize PubNub
Pubnub pubnub = PubnubUnityUtils.NewUnityPubnub(pnConfiguration);

// If you're using Unity Editor setup you can get the Pubnub instance from PNManagerBehaviour
// For more details, see https://www.pubnub.com/docs/sdks/unity#configure-pubnub
/*
[SerializeField] private PNManagerBehaviour pubnubManager;
Pubnub pubnub = pubnubManager.pubnub;
*/

pubnub.Unsubscribe<string>()
    .ChannelGroups(new string[]
    {
        "cg1",
        "cg2",
        "cg3"
    })
    .Execute();
```

##### Example response (old)

```javascript
{
    "Category": "PNDisconnectedCategory",
    "ErrorData": null,
    "Error": false,
    "StatusCode": 200,
    "Operation": "PNUnsubscribeOperation",
    "TlsEnabled": false,
    "Uuid": null,
    "AuthKey": null,
    "Origin": "ps.pndsn.com",
    "ClientRequest": null,
    "AffectedChannels": [],
    "AffectedChannelGroups": ["cg1","cg2","cg3"]
}
```

## Unsubscribe all (old)

:::warning Not recommended
The use of this method is discouraged. Use [Unsubscribe All](#unsubscribe-all) instead.
:::

#### Method(s) (old)

```csharp
pubnub.UnsubscribeAll<string>()
    .QueryParam(Dictionary<string,object>)
```

| Parameter | Description |
| --- | --- |
| `QueryParam`Type: Dictionary`<string, object>` | Dictionary `object` to pass name/value pairs as query `string` params with PubNub URL request for debug purpose. |

#### Sample code (old)

```csharp
pubnub.UnsubscribeAll();
```

#### Returns (old)

None

## Terms in this document

* **Channel** - A pathway for sending and receiving messages between devices, created automatically when you first use it, that can handle any number of users and messages for different communication needs, like 1-1 text chats, group conversations, and other data streaming.
* **Channel pattern** - A way to group and analyze channel data to track performance metrics like message counts and user engagement over time with PubNub Insights.
* **Entity** - A subscribable object within a PubNub SDK that allows you to perform context-specific operations.
* **Signal** - A non-persistent message limited to 64 bytes designed for high-volume usecases where the the most recent data is relevant, like GPS location updates.