---
source_url: https://www.pubnub.com/docs/sdks/kotlin/api-reference/objects
title: App Context API for Kotlin SDK
updated_at: 2026-05-25T11:28:17.882Z
sdk_name: PubNub Kotlin SDK
sdk_version: 13.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


# App Context API for Kotlin SDK

PubNub Kotlin SDK, use the latest version: 13.3.0

Install:

```bash
Add PubNub dependency to your build@13.3.0
```

:::warning Breaking changes in v9.0.0
PubNub Kotlin SDK version 9.0.0 unifies the codebases for Kotlin and [Java](https://www.pubnub.com/docs/sdks/java) SDKs, introduces a new way of instantiating the PubNub client, and changes asynchronous API callbacks and emitted [status events](https://www.pubnub.com/docs/sdks/kotlin/status-events). These changes can impact applications built with previous versions (< `9.0.0` ) of the Kotlin SDK.
For more details about what has changed, refer to [Java/Kotlin SDK migration guide](https://www.pubnub.com/docs/sdks/kotlin/migration-guides/kotlin-v9-migration-guide).
:::

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 running your own databases.

PubNub also triggers events when object data changes: set, update, or removal. Setting the same data again doesn't trigger an event. Clients can receive these events in real time and update their front-end application accordingly.

:::tip Request execution
Most PubNub Kotlin SDK method invocations return an Endpoint object, which allows you to decide whether to perform the operation synchronously or asynchronously.
You must invoke the `.sync()` or `.async()` method on the Endpoint to execute the request, or the operation **will not** be performed.
```kotlin
val channel = pubnub.channel("channelName")
channel.publish("This SDK rules!").async { result ->
    result.onFailure { exception ->
        // Handle error
    }.onSuccess { value ->
        // Handle successful method result
    }
}
```
:::

## User

### Get metadata for all users

Returns a paginated list of UUID Metadata objects, optionally including the custom data object for each.

:::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 Kotlin SDK:

```kotlin
pubnub.getAllUUIDMetadata(
    filter: String? = null,
    sort: Collection<PNSortKey<PNKey>> = listOf(),
    page: PNPage? = null,
    limit: Int? = null,
    includeCustom: Boolean = false,
    includeCount: Boolean = false
).async { result -> }
```

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| filter | String? | Optional | `null` | Filter expression. Only matching objects are returned. See [filtering](https://www.pubnub.com/docs/general/metadata/filtering). |
| sort | Collection<PNSortKey<PNKey>> | Optional | `listOf()` | Sort by `ID`, `NAME`, `UPDATED`, `TYPE`, `STATUS` with asc/desc for sort direction (for example, `PNSortKey.asc(PNKey.STATUS)`). |
| page | PNPage? | Optional | `null` | Cursor-based pagination. |
| limit | Int | Optional | `100` | Number of objects to return. Default/Max: 100. |
| includeCustom | Boolean | Optional | `false` | Whether to include the Custom object in the response. |
| includeCount | Boolean | Optional | `false` | Whether to include the total count in the paginated response. Default is false. |

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

```kotlin
import com.pubnub.api.PubNub
import com.pubnub.api.UserId
import com.pubnub.api.v2.PNConfiguration

/**
 * This example demonstrates how to use the getAllUUIDMetadata method in the PubNub Kotlin SDK.
 *
 * The App Context (Objects) API allows you to store metadata about users (UUIDs) in PubNub's
 * database without setting up your own backend.
 */
fun main() {
    println("PubNub UUID Metadata Example")
    println("============================")

    // 1. Configure PubNub
    val userId = UserId("uuid-metadata-demo-user")
    val config = PNConfiguration.builder(userId, "demo").apply {
        publishKey = "demo"
    }.build()

    // 2. Create PubNub instance
    val pubnub = PubNub.create(config)

    // 3. First, set up some sample user metadata
    setupSampleUsers(pubnub)

    // 4. Demonstrate getting all UUID metadata
    getAllUUIDMetadataBasic(pubnub)

    // 5. Demonstrate getting all UUID metadata with filtering
    getAllUUIDMetadataWithFilter(pubnub)

    // 6. Get metadata for a specific UUID
    getSpecificUUIDMetadata(pubnub)

    // 7. Clean up sample user metadata
    cleanupUserMetadata(pubnub)

    // Clean up
    pubnub.destroy()
}

/**
 * Set up sample user metadata for the demo
 */
private fun setupSampleUsers(pubnub: PubNub) {
    println("\n# Setting up sample user metadata")

    // Create a few users with metadata
    val users = listOf(
        Triple("user-1", "Alice", "Developer"),
        Triple("user-2", "Bob", "Manager"),
        Triple("user-3", "Charlie", "Support")
    )

    users.forEach { (userId, name, role) ->
        println("\nSetting up metadata for $name ($userId)")

        pubnub.setUUIDMetadata(
            uuid = userId,
            name = name,
            includeCustom = true,
            custom = mapOf("role" to role, "active" to true),
            email = "$name@example.com".lowercase()
        ).async { result ->
            result.onSuccess { response ->
                println("SUCCESS: Created/updated user metadata for ${response.data?.id}")
                println("Name: ${response.data?.name}")
                println("Email: ${response.data?.email}")
                println("Custom: ${response.data?.custom}")
            }.onFailure { exception ->
                println("ERROR: Failed to set user metadata")
                println("Error details: ${exception.message}")
            }
        }
    }

    // Wait for a moment to ensure all operations are complete
    println("\nWaiting for metadata operations to complete...")
    Thread.sleep(2000)
}

/**
 * Demonstrates a basic call to getAllUUIDMetadata
 */
private fun getAllUUIDMetadataBasic(pubnub: PubNub) {
    println("\n# Getting All UUID Metadata (Basic)")

    pubnub.getAllUUIDMetadata(
        includeCustom = true, // Include custom fields
        includeCount = true // Include total count in response
    ).async { result ->
        result.onSuccess { response ->
            println("SUCCESS: Retrieved UUID metadata objects")

            if (response.data != null) {
                response.data.forEachIndexed { index, metadata ->
                    println("\nUser ${index + 1}:")
                    println("UUID: ${metadata.id}")
                    println("Name: ${metadata.name}")
                    println("Email: ${metadata.email}")
                    println("Custom: ${metadata.custom}")
                }
            }

            // Check if there are more results available (pagination)
            if (response.next != null) {
                println("\nMore results available. Use the 'next' page token to retrieve them.")
            }
        }.onFailure { exception ->
            println("ERROR: Failed to get all UUID metadata")
            println("Error details: ${exception.message}")
        }
    }

    // Wait for the operation to complete
    Thread.sleep(2000)
}

/**
 * Demonstrates an advanced call to getAllUUIDMetadata with filtering
 */
private fun getAllUUIDMetadataWithFilter(pubnub: PubNub) {
    println("\n# Getting All UUID Metadata (with Filter)")

    // Create a filter to find users with a specific role
    val filter = "custom.role == 'Developer'"

    pubnub.getAllUUIDMetadata(
        filter = filter, // Filter expression
        limit = 10, // Maximum number of results
        includeCustom = true, // Include custom fields
        includeCount = true // Include total count in response
    ).async { result ->
        result.onSuccess { response ->
            println("SUCCESS: Retrieved filtered UUID metadata objects")
            println("Filter: \"$filter\"")

            if (response.data != null) {
                response.data.forEachIndexed { index, metadata ->
                    println("\nUser ${index + 1}:")
                    println("UUID: ${metadata.id}")
                    println("Name: ${metadata.name}")
                    println("Email: ${metadata.email}")
                    println("Custom: ${metadata.custom}")
                }
            }
        }.onFailure { exception ->
            println("ERROR: Failed to get filtered UUID metadata")
            println("Error details: ${exception.message}")
        }
    }

    // Wait for the operation to complete
    Thread.sleep(2000)
}

/**
 * Get metadata for a specific UUID
 */
private fun getSpecificUUIDMetadata(pubnub: PubNub) {
    println("\n# Getting Metadata for a Specific UUID")

    val userId = "user-2" // Get metadata for Bob

    pubnub.getUUIDMetadata(
        uuid = userId,
        includeCustom = true
    ).async { result ->
        result.onSuccess { response ->
            println("SUCCESS: Retrieved metadata for UUID: $userId")
            if (response.data != null) {
                println("UUID: ${response.data.id}")
                println("Name: ${response.data.name}")
                println("Email: ${response.data.email}")
                println("External ID: ${response.data.externalId}")
                println("Profile URL: ${response.data.profileUrl}")
                println("Updated: ${response.data.updated}")
                println("Custom: ${response.data.custom}")
            } else {
                println("No metadata found for UUID: $userId")
            }
        }.onFailure { exception ->
            println("ERROR: Failed to get metadata for UUID: $userId")
            println("Error details: ${exception.message}")
        }
    }

    // Wait for the operation to complete
    Thread.sleep(2000)
}

private fun cleanupUserMetadata(pubnub: PubNub) {
    val users = listOf("user-1", "user-2", "user-3")

    users.forEach { userId ->
        println("\nCleaning up metadata for $userId")

        pubnub.removeUUIDMetadata(
            uuid = userId
        ).async { result ->
            result.onSuccess { response ->
                println("SUCCESS: Removed user metadata for $userId")
            }.onFailure { exception ->
                println("ERROR: Failed to remove user metadata for $userId")
                println("Error details: ${exception.message}")
            }
        }
        Thread.sleep(2000)
    }
}
```

#### Response

```kotlin
data class PNUUIDMetadataArrayResult(
    val status: Int,
    val data: Collection<PNUUIDMetadata>,
    val totalCount: Int?,
    val next: PNPage?,
    val prev: PNPage?
)

data class PNUUIDMetadata(
    val id: String,
    val name: PatchValue<String?>? = null,
    val externalId: PatchValue<String?>? = null,
    val profileUrl: PatchValue<String?>? = null,
    val email: PatchValue<String?>? = null,
    val custom: PatchValue<Map<String, Any?>?>? = null,
    val updated: PatchValue<String>? = null,
    val eTag: PatchValue<String>? = null,
    val type: PatchValue<String?>? = null,
    val status: PatchValue<String?>? = null,
)
```

### Get user metadata

Returns metadata for the specified UUID, optionally including the custom data object for each.

#### Method(s)

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

```kotlin
pubnub.getUUIDMetadata(
    uuid: String? = null,
    includeCustom: Boolean = false
).async { result -> }
```

| Parameter | Description |
| --- | --- |
| `uuid`Type: `String`Default: `pubnub.configuration.uuid` | Unique UUID Metadata identifier. If not supplied, then UUID from configuration will be used. |
| `includeCustom`Type: `Boolean`Default: `false` | Whether to include the Custom object in the response. |

#### Sample code

```kotlin
pubnub.getUUIDMetadata()
    .async { result ->
        result.onFailure { exception ->
            // Handle error
        }.onSuccess { value ->
            // Handle successful method result
        }
    }
```

#### Response

```kotlin
data class PNUUIDMetadataResult(
    val status: Int,
    val data: PNUUIDMetadata?
)

data class PNUUIDMetadata(
    val id: String,
    val name: PatchValue<String?>? = null,
    val externalId: PatchValue<String?>? = null,
    val profileUrl: PatchValue<String?>? = null,
    val email: PatchValue<String?>? = null,
    val custom: PatchValue<Map<String, Any?>?>? = null,
    val updated: PatchValue<String>? = null,
    val eTag: PatchValue<String>? = null,
    val type: PatchValue<String?>? = null,
    val status: PatchValue<String?>? = null,
)
```

### Set user metadata

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

Set metadata for a UUID in the database, optionally including the custom data object for each.

#### Method(s)

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

```kotlin
pubnub.setUUIDMetadata(
    uuid: String? = null,
    includeCustom: Boolean = false,
    name: String? = null,
    externalId: String? = null,
    profileUrl: String? = null,
    email: String? = null,
    custom: Any? = null,
    type: String?,
    status: String?,
    ifMatchesEtag: String?
).async { result -> }
```

| Parameter | Description |
| --- | --- |
| `uuid`Type: `String`Default: `pubnub.configuration.uuid` | Unique UUID Metadata identifier. If not supplied, then UUID from configuration will be used. |
| `includeCustom`Type: `Boolean`Default: `false` | Whether to include the custom field in the fetch response. |
| `name`Type: `String?`Default: `null` | Display name for the user. |
| `externalId`Type: `String?`Default: `null` | User's identifier in an external system |
| `profileUrl`Type: `String?`Default: `null` | The URL of the user's profile picture |
| `email`Type: `String?`Default: `null` | The user's email address. |
| `type`Type: `String?`Default: `null` | The custom type of the user. |
| `status`Type: `String?`Default: `null` | The custom type of the user. |
| `custom`Type: `Any?`Default: `null` | 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. |
| `ifMatchesEtag`Type: StringDefault: n/a | Use the eTag from an applicable get metadata call to ensure updates only apply if the object hasn’t changed. If the eTags differ, the server returns HTTP 412. |

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

```kotlin
pubnub.setUUIDMetadata()
    .async { result ->
        result.onFailure { exception ->
            // Handle error
        }.onSuccess { value ->
            // Handle successful method result
        }
    }
```

#### Response

```kotlin
data class PNUUIDMetadataResult(
    val status: Int,
    val data: PNUUIDMetadata?
)

data class PNUUIDMetadata(
    val id: String,
    val name: PatchValue<String?>? = null,
    val externalId: PatchValue<String?>? = null,
    val profileUrl: PatchValue<String?>? = null,
    val email: PatchValue<String?>? = null,
    val custom: PatchValue<Map<String, Any?>?>? = null,
    val updated: PatchValue<String>? = null,
    val eTag: PatchValue<String>? = null,
    val type: PatchValue<String?>? = null,
    val status: PatchValue<String?>? = null,
)
```

### Remove user metadata

Removes the metadata from a specified UUID.

#### Method(s)

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

```kotlin
pubnub.removeUUIDMetadata(
    uuid: String? = null
).async { result -> }
```

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

#### Sample code

```kotlin
pubnub.removeUUIDMetadata()
    .async { result ->
        result.onFailure { exception ->
            // Handle error
        }.onSuccess { value ->
            // Handle successful method result
        }
    }
```

#### Response

```kotlin
data class PNRemoveMetadataResult(private val status: Int)
```

## Channel

### Get metadata for all channels

Returns a paginated list of Channel Metadata objects, optionally including the custom data object for each.

:::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 Kotlin SDK:

```kotlin
pubnub.getAllChannelMetadata(
    filter: String? = null,
    sort: Collection<PNSortKey<PNKey>> = listOf(),
    page: PNPage? = null,
    limit: Int? = null,
    includeCustom: Boolean = false,
    includeCount: Boolean = false,
).async { result -> }
```

| Parameter | Description |
| --- | --- |
| `filter`Type: `String?`Default: `null` | Filter expression. Only matching objects are returned. See [filtering](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `Collection<PNSortKey<PNKey>>`Default: `listOf()` | List of properties to sort by. Available options are `PNKey.ID`, `PNKey.NAME`, `PNKey.UPDATED`, `PNKey.TYPE`, `PNKey.STATUS`. Use `PNSortKey.asc` or `PNSortKey.desc` to specify sort direction. For example: `PNSortKey.asc(PNKey.STATUS)` , `PNSortKey.desc(PNKey.TYPE)` |
| `page`Type: `PNPage?`Default: `null` | The paging object used for pagination. |
| `limit`Type: `Int`Default: 100 | The number of objects to retrieve at a time. |
| `includeCustom`Type: `Boolean`Default: `false` | Whether to include the `Custom` field in the fetch response. |
| `includeCount`Type: `Boolean`Default: `false` | Request `IncludeCount` to be included in paginated response. By default, `IncludeCount` is omitted. |

#### Sample code

```kotlin
pubnub.getAllChannelMetadata()
    .async { result ->
        result.onFailure { exception ->
            // Handle error
        }.onSuccess { value ->
            // Handle successful method result
        }
    }
```

#### Response

```kotlin
data class PNChannelMetadataArrayResult(
    val status: Int,
    val data: Collection<PNChannelMetadata>,
    val totalCount: Int?,
    val next: PNPage?,
    val prev: PNPage?
)

data class PNChannelMetadata(
    val id: String,
    val name: PatchValue<String?>? = null,
    val description: PatchValue<String?>? = null,
    val custom: PatchValue<Map<String, Any?>?>? = null,
    val updated: PatchValue<String>? = null,
    val eTag: PatchValue<String>? = null,
    val type: PatchValue<String?>? = null,
    val status: PatchValue<String?>? = null,
)
```

### Get channel metadata

Returns metadata for the specified Channel, optionally including the custom data object for each.

#### Method(s)

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

```kotlin
pubnub.getChannelMetadata(
    channel: String,
    includeCustom: Boolean = false
).async { result -> }
```

| Parameter | Description |
| --- | --- |
| `channel`Type: `String`Default: n/a | Channel name. |
| `includeCustom`Type: `Boolean`Default: `false` | Whether to include the custom field in the fetch response. |

#### Sample code

```kotlin
pubnub.getChannelMetadata(channel = "myChannel")
    .async { result ->
        result.onFailure { exception ->
            // Handle error
        }.onSuccess { value ->
            // Handle successful method result
        }
    }
```

#### Response

```kotlin
data class PNChannelMetadataResult(
    val status: Int,
    val data: PNChannelMetadata?
)

data class PNChannelMetadata(
    val id: String,
    val name: PatchValue<String?>? = null,
    val description: PatchValue<String?>? = null,
    val custom: PatchValue<Map<String, Any?>?>? = null,
    val updated: PatchValue<String>? = null,
    val eTag: PatchValue<String>? = null,
    val type: PatchValue<String?>? = null,
    val status: PatchValue<String?>? = null,
)
```

### Set channel metadata

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

Set metadata for a Channel in the database, optionally including the custom data object for each.

#### Method(s)

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

```kotlin
pubnub.setChannelMetadata(
    channel: String,
    includeCustom: Boolean = false,
    name: String? = null,
    description: String? = null,
    custom: Any? = null
    type: String?,
    status: String?,
    ifMatchesEtag: String?
).async { result -> }
```

| Parameter | Description |
| --- | --- |
| `channel`Type: `String`Default: n/a | Channel name. |
| `includeCustom`Type: `Boolean`Default: `false` | Whether to include the custom field in the fetch response. |
| `name`Type: `String?`Default: `null` | Name for the channel. |
| `description`Type: `String?`Default: `null` | Description of a channel. |
| `type`Type: `String?`Default: `null` | The custom type of the channel. |
| `status`Type: `String?`Default: `null` | The custom type of the channel. |
| `custom`Type: `Any?`Default: `null` | Custom JSON values. Can be strings, numbers, or booleans. Filtering by Custom isn’t supported. |
| `ifMatchesEtag`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

```kotlin
pubnub.setChannelMetadata(channel = "myChannel")
    .async { result ->
        result.onFailure { exception ->
            // Handle error
        }.onSuccess { value ->
            // Handle successful method result
        }
    }
```

#### Response

```kotlin
data class PNChannelMetadataResult(
    val status: Int,
    val data: PNChannelMetadata?
)

data class PNChannelMetadata(
    val id: String,
    val name: PatchValue<String?>? = null,
    val description: PatchValue<String?>? = null,
    val custom: PatchValue<Map<String, Any?>?>? = null,
    val updated: PatchValue<String>? = null,
    val eTag: PatchValue<String>? = null,
    val type: PatchValue<String?>? = null,
    val status: PatchValue<String?>? = null,
)
```

#### Other examples

##### Iteratively update existing metadata

```kotlin
import com.pubnub.api.PubNub
import com.pubnub.api.UserId
import com.pubnub.api.models.consumer.objects.channel.PNChannelMetadataResult
import com.pubnub.api.v2.PNConfiguration
import kotlin.test.assertEquals

fun main() {
    // create configuration
    val pnConfiguration = PNConfiguration.builder(userId = UserId("user01"), subscribeKey = "demo") {
        publishKey = "demo"
    }.build()

    // create PubNub
    val pubNub = PubNub.create(pnConfiguration)

    val channel = "channel01"
    val channelName = "Channel1on1"
    val channelDescription = "Channel for 1on1 conversation"
    val status = "active"
    val type = "1on1"
    val initialCustom = mapOf("Days" to "Mon-Fri")

    // set channelMetadata
    val channelMetadataAfterSet: PNChannelMetadataResult = pubNub.setChannelMetadata(
        channel = channel,
        name = channelName,
        description = channelDescription,
        status = status,
        type = type,
        custom = initialCustom
    ).sync()

    // get channelMetadata
    val channelMetadataAfterGet = pubNub.getChannelMetadata(channel = channel, includeCustom = true).sync().data

    //  Update metadata with additional custom data
    val updatedCustomMetadata = (channelMetadataAfterGet.custom?.value ?: emptyMap()) + mapOf("Months" to "Jan-May")
    val updatedChannelMetadata = pubNub.setChannelMetadata(
        channel = channelMetadataAfterGet.id,
        custom = updatedCustomMetadata,
        includeCustom = true
    ).sync()

    val updatedData = updatedChannelMetadata.data
    assertEquals(channel, updatedData.id)
    assertEquals(channelName, updatedData.name?.value)
    assertEquals(channelDescription, updatedData.description?.value)
    assertEquals(status, updatedData.status?.value)
    assertEquals(type, updatedData.type?.value)
    val expectedCustom = mapOf("Days" to "Mon-Fri", "Months" to "Jan-May")
    assertEquals(expectedCustom, updatedData.custom?.value)

    // cleanup
    pubNub.removeChannelMetadata(channel = channel).sync()
    kotlin.system.exitProcess(0)
}
```

### Remove channel metadata

Removes the metadata from a specified channel.

#### Method(s)

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

```kotlin
pubnub.removeChannelMetadata(
    channel: String
).async { result -> }
```

| Parameter | Description |
| --- | --- |
| `channel`Type: `String`Default: n/a | Channel name. |

#### Sample code

```kotlin
pubnub.removeChannelMetadata(channel = "myChannel")
    .async { result ->
        result.onFailure { exception ->
            // Handle error
        }.onSuccess { value ->
            // Handle successful method result
        }
    }
```

#### Response

```kotlin
data class PNRemoveMetadataResult(private val status: Int)
```

## Channel memberships

### Get channel memberships

The method returns a list of channel memberships for a user. This method doesn't return a user's subscriptions.

#### Method(s)

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

```kotlin
pubnub.getMemberships(
    userId: String? = null,
    limit: Int? = null,
    page: PNPage? = null,
    filter: String? = null,
    sort: Collection<PNSortKey<PNMembershipKey>> = listOf(),
    include: MembershipInclude = MembershipInclude(),
).async { result -> }
```

| Parameter | Description |
| --- | --- |
| `userId`Type: `String`Default: `pubnub.configuration.userId.value` | Unique User Metadata identifier. If not supplied, then userId from configuration will be used. |
| `limit`Type: `Int`Default: 100 | The number of objects to retrieve at a time. |
| `page`Type: `PNPage?`Default: `null` | The paging object used for pagination. |
| `filter`Type: `String?`Default: `null` | Filter expression. Only matching objects are returned. See [filtering](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `Collection<PNSortKey<PNMembershipKey>>`Default: `listOf()` | Sort by `CHANNEL_ID`, `CHANNEL_NAME`, `CHANNEL_UPDATED`, `CHANNEL_STATUS`, `CHANNEL_TYPE`, `UPDATED`, `STATUS`, `TYPE` with asc/desc for sort direction (for example, `PNSortKey.PNAsc(PNMembershipKey.TYPE)`). |
| `include`Type: `MembershipInclude`Default: `MembershipInclude()` | Object holding the configuration for whether to include additional data in the response. |

#### Sample code

```kotlin
pubnub.getMemberships(
    include = MembershipInclude(
        includeCustom = true,
        includeStatus = true,
        includeType = true,
        includeTotalCount = true,
        includeChannel = true,
        includeChannelCustom = true,
        includeChannelType = true,
        includeChannelStatus = true
    ),
    sort = listOf(PNSortKey.PNAsc(PNMembershipKey.CHANNEL_ID))
).async { result ->
    result.onFailure { exception ->
        // Handle error
    }.onSuccess { value ->
        // Handle successful method result
    }
}
```

#### Response

```kotlin
data class PNChannelMembershipArrayResult(
    val status: Int,
    val data: Collection<PNChannelMembership>,
    val totalCount: Int?,
    val next: PNPage?,
    val prev: PNPage?
)

data class PNChannelMembership(
    val channel: PNChannelMetadata,
    val custom: PatchValue<Map<String, Any?>?>? = null,
    val updated: String,
    val eTag: String,
    val status: PatchValue<String?>? = null,
    val type: PatchValue<String?>? = null
)
```

### Set channel memberships

Set channel memberships for a User.

#### Method(s)

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

```kotlin
pubnub.setMemberships(
    channels: List<ChannelMembershipInput>,
    userId: String? = null,
    limit: Int? = null,
    page: PNPage? = null,
    filter: String? = null,
    sort: Collection<PNSortKey<PNMembershipKey>>, = listOf(),
    include: MembershipInclude = MembershipInclude(),
).async { result -> }
```

| Parameter | Description |
| --- | --- |
| `channels`Type: [List<ChannelMembershipInput>](#channelmembershipinput)Default: n/a | List of [ChannelMembershipInput](#channelmembershipinput) to add to membership with optional custom metadata, like status or type. |
| `userId`Type: `String`Default: `pubnub.configuration.userId.value` | Unique User Metadata identifier. If not supplied, then userId from configuration will be used. |
| `limit`Type: `Int`Default: 100 | The number of objects to retrieve at a time. |
| `page`Type: `PNPage?`Default: `null` | The paging object used for pagination. |
| `filter`Type: `String?`Default: `null` | Filter expression. Only matching objects are returned. See [filtering](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `Collection<PNSortKey<PNMembershipKey>>`Default: `listOf()` | List of properties to sort by. Available options are `PNMembershipKey.CHANNEL_ID`, `PNMembershipKey.CHANNEL_NAME`, `PNMembershipKey.CHANNEL_UPDATED`, `PNMembershipKey.CHANNEL_STATUS`, `PNMembershipKey.CHANNEL_TYPE`, `PNMembershipKey.UPDATED`, `PNMembershipKey.STATUS` and `PNMembershipKey.TYPE`. Use `PNSortKey.PNAsc` or `PNSortKey.PNDesc` to specify sort direction. For example: `PNSortKey.PNAsc(PNMembershipKey.TYPE)` or `PNSortKey.PNDesc(PNMembershipKey.STATUS)`. |
| `include`Type: `MembershipInclude`Default: `MembershipInclude()` | Object holding the configuration for whether to include additional data 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).
:::

#### ChannelMembershipInput

| Parameter | Description |
| --- | --- |
| `channel`Type: `String` | The channel to add the membership to. |
| `custom`Type: `CustomObject` | Additional information about the membership. |
| `type`Type: `String` | The string description of the type of the membership. |
| `status`Type: `String` | The string description of the status of the membership. |

#### Sample code

```kotlin
pubnub.setMemberships(
    channels = listOf(
        PNChannelMembership.Partial(
            channelId = "myChannel",
            custom = mapOf("owner" to "PubNub"),
            status = "active",
            type = "regular_membership"
        )
    ),
    include = MembershipInclude(
        includeCustom = true,
        includeStatus = true,
        includeType = true,
        includeChannel = true,
        includeChannelCustom = true,
        includeChannelType = true,
        includeChannelStatus = true,
        includeTotalCount = true
    ),
).async { result ->
    result.onFailure { exception ->
        // Handle error
    }.onSuccess { value ->
        // Handle successful method result
    }
}
```

#### Response

```kotlin
data class PNChannelMembershipArrayResult(
    val status: Int,
    val data: Collection<PNChannelMembership>,
    val totalCount: Int?,
    val next: PNPage?,
    val prev: PNPage?
)

data class PNChannelMembership(
    val channel: PNChannelMetadata,
    val custom: PatchValue<Map<String, Any?>?>? = null,
    val updated: String,
    val eTag: String,
    val status: PatchValue<String?>? = null,
    val type: PatchValue<String?>? = null,
)
```

### Remove channel memberships

Remove channel memberships for a User.

#### Method(s)

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

```kotlin
pubnub.removeMemberships(
    channels: List<String>,
    userId: String? = null,
    limit: Int? = null,
    page: PNPage? = null,
    filter: String? = null,
    sort: Collection<PNSortKey<PNMembershipKey>>, = listOf(),
    include: MembershipInclude = MembershipInclude(),
).async { result -> }
```

| Parameter | Description |
| --- | --- |
| `channels`Type: `List<String>`Default: n/a | List of channels to remove from membership. |
| `userId`Type: `String`Default: `pubnub.configuration.userId.value` | Unique User Metadata identifier. If not supplied, then userId from configuration will be used. |
| `filter`Type: `String?`Default: `null` | Filter expression. Only matching objects are returned. See [filtering](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `Collection<PNSortKey<PNMembershipKey>>,`Default: `listOf()` | Sort by `CHANNEL_ID`, `CHANNEL_NAME`, `CHANNEL_UPDATED`, `CHANNEL_STATUS`, `CHANNEL_TYPE`, `UPDATED`, `STATUS`, `TYPE` with asc/desc for sort direction (for example, `PNSortKey.PNAsc(PNMembershipKey.TYPE)`). |
| `page`Type: `PNPage?`Default: `null` | Cursor-based pagination. |
| `limit`Type: `Int`Default: 100 | Number of objects to return. Default/Max: 100. |
| `include`Type: `MembershipInclude`Default: `MembershipInclude()` | Whether to include additional fields. |

#### Sample code

```kotlin
pubnub.removeMemberships(listOf("myChannel"))
    .async { result ->
        result.onFailure { exception ->
            // Handle error
        }.onSuccess { value ->
            // Handle successful method result
        }
    }
```

#### Response

```kotlin
data class PNChannelMembershipArrayResult(
    val status: Int,
    val data: Collection<PNChannelMembership>,
    val totalCount: Int?,
    val next: PNPage?,
    val prev: PNPage?
)

data class PNChannelMembership(
    val channel: PNChannelMetadata,
    val custom: PatchValue<Map<String, Any?>?>? = null,
    val updated: String,
    val eTag: String,
    val status: PatchValue<String?>? = null,
    val type: PatchValue<String?>? = null,
)
```

### Manage channel memberships

Manage a user's channel memberships.

#### Method(s)

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

```kotlin
pubnub.manageMemberships(
    channelsToSet: List<PNChannelWithCustom>,
    channelsToRemove: List<String>,
    userId: String? = null,
    limit: Int? = null,
    page: PNPage? = null,
    filter: String? = null,
    sort: Collection<PNSortKey<PNMembershipKey>>, = listOf(),
    include: MembershipInclude = MembershipInclude(),
).async { result -> }
```

| Parameter | Description |
| --- | --- |
| `channelsToSet`Type: `List<PNChannelWithCustom>`Default: n/a | List of `PNChannelWithCustom` to add to membership. |
| `channelsToRemove`Type: `List<String>`Default: n/a | List of channels to remove from membership. |
| `userId`Type: `String`Default: `pubnub.configuration.userId.value` | Unique User Metadata identifier. If not supplied, then userId from configuration will be used. |
| `filter`Type: `String?`Default: `null` | Filter expression. Only matching objects are returned. See [filtering](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `Collection<PNSortKey<PNMembershipKey>>,`Default: `listOf()` | List of properties to sort by. Available options are `PNMembershipKey.CHANNEL_ID`, `PNMembershipKey.CHANNEL_NAME`, `PNMembershipKey.CHANNEL_UPDATED`, `PNMembershipKey.CHANNEL_STATUS`, `PNMembershipKey.CHANNEL_TYPE`, `PNMembershipKey.UPDATED`, `PNMembershipKey.STATUS` and `PNMembershipKey.TYPE`. Use `PNSortKey.PNAsc` or `PNSortKey.PNDesc` to specify sort direction. For example: `PNSortKey.PNAsc(PNMembershipKey.TYPE)` or `PNSortKey.PNDesc(PNMembershipKey.STATUS)`. |
| `page`Type: `PNPage?`Default: `null` | The paging object used for pagination. |
| `limit`Type: `Int`Default: 100 | The number of objects to retrieve at a time. |
| `include`Type: `MembershipInclude`Default: `MembershipInclude()` | Object holding the configuration for whether to include additional data in the response. |

#### Sample code

```kotlin
pubnub.manageMemberships(
    channelsToSet = listOf(PNChannelMembership.Partial(channelId = "myChannelToSet")),
    channelsToRemove = listOf("myChannelToRemove"),
    include = MembershipInclude(
        includeCustom = true,
        includeStatus = true,
        includeType = true,
        includeChannel = true,
        includeChannelCustom = true,
        includeChannelType = true,
        includeChannelStatus = true,
        includeTotalCount = true
    )
).async { result ->
    result.onFailure { exception ->
        // Handle error
    }.onSuccess { value ->
        // Handle successful method result
    }
}
```

#### Response

```kotlin
data class PNChannelMembershipArrayResult(
    val status: Int,
    val data: Collection<PNChannelMembership>,
    val totalCount: Int?,
    val next: PNPage?,
    val prev: PNPage?
)

data class PNChannelMembership(
    val channel: PNChannelMetadata,
    val custom: PatchValue<Map<String, Any?>?>? = null,
    val updated: String,
    val eTag: String,
    val status: PatchValue<String?>? = null,
    val type: PatchValue<String?>? = null,
)
```

## Channel members

### Get channel members

The method returns a list of members in a channel. The list will include user metadata for members that have additional metadata stored in the database.

#### Method(s)

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

```kotlin
pubnub.getChannelMembers(
    channel: String,
    limit: Int? = null,
    page: PNPage? = null,
    filter: String? = null,
    sort: Collection<PNSortKey<PNMemberKey>> = listOf(),
    include: MemberInclude = MemberInclude(),
).async { result -> }
```

| Parameter | Description |
| --- | --- |
| `channel`Type: `String`Default: n/a | Channel name. |
| `limit`Type: `Int`Default: 100 | The number of objects to retrieve at a time. |
| `page`Type: `PNPage?`Default: `null` | The paging object used for pagination. |
| `filter`Type: `String?`Default: `null` | Filter expression. Only matching objects are returned. See [filtering](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `Collection<PNSortKey<PNMemberKey>>`Default: `listOf()` | List of properties to sort by. Available options are `PNMemberKey.UUID_ID`, `PNMemberKey.UUID_NAME`,`PNMemberKey.UUID_UPDATED`, `PNMemberKey.UUID_NAME`,`PNMemberKey.UUID_TYPE`, `PNMemberKey.UPDATED`,`PNMemberKey.STATUS`, `PNMemberKey.TYPE`. Use `PNSortKey.PNAsc` or `PNSortKey.PNDesc` to specify sort direction. For example: `PNSortKey.PNAsc(PNMemberKey.TYPE)` or `PNSortKey.PNDesc(PNMemberKey.STATUS)`. |
| `include`Type: `MemberInclude`Default: `MemberInclude()` | Object holding the configuration for whether to include additional data in the response. |

#### Sample code

```kotlin
pubnub.getChannelMembers("myChannel")
    .async { result ->
        result.onFailure { exception ->
            // Handle error
        }.onSuccess { value ->
            // Handle successful method result
        }
    }
```

#### Response

```kotlin
data class PNMemberArrayResult(
    val status: Int,
    val data: Collection<PNMember>,
    val totalCount: Int?,
    val next: PNPage.PNNext?,
    val prev: PNPage.PNPrev?
)

data class PNMember(
    val uuid: PNUUIDMetadata?,
    val custom: Any? = null,
    val updated: Instant,
    val eTag: String
)
```

### Set channel members

This method sets members in a channel.

#### Method(s)

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

```kotlin
pubnub.setChannelMembers(
    channel: String,
    users: List<PNMember.Partial>,
    limit: Int? = null,
    page: PNPage? = null,
    filter: String? = null,
    sort: Collection<PNSortKey<PNMemberKey>> = listOf(),
    include: MemberInclude = MemberInclude(),
).async { result, status ->
    if (status.error) {
        // handle error
    } else if (result != null) {
        // handle result
    }
}
```

| Parameter | Description |
| --- | --- |
| `channel` *Type: `String`Default: n/a | Channel name. |
| `users`Type: `List<PNMember.Partial>`Default: n/a | List of members `PNMember.Partial` to add to channel. |
| `limit`Type: `Int`Default: 100 | The number of objects to retrieve at a time. |
| `page`Type: `PNPage?`Default: `null` | The paging object used for pagination. |
| `filter`Type: `String?`Default: `null` | Filter expression. Only matching objects are returned. See [filtering](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `Collection<PNSortKey<PNMemberKey>>`Default: `listOf()` | List of properties to sort by. Available options are `PNMemberKey.UUID_ID`, `PNMemberKey.UUID_NAME`,`PNMemberKey.UUID_UPDATED`, `PNMemberKey.UUID_NAME`,`PNMemberKey.UUID_TYPE`, `PNMemberKey.UPDATED`,`PNMemberKey.STATUS`, `PNMemberKey.TYPE`. Use `PNSortKey.PNAsc` or `PNSortKey.PNDesc` to specify sort direction. For example: `PNSortKey.PNAsc(PNMemberKey.TYPE)` or `PNSortKey.PNDesc(PNMemberKey.STATUS)`. |
| `include`Type: `MemberInclude`Default: `MemberInclude()` | Object holding the configuration for whether to include additional data 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

```kotlin
pubnub.setChannelMembers(
    channel = "myChannel",
    users = listOf(
        PNMember.Partial(
            uuidId = "myUserId",
            custom = mapOf("custom" to "customValue"),
            status = "status",
            type = "typeABC"
        )
    ),
    include = MemberInclude(includeUser = true, includeStatus = true, includeType = true),
    sort = listOf(PNSortKey.PNAsc(PNMemberKey.STATUS)),
).async { result ->
    result.onFailure { exception ->
        // Handle error
    }.onSuccess { value ->
        // Handle successful method result
    }
}
```

#### Response

```kotlin
data class PNMemberArrayResult(
    val status: Int,
    val data: Collection<PNMember>,
    val totalCount: Int?,
    val next: PNPage.PNNext?,
    val prev: PNPage.PNPrev?
)

data class PNMember(
    val uuid: PNUUIDMetadata,
    val custom: PatchValue<Map<String, Any?>?>? = null,
    val updated: String,
    val eTag: String,
    val status: PatchValue<String?>?,
    val type: PatchValue<String?>?,
)
```

### Remove channel members

Remove members from a Channel.

#### Method(s)

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

```kotlin
pubnub.removeChannelMembers(
    userIds: List<String>,
    channel: String,
    limit: Int? = null,
    page: PNPage? = null,
    filter: String? = null,
    sort: Collection<PNSortKey<PNMemberKey>> = listOf(),
    include: MemberInclude = MemberInclude(),
).async { result -> }
```

| Parameter | Description |
| --- | --- |
| `userIds`Type: `List<String>`Default: n/a | List of members userIDs to remove from channel. |
| `channel`Type: `String`Default: n/a | Channel name. |
| `limit`Type: `Int`Default: 100 | The number of objects to retrieve at a time. |
| `page`Type: `PNPage?`Default: `null` | The paging object used for pagination. |
| `filter`Type: `String?`Default: `null` | Filter expression. Only matching objects are returned. See [filtering](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `Collection<PNSortKey<PNMemberKey>>`Default: `listOf()` | List of properties to sort by. Available options are `PNMemberKey.UUID_ID`, `PNMemberKey.UUID_NAME`,`PNMemberKey.UUID_UPDATED`, `PNMemberKey.UUID_NAME`,`PNMemberKey.UUID_TYPE`, `PNMemberKey.UPDATED`,`PNMemberKey.STATUS`, `PNMemberKey.TYPE`. Use `PNSortKey.PNAsc` or `PNSortKey.PNDesc` to specify sort direction. For example: `PNSortKey.PNAsc(PNMemberKey.TYPE)` or `PNSortKey.PNDesc(PNMemberKey.STATUS)`. |
| `include`Type: `MemberInclude`Default: `MemberInclude()` | Object holding the configuration for whether to include additional data in the response. |

#### Sample code

```kotlin
pubnub.removeChannelMembers(
    channel = "myChannel",
    userIds = listOf("myUserId"),
    include = MemberInclude(includeUser = true, includeStatus = true, includeType = true),
).async { result ->
    result.onFailure { exception ->
        // Handle error
    }.onSuccess { value ->
        // Handle successful method result
    }
}
```

#### Response

```kotlin
data class PNMemberArrayResult(
    val status: Int,
    val data: Collection<PNMember>,
    val totalCount: Int?,
    val next: PNPage.PNNext?,
    val prev: PNPage.PNPrev?
)

data class PNMember(
    val uuid: PNUUIDMetadata,
    val custom: PatchValue<Map<String, Any?>?>? = null,
    val updated: String,
    val eTag: String,
    val status: PatchValue<String?>?,
    val type: PatchValue<String?>?,
)
```

### Manage channel members

Set and Remove channel memberships for a user.

#### Method(s)

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

```kotlin
pubnub.manageChannelMembers(
    channel: String,
    usersToSet: List<PNMember.Partial>,
    userIdsToRemove: List<String>,
    limit: Int? = null,
    page: PNPage? = null,
    filter: String? = null,
    sort: Collection<PNSortKey<PNMemberKey>> = listOf(),
    include: MemberInclude = MemberInclude(),
).async { result, status ->
    if (status.error) {
        // Handle error
    } else if (result != null) {
        // Handle successful result
    }
}
```

| Parameter | Description |
| --- | --- |
| `channel`Type: `String`Default: n/a | Channel name. |
| `usersToSet`Type: `List<PNMember.Partial>`Default: n/a | List of members `PNMember.Partial` to add to the channel with optional custom metadata. |
| `userIdsToRemove`Type: `List<String>`Default: n/a | List of members userIds to remove from the channel. |
| `limit`Type: `Int?`Default: 100 | The number of objects to retrieve at a time. |
| `page`Type: `PNPage?`Default: `null` | The paging object used for pagination. |
| `filter`Type: `String?`Default: `null` | Filter expression. Only matching objects are returned. See [filtering](https://www.pubnub.com/docs/general/metadata/filtering). |
| `sort`Type: `Collection<PNSortKey<PNMemberKey>>`Default: `listOf()` | List of properties to sort by. Available options are `PNMemberKey.UUID_ID`, `PNMemberKey.UUID_NAME`,`PNMemberKey.UUID_UPDATED`, `PNMemberKey.UUID_NAME`,`PNMemberKey.UUID_TYPE`, `PNMemberKey.UPDATED`,`PNMemberKey.STATUS`, `PNMemberKey.TYPE`. Use `PNSortKey.PNAsc` or `PNSortKey.PNDesc` to specify sort direction. For example: `PNSortKey.PNAsc(PNMemberKey.TYPE)` or `PNSortKey.PNDesc(PNMemberKey.STATUS)`. |
| `include`Type: `MemberInclude`Default: `MemberInclude()` | Object holding the configuration for whether to include additional data in the response. |

#### Sample code

```kotlin
val pnMemberArrayResult: PNMemberArrayResult = pubnub.manageChannelMembers(
    channel = "myChannel",
    usersToSet = listOf(PNMember.Partial(uuidId = "myUserId", status = "myStatus", type = "distinctType")),
    userIdsToRemove = listOf(),
    include = MemberInclude(includeStatus = true, includeType = true)
).sync()
```

#### Response

```kotlin
data class PNMemberArrayResult(
    val status: Int,
    val data: Collection<PNMember>,
    val totalCount: Int?,
    val next: PNPage.PNNext?,
    val prev: PNPage.PNPrev?
)

data class PNMember(
    val uuid: PNUUIDMetadata,
    val custom: PatchValue<Map<String, Any?>?>? = null,
    val updated: String,
    val eTag: String,
    val status: PatchValue<String?>?,
    val type: PatchValue<String?>?,
)
```

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