---
source_url: https://www.pubnub.com/docs/sdks/python/api-reference/objects
title: App Context API for Python SDK
updated_at: 2026-06-16T12:52:14.917Z
sdk_name: PubNub Python SDK
sdk_version: 10.7.1
---

> 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


# App Context API for Python SDK

PubNub Python SDK, use the latest version: 10.7.1

Install:

```bash
pip install pubnub@10.7.1
```

This page describes App Context (formerly Objects v2). To upgrade from Objects v1, refer to the [migration guide](https://www.pubnub.com/docs/general/resources/migration-guides/objects-v2-migration).

App Context provides easy-to-use, serverless storage for user and channel data you need to build innovative, reliable, scalable applications. Use App Context to store metadata about your application users and channels, and their membership associations, without the need to stand up your own databases.

PubNub also triggers events when object data is changed: set, updated, or removed from the database. Making a request to set the same data that already exists doesn't trigger an event. Clients can receive these events in real time and update their front-end application accordingly.

:::note Request execution and return values
You can decide whether to perform the Python SDK operations synchronously or asynchronously.
* .sync() returns an Envelope object, which has two fields: Envelope.result, whose type differs for each API, and Envelope.status of type PnStatus. 1pubnub.publish() \2 .channel("myChannel") \3 .message("Hello from PubNub Python SDK") \4 .sync()
* .pn_async(callback) returns None and passes the values of Envelope.result and Envelope.status to a callback you must define beforehand. 1def my_callback_function(result, status):2 print(f'TT: {result.timetoken}, status: {status.category.name}')3 4pubnub.publish() \5 .channel("myChannel") \6 .message("Hello from PubNub Python SDK") \7 .pn_async(my_callback_function)
:::

## User

Manage UUID metadata: list, fetch, set, and remove. Keep responses small by including only the fields you need.

### Get metadata for all users

Get a paginated list of UUID metadata. Use filters and sorting to narrow results.

:::warning Required keyset configuration
To get all channel and user metadata, you must uncheck the
Disallow Get All Channel Metadata
and
Disallow Get All User Metadata
checkboxes in the App Context section of your keyset configuration in the
[Admin Portal](https://admin.pubnub.com)
.
:::

#### Method(s)

To `Get All UUID Metadata` you can use the following method(s) in the Python SDK:

```python
pubnub.get_all_uuid_metadata() \
    .limit(Integer) \
    .page(PNPage Object) \
    .filter(String) \
    .sort(List<PNSortKey>) \
    .include_total_count(Boolean) \
    .include_custom(Boolean) \
    .include_status(Boolean) \
    .include_type(Boolean)
```

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| limit | Integer | Optional | `N/A` | The maximum number of objects to retrieve at a time. |
| page | PNPage | Optional | `N/A` | The paging object used for pagination. |
| filter | String | Optional | `N/A` | Expression used to filter the results. Only objects whose properties satisfy the given expression are returned. The filter language is defined [here](https://www.pubnub.com/docs/general/metadata/filtering). |
| sort | List<PNSortKey> | Optional | `N/A` | List of properties to sort by. Available options are `id`, `name`, and `updated`. Use `asc` or `desc` to specify sort direction. For example: `{name: 'asc'}`. |
| include_total_count | Boolean | Optional | `False` | Whether to include the total count in the paginated response. Default is false. |
| include_custom | Boolean | Optional | `False` | Whether to include the Custom object in the response. |
| include_status | Boolean | Optional | `True` | Whether to include the `status` field in the fetch response. Setting this to `False` will prevent this value from being returned. |
| include_type | Boolean | Optional | `True` | Whether to include the `type` field in the fetch response. Setting this to `False` will prevent this value from being returned. |

#### Sample code

:::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.
:::

###### Builder Pattern

Synchronous:

```python
import os
from pubnub.pnconfiguration import PNConfiguration
from pubnub.pubnub import PubNub
from pubnub.models.consumer.objects_v2.sort import PNSortKey, PNSortKeyValue
from pubnub.exceptions import PubNubException

def get_all_uuid_metadata(pubnub: PubNub):
    try:
        result = pubnub.get_all_uuid_metadata() \
            .include_custom(True) \
            .limit(10) \
            .include_total_count(True) \
            .sort(PNSortKey.asc(PNSortKeyValue.ID), PNSortKey.desc(PNSortKeyValue.UPDATED)) \
            .page(None) \
            .sync()

        for uuid_data in result.result.data:
            print(f"UUID: {uuid_data['id']}")
            print(f"Name: {uuid_data['name']}")
            print(f"Custom: {uuid_data['custom']}")

    except PubNubException as e:
        print(f"Error: {e}")

def main():
    # Configuration for PubNub instance
    pn_config = PNConfiguration()
    pn_config.subscribe_key = os.getenv('SUBSCRIBE_KEY', 'demo')
    pn_config.publish_key = os.getenv('PUBLISH_KEY', 'demo')
    pn_config.user_id = os.getenv('USER_ID', 'my_custom_user_id')

    # Initialize PubNub client
    pubnub = PubNub(pn_config)

    # Get all UUID metadata
    get_all_uuid_metadata(pubnub)

if __name__ == "__main__":
    main()
```

Asynchronous:

```python
import os
from pubnub.pnconfiguration import PNConfiguration
from pubnub.pubnub import PubNub
from pubnub.models.consumer.objects_v2.sort import PNSortKey, PNSortKeyValue

def callback(response, status):
    if status.is_error():
        print(f"Error: {status.error_data}")
    else:
        for uuid_data in response.data:
            print(f"UUID: {uuid_data["id"]}")
            print(f"Name: {uuid_data["name"]}")
            print(f"Custom: {uuid_data["custom"]}")

def get_all_uuid_metadata(pubnub: PubNub):
    pubnub.get_all_uuid_metadata() \
        .include_custom(True) \
        .limit(10) \
        .include_total_count(True) \
        .sort(PNSortKey.asc(PNSortKeyValue.ID), PNSortKey.desc(PNSortKeyValue.UPDATED)) \
        .page(None) \
        .pn_async(callback)

def main():
    # Configuration for PubNub instance
    pn_config = PNConfiguration()
    pn_config.subscribe_key = os.getenv('SUBSCRIBE_KEY', 'demo')
    pn_config.publish_key = os.getenv('PUBLISH_KEY', 'demo')
    pn_config.user_id = os.getenv('USER_ID', 'my_custom_user_id')

    # Initialize PubNub client
    pubnub = PubNub(pn_config)

    # Get all UUID metadata
    get_all_uuid_metadata(pubnub)

if __name__ == "__main__":
    main()
```

###### Named Arguments

Synchronous:

```python
import os
from pubnub.pnconfiguration import PNConfiguration
from pubnub.pubnub import PubNub
from pubnub.models.consumer.objects_v2.sort import PNSortKey, PNSortKeyValue
from pubnub.exceptions import PubNubException

def get_all_uuid_metadata(pubnub: PubNub):
    try:
        metadata = pubnub.get_all_uuid_metadata(
            limit=10,
            include_custom=True,
            include_total_count=True,
            sort_keys=[PNSortKey.asc(PNSortKeyValue.ID), PNSortKey.desc(PNSortKeyValue.UPDATED)]
        ).sync()

        for uuid_data in metadata.result.data:
            print(f"UUID: {uuid_data["id"]}")
            print(f"Name: {uuid_data["name"]}")
            print(f"Custom: {uuid_data["custom"]}")

    except PubNubException as e:
        print(f"Error: {e}")

def main():
    # Configuration for PubNub instance
    pn_config = PNConfiguration()
    pn_config.subscribe_key = os.getenv('SUBSCRIBE_KEY', 'demo')
    pn_config.user_id = os.getenv('USER_ID', 'my_custom_user_id')

    # Initialize PubNub client
    pubnub = PubNub(pn_config)

    # Get all UUID metadata
    get_all_uuid_metadata(pubnub)

if __name__ == "__main__":
    main()
```

Asynchronous:

```python
import os
from pubnub.pnconfiguration import PNConfiguration
from pubnub.pubnub import PubNub
from pubnub.models.consumer.objects_v2.sort import PNSortKey, PNSortKeyValue

def callback(response, status):
    if status.is_error():
        print(f"Error: {status.error_data}")
    else:
        for uuid_data in response.data:
            print(f"UUID: {uuid_data["id"]}")
            print(f"Name: {uuid_data["name"]}")
            print(f"Custom: {uuid_data["custom"]}")

def get_all_uuid_metadata(pubnub: PubNub):
    pubnub.get_all_uuid_metadata(
        limit=10,
        include_custom=True,
        include_total_count=True,
        sort_keys=[PNSortKey.asc(PNSortKeyValue.ID), PNSortKey.desc(PNSortKeyValue.UPDATED)]
    ).pn_async(callback)

def main():
    # Configuration for PubNub instance
    pn_config = PNConfiguration()
    pn_config.subscribe_key = os.getenv('SUBSCRIBE_KEY', 'demo')
    pn_config.user_id = os.getenv('USER_ID', 'my_custom_user_id')

    # Initialize PubNub client
    pubnub = PubNub(pn_config)

    # Get all UUID metadata
    get_all_uuid_metadata(pubnub)

if __name__ == "__main__":
    main()
```

##### Returns

The `get_all_uuid_metadata()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNGetAllUUIDMetadataResult](#pngetalluuidmetadataresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

#### PNGetAllUUIDMetadataResult

| Property Name | Type | Description |
| --- | --- | --- |
| `data` | [] | List of dictionaries containing UUID metadata |
| `status` | PNStatus | Status of the operation |

Each element in `data` contains a dictionary with UUID metadata.

| Key | Description |
| --- | --- |
| `id` | UUID |
| `name` | Name associated with UUID object |
| `externalId` | External ID associated with UUID object |
| `profileUrl` | Profile URL associated with UUID object |
| `email` | Email address associated with UUID object |
| `custom` | Custom object associated with UUID object in form of dictionary containing string to string pairs |
| `status` | User status value |
| `type` | User type value |

### Get user metadata

Fetch metadata for a single UUID. Include the Custom object if you need custom fields.

#### Method(s)

To `Get UUID Metadata` you can use the following method(s) in the Python SDK:

```python
pubnub.get_uuid_metadata() \
        .uuid(String) \
        .include_custom(Boolean)
```

| Parameter | Description |
| --- | --- |
| `uuid`Type: StringDefault: `pubnub.configuration.uuid` | Unique UUID Metadata identifier. If not supplied, then UUID from configuration will be used. |
| `include_custom`Type: BooleanDefault: `False` | Whether to include the Custom object in the response. |
| `include_status`Type: BooleanDefault: `True` | Whether to include the `status` field in the fetch response, which is included by default. |
| `include_type`Type: BooleanDefault: `True` | Whether to include the `type` field in the fetch response, which is included by default. |

#### Sample code

##### Builder Pattern

Synchronous:

```python
pubnub.get_uuid_metadata() \
    .include_custom(True) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.get_uuid_metadata() \
    .include_custom(True) \
    .pn_async(callback)
```

##### Named Arguments

Synchronous:

```python
metadata = pubnub.get_uuid_metadata(include_custom=True).sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

metadata = pubnub.get_uuid_metadata(include_custom=True).pn_async(callback)
```

##### Returns

The `get_uuid_metadata()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNGetUUIDMetadataResult](#pngetuuidmetadataresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

##### PNGetUUIDMetadataResult

operation returns a `PNGetUUIDMetadataResult` which contains the following properties:

| Property Name | Type | Description |
| --- | --- | --- |
| `data` |  | Dictionary containing UUID metadata |
| `status` | PNStatus | Status of the operation |

Where each element in `data` contains a dictionary with UUID metadata.

| Key | Description |
| --- | --- |
| `id` | UUID |
| `name` | Name associated with UUID object |
| `externalId` | External ID associated with UUID object |
| `profileUrl` | Profile URL associated with UUID object |
| `email` | Email address associated with UUID object |
| `status` | Status value associated with UUID object |
| `type` | Type value associated with UUID object |
| `custom` | Custom object associated with UUID object in form of dictionary containing string to string pairs |

### Set user metadata

Create or update metadata for a UUID. Use the eTag to avoid overwriting concurrent updates.

:::warning Unsupported partial updates of custom metadata
The value of the custom metadata parameter sent in this method always overwrites the value stored on PubNub servers. If you want to add new custom data to an existing one, you must:
1. Get the existing metadata and store it locally.
2. Append the new custom metadata to the existing one.
3. Set the entire updated custom object.
:::

#### Method(s)

To `Set UUID Metadata` you can use the following method(s) in the Python SDK:

```python
pubnub.set_uuid_metadata() \
    .uuid(String) \
    .set_name(String) \
    .set_status(String) \
    .set_type(String) \
    .external_id(String) \
    .profile_url(String) \
    .email(String) \
    .custom(Dictionary) \
    .include_custom(Boolean) \
    .include_status(Boolean) \
    .include_type(Boolean) \
    .if_matches_etag(String)
```

| Parameter | Description |
| --- | --- |
| `uuid`Type: StringDefault: `pubnub.configuration.uuid` | Unique UUID Metadata identifier. If not supplied, then UUID from configuration will be used. |
| `set_name`Type: StringDefault: N/A | Display name for the user. |
| `set_status`Type: StringDefault: N/A | User status. Max. 50 characters. |
| `set_type`Type: StringDefault: N/A | User type. Max. 50 characters. |
| `external_id`Type: StringDefault: N/A | User's identifier in an external system. |
| `profile_url`Type: StringDefault: N/A | The URL of the user's profile picture. |
| `email`Type: StringDefault: N/A | The user's email address. |
| `custom`Type: `Any`Default: N/A | Any object of key-value pairs with supported data types. [App Context filtering language](https://www.pubnub.com/docs/general/metadata/filtering) doesn't support filtering by custom properties. |
| `include_custom`Type: BooleanDefault: `False` | Whether to include the Custom object in the response. |
| `include_status`Type: BooleanDefault: `False` | Whether to include the `status` object in the fetch response. |
| `include_type`Type: BooleanDefault: `False` | Whether to include the `type` object in the fetch response. |
| `if_matches_etag`Type: StringDefault: n/a | The entity tag to be used to ensure updates only happen if the object hasn't been modified since it was read. Use the eTag you received from an applicable get metadata method to check against the server entity tag. If the eTags don't match, an HTTP 412 error is thrown. |

:::tip API limits
To learn about the maximum length of parameters used to set user metadata, refer to [REST API docs](https://www.pubnub.com/docs/sdks/rest-api/set-user-metadata).
:::

#### Sample code

##### Builder Pattern

Synchronous:

```python
pubnub.set_uuid_metadata() \
    .include_custom(True) \
    .uuid("Some UUID") \
    .set_name("Some Name") \
    .set_status("Active") \
    .set_type("User") \
    .email("test@example.com") \
    .profile_url("http://example.com") \
    .external_id("1234567890") \
    .custom({"key1": "val1", "key2": "val2"}) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.set_uuid_metadata() \
    .include_custom(True) \
    .uuid("Some UUID") \
    .set_name("Some Name") \
    .set_status("Active") \
    .set_type("User") \
    .email("test@example.com") \
    .profile_url("http://example.com") \
    .external_id("1234567890") \
    .custom({"key1": "val1", "key2": "val2"}) \
    pn_async(callback)
```

##### Named Arguments

Synchronous:

```python
pubnub.set_uuid_metadata(uuid="Some UUID",
                         name="Some Name",
                         status="Active", type="User",
                         email="test@example.com",
                         profile_url="http://example.com",
                         external_id="1234567890",
                         custom={"key1": "val1", "key2": "val2"}) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.set_uuid_metadata(uuid="Some UUID",
                         name="Some Name",
                         status="Active", type="User",
                         email="test@example.com",
                         profile_url="http://example.com",
                         external_id="1234567890",
                         custom={"key1": "val1", "key2": "val2"}) \
    .pn_async(callback)
```

##### Returns

The `set_uuid_metadata()` returns a `PNSetUUIDMetadataResult` which contains the following properties:

| Property Name | Type | Description |
| --- | --- | --- |
| `data` |  | Dictionary containing UUID metadata |
| `status` | PNStatus | Status of the operation |

Where each element in `data` contains a dictionary with UUID metadata.

| Key | Description |
| --- | --- |
| `id` | UUID |
| `name` | Name associated with UUID object |
| `externalId` | External ID associated with UUID object |
| `profileUrl` | Profile URL associated with UUID object |
| `email` | Email address associated with UUID object |
| `status` | User status |
| `type` | User type |
| `custom` | Custom object associated with UUID object in form of dictionary containing string to string pairs |

### Remove user metadata

Delete metadata for the specified UUID.

#### Method(s)

To `Remove UUID Metadata` you can use the following method(s) in the Python SDK:

```python
pubnub.remove_uuid_metadata() \
    .uuid(String)
```

| Parameter | Description |
| --- | --- |
| `uuid`Type: StringDefault: `pubnub.configuration.uuid` | Unique UUID Metadata identifier. If not supplied, then UUID from configuration will be used. |

#### Sample code

##### Builder Pattern

Synchronous:

```python
pubnub.remove_uuid_metadata() \
        .uuid("Some UUID").sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.remove_uuid_metadata() \
        .uuid("Some UUID").pn_async(callback)
```

##### Named Arguments

```python
pubnub.remove_uuid_metadata(uuid="Some UUID").sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.remove_uuid_metadata(uuid="Some UUID").pn_async(callback)
```

##### Returns

The `remove_uuid_metadata()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNRemoveUUIDMetadataResult](#pnremoveuuidmetadataresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

##### PNRemoveUUIDMetadataResult

| Property Name | Type | Description |
| --- | --- | --- |
| `status` | PNStatus | Status of the operation |

## Channel

Manage channel metadata: list, fetch, set, and remove.

### Get metadata for all channels

Get a paginated list of channel metadata. Use filters and sorting to narrow results.

:::warning Required keyset configuration
To get all channel and user metadata, you must uncheck the
Disallow Get All Channel Metadata
and
Disallow Get All User Metadata
checkboxes in the App Context section of your keyset configuration in the
[Admin Portal](https://admin.pubnub.com)
.
:::

#### Method(s)

To `Get All Channel Metadata` you can use the following method(s) in the Python SDK:

```python
pubnub.get_all_channel_metadata() \
    .limit(Integer) \
    .page(PNPage) \
    .filter(String) \
    .sort(PNSortKey) \
    .include_total_count(Boolean) \
    .include_custom(Boolean) \
    .include_status(Boolean) \
    .include_type(Boolean)
```

| Parameter | Description |
| --- | --- |
| `limit`Type: IntegerDefault: 100 | The maximum number of objects to retrieve at a time. |
| `page`Type: `PNPage`Default: N/A | The paging object used for pagination. |
| `filter`Type: StringDefault: N/A | Expression used to filter the results. Only objects whose properties satisfy the given expression are returned. The filter language is defined [here](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `[PNSortKey]`Default: N/A | List of properties to sort by. Available options are `id`, `name`, and `updated`. Use `asc` or `desc` to specify sort direction. For example: `{name: 'asc'}`. |
| `include_total_count`Type: BooleanDefault: `False` | Whether to include the total count in the paginated response. Default is false. |
| `include_custom`Type: BooleanDefault: `False` | Whether to include the Custom object in the response. |
| `include_status`Type: BooleanDefault: `True` | Whether to include the `status` field in the fetch response. Setting this to `False` will prevent this value from being returned. |
| `include_type`Type: BooleanDefault: `True` | Whether to include the `type` field in the fetch response. Setting this to `False` will prevent this value from being returned. |

#### Sample code

##### Builder Pattern

Synchronous:

```python
pubnub.get_all_channel_metadata() \
    .include_custom(True) \
    .limit(10) \
    .include_total_count(True) \
    .sort(PNSortKey.asc(PNSortKeyValue.ID), PNSortKey.desc(PNSortKeyValue.UPDATED)) \
    .page(None) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.get_all_channel_metadata() \
    .include_custom(True) \
    .limit(10) \
    .include_total_count(True) \
    .sort(PNSortKey.asc(PNSortKeyValue.ID), PNSortKey.desc(PNSortKeyValue.UPDATED)) \
    .page(None) \
    .pn_async(callback)
```

##### Named Arguments

Synchronous:

```python
metadata = pubnub.get_all_channel_metadata(limit=10,
                                           include_custom=True,
                                           include_total_count=True,
                                           sort=[PNSortKey.asc(PNSortKeyValue.ID), PNSortKey.desc(PNSortKeyValue.UPDATED)]) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.get_all_channel_metadata(limit=10,
                                include_custom=True,
                                include_total_count=True,
                                sort=[PNSortKey.asc(PNSortKeyValue.ID), PNSortKey.desc(PNSortKeyValue.UPDATED)]) \
    .pn_async(callback)
```

#### Returns

The `get_all_channel_metadata()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNGetAllChannelMetadataResult](#pngetallchannelmetadataresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

##### PNGetAllChannelMetadataResult

| Property Name | Type | Description |
| --- | --- | --- |
| `data` | [] | List of dictionaries containing channel metadata |
| `status` | PNStatus | Status of the operation |

Where each element in `data` contains a dictionary with channel metadata.

| Key | Description |
| --- | --- |
| `id` | Channel metadata ID |
| `name` | Name associated with channel metadata object |
| `description` | Description associated with channel metadata object |
| `status` | Channel status value |
| `type` | Channel type value |
| `custom` | Custom object associated with channel metadata object in form of dictionary containing string to string pairs |

### Get channel metadata

Fetch metadata for a single channel. Include the Custom object if you need custom fields.

#### Method(s)

To `Get Channel Metadata` you can use the following method(s) in the Python SDK:

```python
pubnub.get_channel_metadata() \
    .channel(String) \
    .include_custom(Boolean) \
    .include_status(Boolean) \
    .include_type(Boolean)
```

| Parameter | Description |
| --- | --- |
| `channel`Type: `str`Default: n/a | Channel name |
| `include_custom`Type: `bool`Default: `False` | Whether to include the `custom` object in the fetch response. |
| `include_status`Type: BooleanDefault: `True` | Whether to include the `status` field in the fetch response. Setting this to `False` will prevent this value from being returned. |
| `include_type`Type: BooleanDefault: `True` | Whether to include the `type` field in the fetch response. Setting this to `False` will prevent this value from being returned. |

#### Sample code

##### Builder Pattern

Synchronous:

```python
pubnub.get_channel_metadata() \
    .include_custom(True) \
    .channel("channel") \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.get_channel_metadata() \
    .include_custom(True) \
    .channel("channel") \
    .pn_async(callback)
```

##### Named Arguments

Synchronous:

```python
pubnub.get_channel_metadata(channel="channel", include_custom=True).sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.get_channel_metadata(channel="channel", include_custom=True).pn_async(callback)
```

##### Returns

The `get_channel_metadata()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNGetChannelMetadataResult](#pngetchannelmetadataresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

##### PNGetChannelMetadataResult

| Property Name | Type | Description |
| --- | --- | --- |
| `data` |  | Dictionary containing channel metadata |
| `status` | PNStatus | Status of the operation |

Where each element in `data` contains a dictionary with channel metadata.

| Key | Description |
| --- | --- |
| `id` | Channel metadata ID |
| `name` | Name associated with channel metadata object |
| `description` | Description associated with channel metadata object |
| `status` | Channel status value |
| `type` | Channel type value |
| `custom` | Custom object associated with channel metadata object in form of dictionary containing string to string pairs |

### Set channel metadata

Create or update metadata for a channel. Use the eTag to avoid overwriting concurrent updates.

Set metadata for a channel in the database, optionally including its custom data object.

:::warning Unsupported partial updates of custom metadata
The value of the custom metadata parameter sent in this method always overwrites the value stored on PubNub servers. If you want to add new custom data to an existing one, you must:
1. Get the existing metadata and store it locally.
2. Append the new custom metadata to the existing one.
3. Set the entire updated custom object.
:::

#### Method(s)

To `Set Channel Metadata` you can use the following method(s) in the Python SDK:

```python
pubnub.set_channel_metadata() \
    .channel(String) \
    .set_name(String) \
    .set_status(String) \
    .set_type(String) \
    .description(String) \
    .custom(Dictionary) \
    .include_custom(Boolean) \
    .include_status(Boolean) \
    .include_type(Boolean) \
    .if_matches_etag(String)
```

| Parameter | Description |
| --- | --- |
| `channel`Type: StringDefault: n/a | Channel ID. |
| `set_name`Type: StringDefault: N/A | Name of the channel. |
| `set_status`Type: StringDefault: N/A | Channel status. Max. 50 characters. |
| `set_type`Type: StringDefault: N/A | Channel type. Max. 50 characters. |
| `description`Type: StringDefault: N/A | Description of a channel. |
| `custom`Type: `Map<String, Object>`Default: N/A | Any object of key-value pairs with supported data types. [App Context filtering language](https://www.pubnub.com/docs/general/metadata/filtering) doesn't support filtering by custom properties. |
| `include_custom`Type: BooleanDefault: `False` | Whether to include the `custom` object in the fetch response. |
| `include_status`Type: BooleanDefault: `False` | Whether to include the `status` object in the fetch response. |
| `include_type`Type: BooleanDefault: `False` | Whether to include the `type` object in the fetch response. |
| `if_matches_etag`Type: StringDefault: n/a | The entity tag to be used to ensure updates only happen if the object hasn't been modified since it was read. Use the eTag you received from an applicable get metadata method to check against the server entity tag. If the eTags don't match, an HTTP 412 error is thrown. |

:::tip API limits
To learn about the maximum length of parameters used to set channel metadata, refer to [REST API docs](https://www.pubnub.com/docs/sdks/rest-api/set-channel-metadata).
:::

#### Sample code

##### Builder Pattern

Synchronous:

```python
pubnub.set_channel_metadata() \
    .include_custom(True) \
    .channel("channel id") \
    .set_name("Channel Name") \
    .set_status("Archived") \
    .set_type("Archived") \
    .description("Description") \
    .custom({ "key1": "val1", "key2": "val2" }) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.set_channel_metadata() \
    .include_custom(True) \
    .channel("channel id") \
    .set_name("Channel Name") \
    .set_status("Archived") \
    .set_type("Archived") \
    .description("Description") \
    .custom({ "key1": "val1", "key2": "val2" }) \
    .pn_async(callback)
```

##### Named Arguments

Synchronous:

```python
pubnub.set_channel_metadata(channel="channel id",
                            name="Channel Name",
                            status="Archived",
                            type="Archived",
                            description="Description",
                            custom={ "key1": "val1", "key2": "val2" },
                            include_custom=True) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.set_channel_metadata(channel="channel id",
                            name="Channel Name",
                            status="Archived",
                            type="Archived",
                            description="Description",
                            custom={ "key1": "val1", "key2": "val2" },
                            include_custom=True) \
    .pn_async(callback)
```

##### Returns

The `set_channel_metadata()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNSetChannelMetadataResult](#pnsetchannelmetadataresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

##### PNSetChannelMetadataResult

| Property Name | Type | Description |
| --- | --- | --- |
| `data` |  | Dictionary containing channel metadata |
| `status` | PNStatus | Status of the operation |

Where each element in `data` contains a dictionary with channel metadata.

| Key | Description |
| --- | --- |
| `id` | channel metadata id |
| `name` | Name associated with channel metadata object |
| `description` | Description associated with channel metadata object |
| `status` | Channels status value |
| `type` | Channels type value |
| `custom` | Custom object associated with channel metadata object in form of dictionary containing string to string pairs |

#### Other examples

##### Iteratively update existing metadata

```python
from pprint import pprint
from pubnub.pubnub import PubNub
from pubnub.pnconfiguration import PNConfiguration

config = PNConfiguration()
config.publish_key = 'demo'
config.subscribe_key = 'demo'
config.user_id = 'example'

channel = "demo_example"
help_string = "\tTo exit type '/exit'\n\tTo show the current object type '/show'\n\tTo show this help type '/help'\n"

pubnub = PubNub(config)

print(f"We're setting the channel's {channel} additional info. \n{help_string}\n")

name = input("Enter the channel name: ")
description = input("Enter the channel description: ")

# Setting the basic channel info
set_result = pubnub.set_channel_metadata(
    channel,
    name=name,
    description=description,
).sync()
print("The channel has been created with name and description.\n")

# We start to iterate over the custom fields
while True:
    # First we have to get the current object to know what fields are already set
    current_object = pubnub.get_channel_metadata(
        channel,
        include_custom=True,
        include_status=True,
        include_type=True
    ).sync()

    # Gathering new data
    field_name = input("Enter the field name: ")
    if field_name == '/exit':
        break
    if field_name == '/show':
        pprint(current_object.result.data, indent=2)
        print()
        continue
    if field_name == '/help':
        print(help_string, end="\n\n")
        continue

    field_value = input("Enter the field value: ")

    # We may have to initialize the custom field
    custom = current_object.result.data.get('custom', {})
    if custom is None:
        custom = {}

    # We have to check if the field already exists and
    if custom.get(field_name):
        confirm = input(f"Field {field_name} already has a value. Overwrite? (y/n):").lower()
        while confirm not in ['y', 'n']:
            confirm = input("Please enter 'y' or 'n': ").lower()
        if confirm == 'n':
            print("Object will not be updated.\n")
            continue
        if confirm == 'y':
            custom[field_name] = field_value
    else:
        custom[field_name] = field_value

    # Writing the updated object back to the server
    set_result = pubnub.set_channel_metadata(
        channel,
        custom=custom,
        name=current_object.result.data.get('name'),
        description=current_object.result.data.get('description')
    ).sync()
    print("Object has been updated.\n")
```

### Remove channel metadata

Delete metadata for the specified channel.

Removes the metadata from a specified channel.

#### Method(s)

To `Remove Channel Metadata` you can use the following method(s) in the Python SDK:

```python
pubnub.remove_channel_metadata() \
    .channel(String)
```

| Parameter | Description |
| --- | --- |
| `channel`Type: StringDefault: n/a | Channel name |

#### Sample code

##### Builder Pattern

Synchronous:

```python
pubnub.remove_channel_metadata() \
    .channel("channel id") \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.remove_channel_metadata() \
    .channel("channel id") \
    .pn_async(callback)
```

##### Named Arguments

Synchronous:

```python
pubnub.remove_channel_metadata(channel="channel id").sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.remove_channel_metadata(channel="channel id").pn_async(callback)
```

##### Returns

The `remove_channel_metadata()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNRemoveChannelMetadataResult](#pnremovechannelmetadataresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

##### PNRemoveChannelMetadataResult

| Property Name | Type | Description |
| --- | --- | --- |
| `status` | PNStatus | Status of the operation |

## Channel memberships

Manage the channels a UUID belongs to: list, set, remove, and manage in bulk.

### Get channel memberships

List channel memberships for a UUID. This does not return subscriptions.

#### Method(s)

To `Get Channel Memberships` you can use the following method(s) in the Python SDK:

```python
pubnub.get_memberships() \
    .uuid(String) \
    .limit(Integer) \
    .page(PNPage Object) \
    .filter(String) \
    .sort(* PNSortKey Object) \
    .include(MembershipIncludes)
```

| Parameter | Description |
| --- | --- |
| `uuid`Type: StringDefault: `pubnub.configuration.uuid` | Unique UUID Metadata identifier. If not supplied, then UUID from configuration will be used. |
| `limit`Type: IntegerDefault: 100 | The maximum number of objects to retrieve at a time |
| `page`Type: `PNPage`Default: N/A | The paging object used for pagination |
| `filter`Type: StringDefault: N/A | Expression used to filter the results. Only objects whose properties satisfy the given expression are returned. The filter language is defined [here](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `PNSortKey`Default: N/A | List of properties to sort by. Available options are `id`, `name`, and `updated`. Use `asc` or `desc` to specify sort direction. For example: `{name: 'asc'}` |
| `include`Type: `MembershipIncludes`Default: n/a | The additional information to include in the membership response. |
| `> total_count`Type: BooleanDefault: `False` | Request `totalCount` to be included in paginated response, which is omitted by default |
| `> custom`Type: BooleanDefault: `False` | Indicates whether custom data should be included in the response. |
| `> status`Type: BooleanDefault: `False` | Indicates whether the status should be included in the response. |
| `> type`Type: BooleanDefault: `False` | Indicates whether the type should be included in the response. |
| `> total_count`Type: BooleanDefault: `False` | Indicates whether the total count should be included in the response. |
| `> channel`Type: BooleanDefault: `False` | Indicates whether the channel information should be included in the response. |
| `> channel_custom`Type: BooleanDefault: `False` | Indicates whether custom data for the channel should be included in the response. |
| `> channel_type`Type: BooleanDefault: `False` | Indicates whether the type of the channel should be included in the response. |
| `> channel_status`Type: BooleanDefault: `False` | Indicates whether the status of the channel should be included in the response. |

#### Sample code

##### Builder Pattern

Synchronous:

```python
pubnub.get_memberships() \
    .include(MembershipIncludes(custom=True, channel=True, channel_custom=True)) \
    .uuid("Some UUID").sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.get_memberships() \
    .include(MembershipIncludes(custom=True, channel=True, channel_custom=True)) \
    .uuid("Some UUID").pn_async(callback)
```

##### Named Arguments

Synchronous:

```python
pubnub.get_memberships(uuid="Some UUID",
                       include=MembershipIncludes(custom=True, channel=True, channel_custom=True))
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.get_memberships(uuid="Some UUID",
                       include=.MembershipIncludes(custom=True, channel=True, channel_custom=True))
    .pn_async(callback)
```

##### Returns

The `get_memberships()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNGetMembershipsResult](#pngetmembershipsresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

##### PNGetMembershipsResult

| Property Name | Type | Description |
| --- | --- | --- |
| `data` |  | List of dictionaries containing memberships metadata |
| `status` | PNStatus | Status of the operation |
| `total_count` | `int` | Total count of results (if `include_total_count` was set) |
| `prev` | `PNPage.Previous` | PNPage instance to be used if further requests |
| `next` | `PNPage.Next` | PNPage instance to be used if further requests |

Where each element in `data` contains a dictionary with membership metadata.

| Key | Description |
| --- | --- |
| `channel` | Dictionary containing channel metadata (id, name, description, custom) |
| `custom` | Custom object associated with membership in form of dictionary containing string to string pairs |

### Set channel memberships

Replace or add memberships for a UUID. Provide channels (optionally with custom data).

Set channel memberships for a UUID.

#### Method(s)

To `Set Channel Memberships` you can use the following method(s) in the Python SDK:

```python
pubnub.set_memberships() \
    .channel_memberships([PNChannelMembership]) \
    .uuid(String) \
    .limit(Integer) \
    .page(PNPage) \
    .filter(String) \
    .sort(* PNSort Object) \
    .include(MembershipIncludes)
```

| Parameter | Description |
| --- | --- |
| `channelMemberships`Type: `[PNChannelMembership]`Default: n/a | Collection of [PNChannelMembership](#pnchannelmembership-class) to add to membership |
| `uuid`Type: StringDefault: `pubnub.configuration.uuid` | Unique UUID Metadata identifier. If not supplied, then UUID from configuration will be used. |
| `limit`Type: IntegerDefault: 100 | The maximum number of objects to retrieve at a time |
| `page`Type: `PNPage`Default: N/A | The paging object used for pagination |
| `filter`Type: StringDefault: N/A | Expression used to filter the results. Only objects whose properties satisfy the given expression are returned. The filter language is defined [here](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `PNSortKey`Default: N/A | List of properties to sort by. Available options are `id`, `name`, and `updated`. Use `asc` or `desc` to specify sort direction. For example: `{name: 'asc'}` |
| `include`Type: `MembershipIncludes`Default: n/a | The additional information to include in the membership response. |
| `> total_count`Type: BooleanDefault: `False` | Request `totalCount` to be included in paginated response, which is omitted by default |
| `> custom`Type: BooleanDefault: `False` | Indicates whether custom data should be included in the response. |
| `> status`Type: BooleanDefault: `False` | Indicates whether the status should be included in the response. |
| `> type`Type: BooleanDefault: `False` | Indicates whether the type should be included in the response. |
| `> total_count`Type: BooleanDefault: `False` | Indicates whether the total count should be included in the response. |
| `> channel`Type: BooleanDefault: `False` | Indicates whether the channel information should be included in the response. |
| `> channel_custom`Type: BooleanDefault: `False` | Indicates whether custom data for the channel should be included in the response. |
| `> channel_type`Type: BooleanDefault: `False` | Indicates whether the type of the channel should be included in the response. |
| `> channel_status`Type: BooleanDefault: `False` | Indicates whether the status of the channel should be included in the response. |

:::tip API limits
To learn about the maximum length of parameters used to set channel membership metadata, refer to [REST API docs](https://www.pubnub.com/docs/sdks/rest-api/set-membership-metadata).
:::

#### Sample code

##### Builder Pattern

Synchronous:

```python
some_channel = "somechannel"
some_channel_with_custom = "somechannel_with_custom"

pubnub.set_channel_metadata() \
    .channel(some_channel) \
    .set_name("some name") \
    .sync()

custom_1 = {
    "key3": "val1",
    "key4": "val2",
}

pubnub.set_channel_metadata() \
    .channel(some_channel_with_custom) \
    .set_name("some name with custom") \
    .custom(custom_1) \
    .sync()

custom_2 = {
    "key5": "val1",
    "key6": "val2",
}

channel_memberships_to_set = [
    PNChannelMembership.channel(some_channel),
    PNChannelMembership.channel_with_custom(some_channel_with_custom, custom_2),
]

pubnub.set_memberships() \
    .uuid("some-uuid") \
    .channel_memberships(channel_memberships_to_set) \
    .include(MembershipIncludes(custom=True, channel=True, channel_custom=True)) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

some_channel = "somechannel"
some_channel_with_custom = "somechannel_with_custom"

pubnub.set_channel_metadata() \
    .channel(some_channel) \
    .set_name("some name") \
    .sync()

custom_1 = {
    "key3": "val1",
    "key4": "val2"
}

pubnub.set_channel_metadata() \
    .channel(some_channel_with_custom) \
    .set_name("some name with custom") \
    .custom(custom_1) \
    .sync()

custom_2 = {
    "key5": "val1",
    "key6": "val2",
}

channel_memberships_to_set = [
    PNChannelMembership.channel(some_channel),
    PNChannelMembership.channel_with_custom(some_channel_with_custom, custom_2),
]

pubnub.set_memberships() \
    .uuid("some-uuid") \
    .channel_memberships(channel_memberships_to_set) \
    .include(MembershipIncludes(custom=True, channel=True, channel_custom=True)) \
    .pn_async(callback)
```

##### Named Arguments

Synchronous:

```python
some_channel = "somechannel"
some_channel_with_custom = "somechannel_with_custom"

pubnub.set_channel_metadata(channel=some_channel, name="some name").sync()

custom_1 = {
    "key3": "val1",
    "key4": "val2",
}

pubnub.set_channel_metadata(channel=some_channel_with_custom,
                            name="some name with custom",
                            custom=custom_1) \
    .sync()

custom_2 = {
    "key5": "val1",
    "key6": "val2",
}

channel_memberships_to_set = [
    PNChannelMembership.channel(some_channel),
    PNChannelMembership.channel_with_custom(some_channel_with_custom, custom_2),
]

pubnub.set_memberships(uuid="some-uuid",
                       channel_memberships=channel_memberships_to_set,
                       include(MembershipIncludes(custom=True, channel=True, channel_custom=True))) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

some_channel = "somechannel"
some_channel_with_custom = "somechannel_with_custom"

pubnub.set_channel_metadata(channel=some_channel, name="some name").pn_async(callback)

custom_1 = {
    "key3": "val1",
    "key4": "val2"
}

pubnub.set_channel_metadata(channel=some_channel_with_custom,
                            name="some name with custom",
                            custom=custom_1) \
    .pn_async(callback)

custom_2 = {
    "key5": "val1",
    "key6": "val2",
}

channel_memberships_to_set = [
    PNChannelMembership.channel(some_channel),
    PNChannelMembership.channel_with_custom(some_channel_with_custom, custom_2),
]

pubnub.set_memberships(uuid="some-uuid",
                       channel_memberships=channel_memberships_to_set,
                       include(MembershipIncludes(custom=True, channel=True, channel_custom=True))) \
    .pn_async(callback)
```

##### Returns

The `set_memberships()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNSetMembershipsResult](#pnsetmembershipsresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

##### PNSetMembershipsResult

| Property Name | Type | Description |
| --- | --- | --- |
| `data` |  | List of dictionaries containing memberships metadata |
| `status` | PNStatus | Status of the operation |
| `total_count` | `int` | Total count of results (if `include_total_count` was set) |
| `prev` | `PNPage.Previous` | PNPage instance to be used if further requests |
| `next` | `PNPage.Next` | PNPage instance to be used if further requests |

Where each element in `data` contains a dictionary with membership metadata.

| Key | Description |
| --- | --- |
| `channel` | Dictionary containing channel metadata (id, name, description, custom) |
| `custom` | Custom object associated with membership in form of dictionary containing string to string pairs |

### Remove channel memberships

Remove memberships for a UUID. Provide the channels to remove.

#### Method(s)

To `Remove Channel Memberships` you can use the following method(s) in the Python SDK:

```python
pubnub.remove_memberships() \
    .channel_memberships([PNChannelMembership]) \
    .uuid(String) \
    .limit(Integer) \
    .page(PNPage) \
    .filter(String) \
    .sort(* PNSort) \
    .include_total_count(Boolean) \
    .include_custom(Boolean) \
    .include_channel(Integer)
```

| Parameter | Description |
| --- | --- |
| `channel_memberships`Type: `[PNChannelMembership]`Default: n/a | List of channels (as [PNChannelMembership](#pnchannelmembership-class)) to remove from membership. |
| `uuid`Type: StringDefault: `pubnub.configuration.uuid` | Unique UUID Metadata identifier. If not supplied, then UUID from configuration will be used. |
| `limit`Type: IntegerDefault: 100 | The maximum number of objects to retrieve at a time. |
| `page`Type: `PNPage`Default: N/A | The paging object used for pagination. |
| `filter`Type: StringDefault: N/A | Expression used to filter the results. Only objects whose properties satisfy the given expression are returned. The filter language is defined [here](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `PNSortKey`Default: N/A | List of properties to sort by. Available options are `id`, `name`, and `updated`. Use `asc` or `desc` to specify sort direction. For example: `{name: 'asc'}` |
| `include_total_count`Type: BooleanDefault: `False` | Whether to include the total count in the paginated response. Default is false. |
| `include_custom`Type: BooleanDefault: `False` | Whether to include the `custom` object in the fetch response. |
| `include_channel`Type: IntegerDefault: N/A | The level of channel details to return in the membership. Possible values are defined as constants in `ChannelIncludeEndpoint`: `ChannelIncludeEndpoint.CHANNEL` and `ChannelIncludeEndpoint.CHANNEL_WITH_CUSTOM` |

#### Sample code

##### Builder Pattern

Synchronous:

```python
pubnub.remove_memberships() \
    .uuid("some_uuid") \
    .channel_memberships([PNChannelMembership.channel(some_channel)]) \
    .include_custom(True) \
    .include_channel(ChannelIncludeEndpoint.CHANNEL_WITH_CUSTOM) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.remove_memberships() \
    .uuid("some_uuid") \
    .channel_memberships([PNChannelMembership.channel(some_channel)]) \
    .include_custom(True) \
    .include_channel(ChannelIncludeEndpoint.CHANNEL_WITH_CUSTOM) \
    .pn_async(callback)
```

##### Named Arguments

Synchronous:

```python
pubnub.remove_memberships(uuid="some_uuid",
                          channel_memberships=[PNChannelMembership.channel(some_channel)],
                          include_channel=ChannelIncludeEndpoint.CHANNEL_WITH_CUSTOM
                          include_custom=True) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.remove_memberships(uuid="some_uuid",
                          channel_memberships=[PNChannelMembership.channel(some_channel)],
                          include_channel=ChannelIncludeEndpoint.CHANNEL_WITH_CUSTOM
                          include_custom=True) \
    .pn_async(callback)
```

##### Returns

The `remove_memberships()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNRemoveMembershipsResult](#pnremovemembershipsresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

##### PNRemoveMembershipsResult

| Property Name | Type | Description |
| --- | --- | --- |
| `data` |  | List of dictionaries containing memberships metadata |
| `status` | `PNStatus` | Status of the operation |
| `total_count` | `int` | Total count of results (if `include_total_count` was set) |
| `prev` | `PNPage.Previous` | PNPage instance to be used if further requests |
| `next` | `PNPage.Next` | PNPage instance to be used if further requests |

Where each element in `data` contains a dictionary with membership metadata.

| Key | Description |
| --- | --- |
| `channel` | Dictionary containing channel metadata (id, name, description, custom) |
| `custom` | Custom object associated with membership in form of dictionary containing string to string pairs |

### Manage channel memberships

Add and remove memberships for a UUID in one request.

#### Method(s)

To `Manage Channel Memberships` you can use the following method(s) in the Python SDK:

```python
pubnub.manage_memberships() \
    .uuid(String) \
    .set([PNChannelMembership>]) \
    .remove([PNChannelMembership]) \
    .limit(Integer) \
    .page(PNPage) \
    .filter(String) \
    .sort(* PNSortKey) \
    .include(MembershipIncludes)
```

| Parameter | Description |
| --- | --- |
| `uuid`Type: StringDefault: `pubnub.configuration.uuid` | Unique UUID Metadata identifier. If not supplied, then UUID from configuration will be used. |
| `set`Type: `[PNChannelMembership]`Default: n/a | List of members [PNChannelMembership](#pnchannelmembership-class) to add to channel |
| `remove`Type: `[PNChannelMembership]`Default: n/a | List of members [PNChannelMembership](#pnchannelmembership-class) to remove from channel |
| `limit`Type: IntegerDefault: 100 | The maximum number of objects to retrieve at a time |
| `page`Type: `PNPage`Default: `null` | The paging object used for pagination |
| `filter`Type: StringDefault: `null` | Expression used to filter the results. Only objects whose properties satisfy the given expression are returned. The filter language is defined [here](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `PNSortKey`Default: N/A | List of properties to sort by. Available options are `id`, `name`, and `updated`. Use `asc` or `desc` to specify sort direction. For example: `{name: 'asc'}` |
| `include`Type: `MembershipIncludes`Default: n/a | The additional information to include in the membership response. |
| `> total_count`Type: BooleanDefault: `False` | Request `totalCount` to be included in paginated response, which is omitted by default |
| `> custom`Type: BooleanDefault: `False` | Indicates whether custom data should be included in the response. |
| `> status`Type: BooleanDefault: `False` | Indicates whether the status should be included in the response. |
| `> type`Type: BooleanDefault: `False` | Indicates whether the type should be included in the response. |
| `> total_count`Type: BooleanDefault: `False` | Indicates whether the total count should be included in the response. |
| `> channel`Type: BooleanDefault: `False` | Indicates whether the channel information should be included in the response. |
| `> channel_custom`Type: BooleanDefault: `False` | Indicates whether custom data for the channel should be included in the response. |
| `> channel_type`Type: BooleanDefault: `False` | Indicates whether the type of the channel should be included in the response. |
| `> channel_status`Type: BooleanDefault: `False` | Indicates whether the status of the channel should be included in the response. |

#### Sample code

##### Builder Pattern

Synchronous:

```python
pubnub.manage_memberships() \
    .uuid("some_uuid") \
    .set([PNChannelMembership.channel(some_channel)]) \
    .remove([PNChannelMembership.channel(some_channel_with_custom)]) \
    .include(MembershipIncludes(custom=True, channel=True, channel_custom=True)) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.manage_memberships() \
    .uuid("some_uuid") \
    .set([PNChannelMembership.channel(some_channel)]) \
    .remove([PNChannelMembership.channel(some_channel_with_custom)]) \
    .include(MembershipIncludes(custom=True, channel=True, channel_custom=True)) \
    .pn_async(callback)
```

##### Named Arguments

Synchronous:

```python
pubnub.manage_memberships(uuid="some_uuid",
                          set=[PNChannelMembership.channel(some_channel)],
                          remove=[PNChannelMembership.channel(some_channel_with_custom)],
                          include=MembershipIncludes(custom=True, channel=True, channel_custom=True)) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.manage_memberships(uuid="some_uuid",
                          set=[PNChannelMembership.channel(some_channel)],
                          remove=[PNChannelMembership.channel(some_channel_with_custom)],
                          include=MembershipIncludes(custom=True, channel=True, channel_custom=True))
    .pn_async(callback)
```

##### Returns

The `manage_memberships()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNManageMembershipsResult](#pnmanagemembershipsresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

##### PNManageMembershipsResult

| Property Name | Type | Description |
| --- | --- | --- |
| `data` |  | List of dictionaries containing memberships metadata |
| `status` | `PNStatus` | Status of the operation |
| `total_count` | `int` | Total count of results (if `include_total_count` was set) |
| `prev` | `PNPage.Previous` | PNPage instance to be used if further requests |
| `next` | `PNPage.Next` | PNPage instance to be used if further requests |

Where each element in `data` contains a dictionary with membership metadata.

| Key | Description |
| --- | --- |
| `channel` | Dictionary containing channel metadata (id, name, description, custom) |
| `custom` | Custom object associated with membership in form of dictionary containing string to string pairs |

## Channel members

Manage the users in a channel: list, set, remove, and manage in bulk.

### Get channel members

List users in a channel. Include user metadata if needed.

#### Method(s)

To `Get Channel Members` you can use the following method(s) in the Python SDK:

```python
pubnub.get_channel_members() \
    .channel(String) \
    .limit(Integer) \
    .page(PNPage) \
    .filter(String) \
    .sort(* PNSortKey) \
    .include(MemberIncludes)
```

| Parameter | Description |
| --- | --- |
| `channel`Type: StringDefault: n/a | Channel name |
| `limit`Type: IntegerDefault: 100 | The maximum number of objects to retrieve at a time |
| `page`Type: `PNPage`Default: N/A | The paging object used for pagination |
| `filter`Type: StringDefault: N/A | Expression used to filter the results. Only objects whose properties satisfy the given expression are returned. The filter language is defined [here](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `PNSortKey`Default: N/A | List of properties to sort by. Available options are `id`, `name`, and `updated`. Use `asc` or `desc` to specify sort direction. For example: `{name: 'asc'}` |
| `include`Type: `MemberIncludes`Default: n/a | The additional information to include in the member response. |
| `> total_count`Type: BooleanDefault: `False` | Request `totalCount` to be included in paginated response, which is omitted by default |
| `> custom`Type: BooleanDefault: `False` | Indicates whether custom data should be included in the response. |
| `> status`Type: BooleanDefault: `False` | Indicates whether the status should be included in the response. |
| `> type`Type: BooleanDefault: `False` | Indicates whether the type should be included in the response. |
| `> total_count`Type: BooleanDefault: `False` | Indicates whether the total count should be included in the response. |
| `> user`Type: BooleanDefault: `False` | Indicates whether the user ID information should be included in the response. |
| `> user_custom`Type: BooleanDefault: `False` | Indicates whether custom data for the user should be included in the response. |
| `> user_type`Type: BooleanDefault: `False` | Indicates whether the type of the user should be included in the response. |
| `> user_status`Type: BooleanDefault: `False` | Indicates whether the status of the user should be included in the response. |

#### Sample code

##### Builder Pattern

Synchronous:

```python
pubnub.get_channel_members() \
    .channel("channel") \
    .include(MemberIncludes(custom=True, channel=True, user_custom=True)) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.get_channel_members() \
    .channel("channel") \
    .include(MemberIncludes(custom=True, channel=True, user_custom=True)) \
    .pn_async(callback)
```

##### Named Arguments

Synchronous:

```python
pubnub.get_channel_members(channel="channel",
                           include=MemberIncludes(custom=True, channel=True, user_custom=True)) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.get_channel_members(channel="channel",
                           include=MemberIncludes(custom=True, channel=True, user_custom=True)) \
    .pn_async(callback)
```

#### Returns

The `get_channel_members()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNManageMembershipsResult](#pngetchannelmembersresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

##### PNGetChannelMembersResult

| Property Name | Type | Description |
| --- | --- | --- |
| `data` | [] | List of dictionaries containing channel members metadata |
| `status` | PNStatus | Status of the operation |
| `total_count` | `int` | Total count of results (if `include_total_count` was set) |
| `prev` | `PNPage.Previous` | PNPage instance to be used if further requests |
| `next` | `PNPage.Next` | PNPage instance to be used if further requests |

Where each element in `data` contains a dictionary with membership metadata.

| Key | Description |
| --- | --- |
| `uuid` | Dictionary containing UUID metadata (id, name, email, externalId, profileUrl, custom) |
| `custom` | Custom object associated with channel member in form of dictionary containing string to string pairs |

### Set channel members

Set users in a channel. Provide UUIDs (optionally with custom data).

#### Method(s)

To `Set Channel Members` you can use the following method(s) in the Python SDK:

```python
pubnub.set_channel_members() \
    .channel(String) \
    .uuids([PNUUID object]) \
    .limit(Integer) \
    .page(PNPage) \
    .filter(String) \
    .sort(* PNSortKey) \
    .include(MemberIncludes)
```

| Parameter | Description |
| --- | --- |
| `channel`Type: StringDefault: n/a | Channel name |
| `uuids`Type: `[PNUUID]`Default: n/a | List of members [PNUUID](#pnuuid-class) to add to channel |
| `limit`Type: IntegerDefault: 100 | The maximum number of objects to retrieve at a time |
| `page`Type: `PNPage`Default: `null` | The paging object used for pagination |
| `filter`Type: StringDefault: `null` | Expression used to filter the results. Only objects whose properties satisfy the given expression are returned. The filter language is defined [here](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `PNSortKey`Default: N/A | List of properties to sort by. Available options are `id`, `name`, and `updated`. Use `asc` or `desc` to specify sort direction. For example: `{name: 'asc'}` |
| `include`Type: `MemberIncludes`Default: n/a | The additional information to include in the member response. |
| `> total_count`Type: BooleanDefault: `False` | Request `totalCount` to be included in paginated response, which is omitted by default |
| `> custom`Type: BooleanDefault: `False` | Indicates whether custom data should be included in the response. |
| `> status`Type: BooleanDefault: `False` | Indicates whether the status should be included in the response. |
| `> type`Type: BooleanDefault: `False` | Indicates whether the type should be included in the response. |
| `> total_count`Type: BooleanDefault: `False` | Indicates whether the total count should be included in the response. |
| `> user`Type: BooleanDefault: `False` | Indicates whether the user ID information should be included in the response. |
| `> user_custom`Type: BooleanDefault: `False` | Indicates whether custom data for the user should be included in the response. |
| `> user_type`Type: BooleanDefault: `False` | Indicates whether the type of the user should be included in the response. |
| `> user_status`Type: BooleanDefault: `False` | Indicates whether the status of the user should be included in the response. |

:::tip API limits
To learn about the maximum length of parameters used to set channel members metadata, refer to [REST API docs](https://www.pubnub.com/docs/sdks/rest-api/set-channel-members-metadata).
:::

#### Sample code

##### Builder Pattern

Synchronous:

```python
pubnub.set_uuid_metadata() \
    .uuid("some_uuid") \
    .set_name("some name") \
    .sync()

custom_1 = {
    "key3": "val1",
    "key4": "val2"
}

pubnub.set_uuid_metadata() \
    .uuid("some_uuid_with_custom") \
    .set_name("some name with custom") \
    .custom(custom_1) \
    .sync()

uuids_to_set = [
    PNUUID.uuid("some_uuid"),
    PNUUID.uuid_with_custom("some_uuid_with_custom", custom_2)
]

pubnub.set_channel_members() \
    .channel("channel id") \
    .uuids(uuids_to_set) \
    .include(MemberIncludes(custom=True, channel=True, user_custom=True)) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.set_uuid_metadata() \
    .uuid("some_uuid") \
    .set_name("some name") \
    .sync()

custom_1 = {
    "key3": "val1",
    "key4": "val2"
}

pubnub.set_uuid_metadata() \
    .uuid("some_uuid_with_custom") \
    .set_name("some name with custom") \
    .custom(custom_1) \
    .sync()

uuids_to_set = [
    PNUUID.uuid("some_uuid"),
    PNUUID.uuid_with_custom("some_uuid_with_custom", custom_2)
]

pubnub.set_channel_members() \
    .channel("channel id") \
    .uuids(uuids_to_set) \
    .include(MemberIncludes(custom=True, channel=True, user_custom=True)) \
    .pn_async(callback)
```

##### Named Arguments

Synchronous:

```python
pubnub.set_uuid_metadata(uuid=some_uuid, name="some name").sync()

custom_1 = {
    "key3": "val1",
    "key4": "val2"
}

pubnub.set_uuid_metadata(uuid=some_uuid_with_custom,
                         name="some name with custom",
                         custom=custom_1) \
    .sync()

uuids_to_set = [
    PNUUID.uuid(some_uuid),
    PNUUID.uuid_with_custom(some_uuid_with_custom, custom_2)
]

pubnub.set_channel_members(channel="channel id",
                           uuids=uuids_to_set,
                           include=MemberIncludes(custom=True, channel=True, user_custom=True)) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.set_uuid_metadata(uuid=some_uuid, name="some name").sync().sync()

custom_1 = {
    "key3": "val1",
    "key4": "val2"
}

pubnub.set_uuid_metadata(uuid=some_uuid_with_custom,
                         name="some name with custom",
                         custom=custom_1) \
    .sync()

uuids_to_set = [
    PNUUID.uuid(some_uuid),
    PNUUID.uuid_with_custom(some_uuid_with_custom, custom_2)
]

pubnub.set_channel_members(channel="channel id",
                           uuids=uuids_to_set,
                           include=MemberIncludes(custom=True, channel=True, user_custom=True)) \
    .pn_async(callback)
```

#### Returns

The `set_channel_members()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNSetChannelMembersResult](#pnsetchannelmembersresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

##### PNSetChannelMembersResult

| Property Name | Type | Description |
| --- | --- | --- |
| `data` | [] | List of dictionaries containing channel members metadata |
| `status` | `PNStatus` | Status of the operation |
| `total_count` | `int` | Total count of results (if `include_total_count` was set) |
| `prev` | `PNPage.Previous` | PNPage instance to be used if further requests |
| `next` | `PNPage.Next` | PNPage instance to be used if further requests |

Where each element in `data` contains a dictionary with membership metadata.

| Key | Description |
| --- | --- |
| `uuid` | Dictionary containing UUID metadata (id, name, email, externalId, profileUrl, custom) |
| `custom` | Custom object associated with channel member in form of dictionary containing string to string pairs |

### Remove channel members

Remove users from a channel.

#### Method(s)

To `Remove Channel Members` you can use the following method(s) in the Python SDK:

```python
pubnub.remove_channel_members() \
    .channel(String) \
    .uuids([PNUUID]) \
    .limit(Integer) \
    .page(PNPage) \
    .filter(String) \
    .sort(* PNSortKey) \
    .include_total_count(Boolean) \
    .include_custom(Boolean) \
    .includeUUID(Integer)
```

| Parameter | Description |
| --- | --- |
| `channel`Type: StringDefault: n/a | Channel name |
| `uuids`Type: `[PNUUID]`Default: n/a | List of members (as [PNUUID](#pnuuid-class)) to remove from channel |
| `limit`Type: IntegerDefault: 100 | The maximum number of objects to retrieve at a time |
| `page`Type: `PNPage`Default: N/A | The paging object used for pagination |
| `filter`Type: StringDefault: N/A | Expression used to filter the results. Only objects whose properties satisfy the given expression are returned. The filter language is defined [here](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `PNSortKey`Default: N/A | List of properties to sort by. Available options are `id`, `name`, and `updated`. Use `asc` or `desc` to specify sort direction. For example: `{name: 'asc'}` |
| `include_total_count`Type: BooleanDefault: `False` | Request `include_total_count` to be included in paginated response, which is omitted by default |
| `include_custom`Type: BooleanDefault: `False` | Whether to include the Custom object in the response. |
| `include_uuid`Type: IntegerDefault: N/A | The level of uuid metadata details to return in the channel member. Possible values are defined as constants in `UUIDIncludeEndpoint`: `UUIDIncludeEndpoint.UUID` and `UUIDIncludeEndpoint.UUID_WITH_CUSTOM` |

#### Sample code

##### Builder Pattern

Synchronous:

```python
pubnub.remove_channel_members() \
    .channel("channel id") \
    .uuids([PNUUID.uuid(some_uuid)]) \
    .include_custom(True) \
    .include_uuid(UUIDIncludeEndpoint.UUID_WITH_CUSTOM) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.remove_channel_members() \
    .channel("channel id") \
    .uuids([PNUUID.uuid(some_uuid)]) \
    .include_custom(True) \
    .include_uuid(UUIDIncludeEndpoint.UUID_WITH_CUSTOM).pn_async(callback)
```

##### Named Arguments

Synchronous:

```python
pubnub.remove_channel_members(channel="channel id",
                              uuids=[PNUUID.uuid(some_uuid)],
                              include_custom=True,
                              include_uuid=UUIDIncludeEndpoint.UUID_WITH_CUSTOM) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.remove_channel_members(channel="channel id",
                              uuids=[PNUUID.uuid(some_uuid)],
                              include_custom=True,
                              include_uuid=UUIDIncludeEndpoint.UUID_WITH_CUSTOM) \
    .pn_async(callback)
```

#### Returns

The `remove_channel_members()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNRemoveChannelMembersResult](#pnremovechannelmembersresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

##### PNRemoveChannelMembersResult

| Property Name | Type | Description |
| --- | --- | --- |
| `data` | [] | List of dictionaries containing channel members metadata |
| `status` | `PNStatus` | Status of the operation |
| `total_count` | `int` | Total count of results (if `include_total_count` was set) |
| `prev` | `PNPage.Previous` | PNPage instance to be used if further requests |
| `next` | `PNPage.Next` | PNPage instance to be used if further requests |

Where each element in `data` contains a dictionary with membership metadata.

| Key | Description |
| --- | --- |
| `uuid` | Dictionary containing UUID metadata (id, name, email, externalId, profileUrl, custom) |
| `custom` | Custom object associated with channel member in form of dictionary containing string to string pairs |

### Manage channel members

Add and remove users in a channel in one request.

#### Method(s)

To `Manage Channel Members` you can use the following method(s) in the Python SDK:

```python
pubnub.manage_channel_members() \
    .channel(String) \
    .set([PNUUID]) \
    .remove([PNUUID]) \
    .limit(Integer) \
    .page(PNPage) \
    .filter(String) \
    .sort(* PNSortKey) \
    .include(MemberIncludes)
```

| Parameter | Description |
| --- | --- |
| `channel`Type: StringDefault: n/a | Channel name |
| `set`Type: `[PNUUID]`Default: n/a | List of members [PNUUID](#pnuuid-class) to add to channel |
| `remove`Type: `[PNUUID]`Default: n/a | List of members [PNUUID](#pnuuid-class) to remove from channel |
| `limit`Type: IntegerDefault: 100 | The maximum number of objects to retrieve at a time |
| `page`Type: `PNPage`Default: N/A | The paging object used for pagination |
| `filter`Type: StringDefault: N/A | Expression used to filter the results. Only objects whose properties satisfy the given expression are returned. The filter language is defined [here](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `PNSortKey`Default: N/A | List of properties to sort by. Available options are `id`, `name`, and `updated`. Use `asc` or `desc` to specify sort direction. For example: `{name: 'asc'}` |
| `include`Type: `MemberIncludes`Default: n/a | The additional information to include in the member response. |
| `> total_count`Type: BooleanDefault: `False` | Request `totalCount` to be included in paginated response, which is omitted by default |
| `> custom`Type: BooleanDefault: `False` | Indicates whether custom data should be included in the response. |
| `> status`Type: BooleanDefault: `False` | Indicates whether the status should be included in the response. |
| `> type`Type: BooleanDefault: `False` | Indicates whether the type should be included in the response. |
| `> total_count`Type: BooleanDefault: `False` | Indicates whether the total count should be included in the response. |
| `> user`Type: BooleanDefault: `False` | Indicates whether the user ID information should be included in the response. |
| `> user_custom`Type: BooleanDefault: `False` | Indicates whether custom data for the user should be included in the response. |
| `> user_type`Type: BooleanDefault: `False` | Indicates whether the type of the user should be included in the response. |
| `> user_status`Type: BooleanDefault: `False` | Indicates whether the status of the user should be included in the response. |

#### Sample code

##### Builder Pattern

Synchronous:

```python
pubnub.manage_channel_members() \
    .channel("channel id") \
    .set([PNUUID.uuid(some_uuid)]) \
    .remove([PNUUID.uuid(some_uuid_with_custom)]) \
    .include(MemberIncludes(custom=True, channel=True, user_custom=True)) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.manage_channel_members() \
    .channel("channel id") \
    .set([PNUUID.uuid(some_uuid)]) \
    .remove([PNUUID.uuid(some_uuid_with_custom)]) \
    .include(MemberIncludes(custom=True, channel=True, user_custom=True)) \
    .pn_async(callback)
```

##### Named Arguments

Synchronous:

```python
pubnub.manage_channel_members(channel="channel id",
                              set=[PNUUID.uuid(some_uuid)],
                              remove=[PNUUID.uuid(some_uuid_with_custom)],
                              include=MemberIncludes(custom=True, channel=True, user_custom=True)) \
    .sync()
```

Asynchronous:

```python
def callback(response, status):
    pass

pubnub.manage_channel_members(channel="channel id",
                              set=[PNUUID.uuid(some_uuid)],
                              remove=[PNUUID.uuid(some_uuid_with_custom)],
                              include=MemberIncludes(custom=True, channel=True, user_custom=True))
    .pn_async(callback)
```

#### Returns

The `manage_channel_members()` operation returns an `Envelope` which contains the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNManageChannelMembersResult](#pnmanagechannelmembersresult) | A detailed object containing the result of the operation. |
| status | `PNStatus` | A status object with additional information. |

##### PNManageChannelMembersResult

| Property Name | Type | Description |
| --- | --- | --- |
| `data` | [] | List of dictionaries containing channel members metadata |
| `status` | `PNStatus` | Status of the operation |
| `total_count` | `int` | Total count of results (if `include_total_count` was set) |
| `prev` | `PNPage.Previous` | PNPage instance to be used if further requests |
| `next` | `PNPage.Next` | PNPage instance to be used if further requests |

Where each element in `data` contains a dictionary with membership metadata.

| Key | Description |
| --- | --- |
| `uuid` | Dictionary containing UUID metadata (id, name, email, externalId, profileUrl, custom) |
| `custom` | Custom object associated with channel member in form of dictionary containing string to string pairs |

## PNChannelMembership class

`PNChannelMembership` is a utility class that exposes two factory methods: `channel(channel)` constructs a channel membership, and `channel_with_custom(channelId, custom)` constructs a channel membership with additional custom metadata.

```python
class PNChannelMembership:
    __metaclass__ = ABCMeta

    def __init__(self, channel):
        self._channel = channel

    @staticmethod
    def channel(channel):
        return JustChannel(channel)

    @staticmethod
    def channel_with_custom(channel, custom):
        return ChannelWithCustom(channel, custom)

class JustChannel(PNChannelMembership):
    def __init__(self, channel):
        PNChannelMembership.__init__(self, channel)

class ChannelWithCustom(PNChannelMembership):
    def __init__(self, channel, custom):
        PNChannelMembership.__init__(self, channel)
        self._custom = custom
```

## PNUUID class

`PNUUID` is a utility class that exposes two factory methods: `uuid(uuid)` constructs a UUID, and `uuid_with_custom(channel_id, custom)` constructs a UUID with additional custom metadata.

```python
class PNUUID:
    __metaclass__ = ABCMeta

    def __init__(self, uuid):
        self._uuid = uuid

    @staticmethod
    def uuid(uuid):
        return JustUUID(uuid)

    @staticmethod
    def uuid_with_custom(uuid, custom):
        return UUIDWithCustom(uuid, custom)

class JustUUID(PNUUID):
    def __init__(self, uuid, custom):
        PNUUID.__init__(self, uuid)

class UUIDWithCustom(PNUUID):
    def __init__(self, uuid, custom):
        PNUUID.__init__(self, uuid)
        self._custom = custom
```

## 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.
* **User** - An individual or entity that interacts with a system, application, or service. In PubNub, a user typically refers to someone who sends or receives messages through the platform, identified by a unique user ID or username.
* **User ID** - UTF-8 encoded, unique string of up to 92 characters used to identify a single client (end user, device, or server) that connects to PubNub.