---
source_url: https://www.pubnub.com/docs/sdks/unreal/api-reference/storage-and-playback
title: Message Persistence API for Unreal SDK
updated_at: 2026-06-15T09:17:48.523Z
sdk_name: PubNub Unreal SDK
sdk_version: 2.0.5
---

> 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


# Message Persistence API for Unreal SDK

PubNub Unreal SDK, use the latest version: 2.0.5

Message Persistence gives you real-time access to the history of messages published to PubNub. Each message is timestamped to the nearest 10 nanoseconds and stored across multiple availability zones in several geographic locations. You can encrypt stored messages with AES-256 so they are not readable on PubNub’s network. For details, see [Message Persistence](https://www.pubnub.com/docs/general/storage).

You control how long messages are stored through your account’s retention policy. Options include: 1 day, 7 days, 30 days, 3 months, 6 months, 1 year, or Unlimited.

You can retrieve the following:

* Messages
* Message reactions
* Files (using the File Sharing API)

##### Usage in Blueprints and C++

You can use PubNub's functionality via Blueprints or directly in C++ code.

* In Blueprints, the SDK is managed by a subsystem. Start by calling the Pubnub Subsystem node, then use Create Pubnub Client to create a UPubnubClient instance.
* In a C++ project, you have to add a dependency to PubnubLibrary: In your IDE, navigate to Source/_{YourProject}_/_{YourProject}_.Build.cs and add a dependency to PubnubLibrary. PrivateDependencyModuleNames.AddRange(new string[] { "PubnubLibrary" });, Compile the code and run the project.
* In C++, start by getting the UPubnubSubsystem (a Game Instance Subsystem), then create a UPubnubClient with your configuration. #include "Kismet/GameplayStatics.h"#include "PubnubSubsystem.h"#include "PubnubClient.h" UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(this);UPubnubSubsystem* PubnubSubsystem = GameInstance->GetSubsystem<UPubnubSubsystem>(); FPubnubConfig Config;Config.PublishKey = "pub-c-...";Config.SubscribeKey = "sub-c-...";Config.UserId = "my-user-id"; UPubnubClient* PubnubClient = PubnubSubsystem->CreatePubnubClient(Config); PubnubClient allows you to call PubNub SDK functions, for example: PubnubClient->PublishMessageAsync("my-channel", "Hello!", OnPublishMessageResponseDelegate); The SDK supports multiple UPubnubClient instances within the same game for different contexts such as different users or keysets. For more information, refer to Configuration.

:::note Asynchronous and synchronous method execution
Most PubNub Unreal SDK methods are available in both asynchronous and synchronous variants.
* Asynchronous methods (Async suffix) return void and take an optional delegate parameter that fires when the operation completes. 1PubnubClient->FetchHistoryAsync(Channel, OnFetchHistoryResponseDelegate, FetchHistorySettings); You can also use native callbacks that accept lambdas instead of dynamic delegates. Native callback types have the Native suffix (for example, FOnPubnubFetchHistoryResponseNative).
* Synchronous methods (no suffix) block the main game thread until the operation completes and return a result struct directly. 1FPubnubFetchHistoryResult Result = PubnubClient->FetchHistory(Channel, FetchHistorySettings);
:::

## Fetch history

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

This function fetches historical messages from one or multiple channels. The `IncludeMessageActions` flag also allows you to fetch message actions along with the messages.

It's possible to control how messages are returned and in what order.

* If you specify only the `Start` parameter (without `End`), you receive messages older than the `Start` timetoken.
* If you specify only the `End` parameter (without `Start`), you receive messages from that `End` timetoken and newer.
* If you specify both `Start` and `End`, you receive messages between those timetokens (inclusive of `End`).

Returns up to 100 messages on a single channel, or 25 per channel on up to 500 channels. To page, iteratively update the `Start` timetoken.

### Method(s)

```cpp
PubnubClient->FetchHistoryAsync(
    FString Channel,
    FOnPubnubFetchHistoryResponse OnFetchHistoryResponse,
    FPubnubFetchHistorySettings FetchHistorySettings = FPubnubFetchHistorySettings()
);
```

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| Channel | FString | Yes |  | The channel to get the historical messages of. |
| OnFetchHistoryResponse | FOnPubnubFetchHistoryResponse | Yes |  | The delegate for the operation's result. You can also use a native callback of the type [FOnPubnubFetchHistoryResponseNative](#fonpubnubfetchhistoryresponsenative) to handle the result using a lambda. |
| FetchHistorySettings | FPubnubFetchHistorySettings | Optional |  | Struct defining history configuration. |

#### FPubnubFetchHistorySettings

| Parameter | Description |
| --- | --- |
| `MaxPerChannel`Type: int | Specifies the number of historical messages to return. Default and maximum is 100 for a single channel, 25 for multiple channels, and 25 if `IncludeMessageActions` is `true`. |
| `Reverse`Type: bool | Setting to `true` will traverse the time line in reverse starting with the oldest message first. Default is `false`. |
| `Start`Type: `FString` | timetoken delimiting the `start` of time slice (exclusive) to pull messages from. |
| `End`Type: `FString` | timetoken delimiting the `end` of time slice (inclusive) to pull messages from. |
| `IncludeMeta`Type: bool | Whether meta (passed when Publishing the message) should be included in response or not. |
| `IncludeMessageType`Type: bool | Pass `true` to receive the message type with each history message. Default is `false`. |
| `IncludeUserID`Type: bool | Pass `true` to receive the publisher `uuid` with each history message. Default is `false`. |
| `IncludeMessageActions`Type: bool | The flag denoting to retrieve history messages with `message` actions. If `true`, the method is limited to one channel and 25 messages only. Default is `false`. |
| `IncludeCustomMessageType`Type: bool | Indicates whether to retrieve messages with the custom message type. For more information, refer to [Retrieving Messages](https://www.pubnub.com/docs/general/storage#retrieve-messages). |

### Sample code

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

###### C++

#### Actor.h

```cpp
#include "PubnubClient.h"

// blueprint.yy21j44m
UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Message Persistence")
void FetchHistorySample();
	
UFUNCTION()
void OnFetchHistoryResponse_Simple(FPubnubOperationResult Result, const TArray<FPubnubHistoryMessageData>& Messages);
	
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::FetchHistorySample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
	FOnPubnubFetchHistoryResponse OnFetchHistoryResponse;
	OnFetchHistoryResponse.BindDynamic(this, &ASample_MessagePersistence::OnFetchHistoryResponse_Simple);

	//Fetch history for a channel
	FString Channel = TEXT("history-channel");
	PubnubClient->FetchHistoryAsync(Channel, OnFetchHistoryResponse);
}

// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::OnFetchHistoryResponse_Simple(FPubnubOperationResult Result, const TArray<FPubnubHistoryMessageData>& Messages)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to fetch history. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Successfully fetched history. Number of messages: %d"), Messages.Num());
		//List all received messages
		for (const FPubnubHistoryMessageData& Message : Messages)
		{
			UE_LOG(LogTemp, Log, TEXT("- Message: %s, Timetoken: %s"), *Message.Message, *Message.Timetoken);
		}
	}
}
```

###### Blueprint

:::note Truncated response
If truncated, a `more` property will be returned with additional parameters. Make iterative calls adjusting parameters.
:::

### Returns

This method is void. The delegate returns the following struct:

#### FOnPubnubFetchHistoryResponse

Delegate type: `DECLARE_DYNAMIC_DELEGATE_TwoParams`

| Parameter | Description |
| --- | --- |
| `Result`Type: [FPubnubOperationResult](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |
| `Messages`Type: `const TArray<FPubnubHistoryMessageData>&` | An array of historical messages. |

#### FOnPubnubFetchHistoryResponseNative

Native callback variant that accepts a lambda.

| Parameter | Description |
| --- | --- |
| `Result`Type: [const FPubnubOperationResult&](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |
| `Messages`Type: `const TArray<FPubnubHistoryMessageData>&` | An array of historical messages. |

#### FPubnubHistoryMessageData

| Field | Type | Description |
| --- | --- | --- |
| `Message` | `FString` | The message text. |
| `Channel` | `FString` | Channel that message was published to. |
| `UserID` | `FString` | User ID of the user who sent the message. |
| `timetoken` | `FString` | timetoken indicating when the message was sent. |
| `Meta` | `FString` | Additional information. |
| `MessageType` | `FString` | Type of the message. Refer to [Message types](https://www.pubnub.com/docs/general/messages/type) for more information. |
| `CustomMessageType` | `FString` | The custom message type associated with the message. |
| `MessageActions` | `TArray<FPubnubMessageActionData>` | An array of [FPubnubMessageActionData](#fpubnubmessageactiondata) structs which are [message actions](https://www.pubnub.com/docs/general/messages/actions) that were added to the historical messages. |

#### FPubnubMessageActionData

| Field | Type | Description |
| --- | --- | --- |
| `Type` | `FString` | Message action type. |
| `Value` | `FString` | Message action value. |
| `UserID` | `FString` | User ID of the user who added the action. |
| `ActionTimetoken` | `FString` | timetoken indicating when the message action was added. |
| `MessageTimetoken` | `FString` | timetoken indicating when the message the action was added to had been sent. |

### Other examples

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

#### Fetch history for a specific time window

You can add a time window to the request:

#### Actor.h

```cpp
#include "PubnubClient.h"

UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Message Persistence")
void FetchHistoryWithTimeWindowSample();

UFUNCTION()
void OnFetchHistoryResponse_WithTimeWindow(FPubnubOperationResult Result, const TArray<FPubnubHistoryMessageData>& Messages);
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::FetchHistoryWithTimeWindowSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Create settings with a specific time window
	FPubnubFetchHistorySettings Settings;
	Settings.Start = TEXT("17298418360000000"); // Newer timetoken (exclusive)
	Settings.End = TEXT("17292370360000000");   // Older timetoken (inclusive)

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
	FOnPubnubFetchHistoryResponse OnFetchHistoryResponse;
	OnFetchHistoryResponse.BindDynamic(this, &ASample_MessagePersistence::OnFetchHistoryResponse_WithTimeWindow);

	//Fetch history for a channel
	FString Channel = TEXT("history-channel");
	PubnubClient->FetchHistoryAsync(Channel, OnFetchHistoryResponse, Settings);
}

// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::OnFetchHistoryResponse_WithTimeWindow(FPubnubOperationResult Result, const TArray<FPubnubHistoryMessageData>& Messages)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to fetch history. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Successfully fetched history with time window. Number of messages: %d"), Messages.Num());
		//List all received messages
		for (const FPubnubHistoryMessageData& Message : Messages)
		{
			UE_LOG(LogTemp, Log, TEXT("- Message: %s, Timetoken: %s"), *Message.Message, *Message.Timetoken);
		}
	}
}
```

#### Fetch history with all additional parameters

You can add additional parameters to the request:

#### Actor.h

```cpp
#include "PubnubClient.h"

UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Message Persistence")
void FetchHistoryWithAllIncludesSample();

UFUNCTION()
void OnFetchHistoryResponse_WithAllIncludes(FPubnubOperationResult Result, const TArray<FPubnubHistoryMessageData>& Messages);
	
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::FetchHistoryWithAllIncludesSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Create settings to include all extra data
	FPubnubFetchHistorySettings Settings;
	Settings.IncludeMeta = true;
	Settings.IncludeMessageType = true;
	Settings.IncludeUserID = true;
	Settings.IncludeMessageActions = true;
	Settings.IncludeCustomMessageType = true;
	
	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
	FOnPubnubFetchHistoryResponse OnFetchHistoryResponse;
	OnFetchHistoryResponse.BindDynamic(this, &ASample_MessagePersistence::OnFetchHistoryResponse_WithAllIncludes);

	//Fetch history for a channel
	FString Channel = TEXT("history-channel");
	PubnubClient->FetchHistoryAsync(Channel, OnFetchHistoryResponse, Settings);
}

// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::OnFetchHistoryResponse_WithAllIncludes(FPubnubOperationResult Result, const TArray<FPubnubHistoryMessageData>& Messages)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to fetch history. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Successfully fetched history with all includes. Number of messages: %d"), Messages.Num());
		//List all received messages
		for (const FPubnubHistoryMessageData& Message : Messages)
		{
			UE_LOG(LogTemp, Log, TEXT("- Message: %s, Timetoken: %s, Meta: %s, MessageType: %s, UserID: %s, CustomMessageType: %s"), 
				*Message.Message, *Message.Timetoken, *Message.Meta, *Message.MessageType, *Message.UserID, *Message.CustomMessageType);
		}
	}
}
```

#### Fetch history with lambda

You can use a lambda function to handle the response:

#### Actor.h

```cpp
#include "PubnubClient.h"

UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Message Persistence")
void FetchHistoryWithLambdaSample();
	
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::FetchHistoryWithLambdaSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind lambda to response delegate
	FOnPubnubFetchHistoryResponseNative OnFetchHistoryResponse;
	OnFetchHistoryResponse.BindLambda([](const FPubnubOperationResult& Result, const TArray<FPubnubHistoryMessageData>& Messages)
	{
		if(Result.Error)
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to fetch history. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
		}
		else
		{
			UE_LOG(LogTemp, Log, TEXT("Successfully fetched history. Number of messages: %d"), Messages.Num());
			//List all received messages
			for (const FPubnubHistoryMessageData& Message : Messages)
			{
				UE_LOG(LogTemp, Log, TEXT("- Message: %s, Timetoken: %s"), *Message.Message, *Message.Timetoken);
			}
		}
	});
	
	//Fetch history for a channel
	FString Channel = TEXT("history-channel");
	PubnubClient->FetchHistoryAsync(Channel, OnFetchHistoryResponse);
}
```

## Delete messages from history

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

Removes the messages from the history of a specific channel.

:::note Required setting
Enable Delete-From-History in key settings and initialize with a secret key.
:::

### Method(s)

```cpp
PubnubClient->DeleteMessagesAsync(
    FString Channel,
    FOnPubnubDeleteMessagesResponse OnDeleteMessagesResponse,
    FPubnubDeleteMessagesSettings DeleteMessagesSettings = FPubnubDeleteMessagesSettings()
);
```

| Parameter | Description |
| --- | --- |
| `Channel` *Type: `FString` | The channel to get the historical messages of. |
| `OnDeleteMessagesResponse` *Type: [FOnPubnubDeleteMessagesResponse](#fonpubnubdeletemessagesresponse) | The delegate for the operation's result. You can also use a native callback of the type [FOnPubnubDeleteMessagesResponseNative](#fonpubnubdeletemessagesresponsenative) to handle the result using a lambda. |
| `DeleteMessagesSettings`Type: [FPubnubDeleteMessagesSettings](#fpubnubdeletemessagessettings) | Struct defining delete messages configuration. |

#### FPubnubDeleteMessagesSettings

| Parameter | Description |
| --- | --- |
| `Start`Type: `FString` | timetoken delimiting the `start` of time slice (inclusive) to delete messages from. |
| `End`Type: `FString` | timetoken delimiting the `end` of time slice (exclusive) to delete messages from. |

### Sample code

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

###### C++

#### Actor.h

```cpp
#include "PubnubClient.h"

// blueprint.6nhkck5i
UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Message Persistence")
void DeleteMessagesSample();
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::DeleteMessagesSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	//Delete all messages from a channel
	FString Channel = TEXT("history-channel");
	PubnubClient->DeleteMessagesAsync(Channel);
}
```

###### Blueprint

### Returns

This method is void. The delegate returns the following struct:

#### FOnPubnubDeleteMessagesResponse

Delegate type: `DECLARE_DYNAMIC_DELEGATE_OneParam`

| Parameter | Description |
| --- | --- |
| `Result`Type: [FPubnubOperationResult](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |

#### FOnPubnubDeleteMessagesResponseNative

Native callback variant that accepts a lambda.

| Parameter | Description |
| --- | --- |
| `Result`Type: [const FPubnubOperationResult&](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |

### Other examples

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

#### Delete specific message from history

To delete a specific message, pass the `publish timetoken` (received from a successful publish) in the `End` parameter and timetoken `- 1` in the `Start` parameter. For example, if `15526611838554310` is the publish timetoken, pass `15526611838554309` in `Start` and `15526611838554310` in `End`.

#### Actor.h

```cpp
#include "PubnubClient.h"

UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Message Persistence")
void DeleteMessagesWithSettingsSample();
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::DeleteMessagesWithSettingsSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Create settings with a specific time window to delete
	FPubnubDeleteMessagesSettings Settings;
	Settings.Start = TEXT("17298418360000000"); // Newer timetoken (exclusive)
	Settings.End = TEXT("17292370360000000");   // Older timetoken (inclusive)
	
	//Delete messages from a channel within the specified time window
	FString Channel = TEXT("history-channel");
	PubnubClient->DeleteMessagesAsync(Channel, Settings);
}
```

#### Delete messages with result struct

You can use the result struct to handle the response:

#### Actor.h

```cpp
#include "PubnubClient.h"

UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Message Persistence")
void DeleteMessagesWithResultSample();

UFUNCTION()
void OnDeleteMessagesResponse(FPubnubOperationResult Result);
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::DeleteMessagesWithResultSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
	FOnPubnubDeleteMessagesResponse OnDeleteMessagesResponse;
	OnDeleteMessagesResponse.BindDynamic(this, &ASample_MessagePersistence::OnDeleteMessagesResponse);

	//Delete all messages from a channel
	FString Channel = TEXT("history-channel");
	PubnubClient->DeleteMessagesAsync(Channel, OnDeleteMessagesResponse);
}

// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::OnDeleteMessagesResponse(FPubnubOperationResult Result)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to delete messages. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Successfully deleted messages."));
	}
}
```

#### Delete messages with lambda

You can use a lambda function to handle the response:

#### Actor.h

```cpp
#include "PubnubClient.h"

UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Message Persistence")
void DeleteMessagesWithResultLambdaSample();
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::DeleteMessagesWithResultLambdaSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind lambda to response delegate
	FOnPubnubDeleteMessagesResponseNative OnDeleteMessagesResponse;
	OnDeleteMessagesResponse.BindLambda([](const FPubnubOperationResult& Result)
	{
		if(Result.Error)
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to delete messages. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
		}
		else
		{
			UE_LOG(LogTemp, Log, TEXT("Successfully deleted messages."));
		}
	});
	
	//Delete all messages from a channel
	FString Channel = TEXT("history-channel");
	PubnubClient->DeleteMessagesAsync(Channel, OnDeleteMessagesResponse);
}
```

## Message counts

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

Returns the number of messages published on one or more channels since a given time. The count returned is the number of messages in history with a `timetoken` value greater than or equal to than the passed value in the `timetoken` parameter.

:::note Unlimited message retention
For keys with unlimited message retention enabled, this method considers only messages published in the last 30 days.
:::

### Method(s)

```cpp
PubnubClient->MessageCountsAsync(
    FString Channel,
    FString Timetoken,
    FOnPubnubMessageCountsResponse OnMessageCountsResponse
);
```

| Parameter | Description |
| --- | --- |
| `Channel` *Type: `FString` | The channel to get the message counts of. |
| `Timetoken` *Type: `FString` | The timetoken to fetch the message counts from. |
| `OnMessageCountsResponse` *Type: [FOnPubnubMessageCountsResponse](#fonpubnubmessagecountsresponse) | The delegate for the operation's result. You can also use a native callback of the type [FOnPubnubMessageCountsResponseNative](#fonpubnubmessagecountsresponsenative) to handle the result using a lambda. |

### Sample code

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

###### C++

#### Actor.h

```cpp
#include "PubnubClient.h"

// blueprint.cw7px-_q
UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Message Persistence")
void MessageCountsSample();

UFUNCTION()
void OnMessageCountsResponse(FPubnubOperationResult Result, int MessageCounts);
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::MessageCountsSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind response delegate
	// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
	FOnPubnubMessageCountsResponse OnMessageCountsResponse;
	OnMessageCountsResponse.BindDynamic(this, &ASample_MessagePersistence::OnMessageCountsResponse);

	//Get message counts for a channel from a specific timetoken
	FString Channel = TEXT("history-channel");
	FString Timetoken = TEXT("17292370360000000");
	PubnubClient->MessageCountsAsync(Channel, Timetoken, OnMessageCountsResponse);
}

// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::OnMessageCountsResponse(FPubnubOperationResult Result, int MessageCounts)
{
	if(Result.Error)
	{
		UE_LOG(LogTemp, Error, TEXT("Failed to get message counts. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Successfully got message counts: %d"), MessageCounts);
	}
}
```

###### Blueprint

### Returns

This method is void. The delegate returns the following struct:

#### FOnPubnubMessageCountsResponse

Delegate type: `DECLARE_DYNAMIC_DELEGATE_TwoParams`

| Parameter | Description |
| --- | --- |
| `Result`Type: [FPubnubOperationResult](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |
| `MessageCounts`Type: `int` | The number of messages published on one or more channels since a given time. |

#### FOnPubnubMessageCountsResponseNative

Native callback variant that accepts a lambda.

| Parameter | Description |
| --- | --- |
| `Result`Type: [const FPubnubOperationResult&](https://www.pubnub.com/docs/sdks/unreal/api-reference/configuration#operation-result) | The result of the operation. |
| `MessageCounts`Type: `int` | The number of messages published on one or more channels since a given time. |

### Other examples

:::tip Reference code
Set up your Unreal project and follow the instructions in the lines marked with
ACTION REQUIRED
before running the code.
:::

#### Message counts with lambda

You can use a lambda function to handle the response:

#### Actor.h

```cpp
#include "PubnubClient.h"

UFUNCTION(BlueprintCallable, Category = "Pubnub|Samples|Message Persistence")
void MessageCountsWithLambdaSample();
	
```

#### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_MessagePersistence with name of your Actor class
void ASample_MessagePersistence::MessageCountsWithLambdaSample()
{
	// snippet.hide
	UPubnubClient* PubnubClient = GetPubnubClient();
	// snippet.show
	
	//Assumes PubnubClient is created and UserID is set

	// Bind lambda to response delegate
	FOnPubnubMessageCountsResponseNative OnMessageCountsResponse;
	OnMessageCountsResponse.BindLambda([](const FPubnubOperationResult& Result, int MessageCounts)
	{
		if(Result.Error)
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to get message counts. Status: %d, Reason: %s"), Result.Status, *Result.ErrorMessage);
		}
		else
		{
			UE_LOG(LogTemp, Log, TEXT("Successfully got message counts: %d"), MessageCounts);
		}
	});
	
	//Get message counts for a channel from a specific timetoken
	FString Channel = TEXT("history-channel");
	FString Timetoken = TEXT("17292370360000000");
	PubnubClient->MessageCountsAsync(Channel, Timetoken, OnMessageCountsResponse);
}
```

## Message counts multiple

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

Returns the number of messages published on multiple channels since given timetokens. For each channel you provide a corresponding timetoken; the count for that channel is the number of messages in history with a timetoken greater than or equal to the given value.

:::note Unlimited message retention
For keys with unlimited message retention enabled, this method considers only messages published in the last 30 days.
:::

### Method(s)

```cpp
PubnubClient->MessageCountsMultipleAsync(
    TArray<FString> Channels,
    TArray<FString> Timetokens,
    FOnPubnubMessageCountsMultipleResponse OnMessageCountsMultipleResponse
);
```

| Parameter | Description |
| --- | --- |
| `Channels` *Type: `TArray<FString>` | The channels to get the message counts of. |
| `Timetokens` *Type: `TArray<FString>` | One timetoken per channel; the count for each channel is from that timetoken onward. |
| `OnMessageCountsMultipleResponse` *Type: [FOnPubnubMessageCountsMultipleResponse](#fonpubnubmessagecountsmultipleresponse) | The delegate for the operation's result. You can also use [FOnPubnubMessageCountsMultipleResponseNative](#fonpubnubmessagecountsmultipleresponsenative) with a lambda. |

### Returns

This method is void. The delegate returns the following struct:

#### FOnPubnubMessageCountsMultipleResponse

Delegate type: `DECLARE_DYNAMIC_DELEGATE_OneParam`

| Parameter | Description |
| --- | --- |
| `Result`Type: `FPubnubMessageCountsMultipleResult` | The operation result including message counts per channel. |

#### FOnPubnubMessageCountsMultipleResponseNative

Native callback variant that accepts a lambda.

| Parameter | Description |
| --- | --- |
| `Result`Type: `const FPubnubMessageCountsMultipleResult&` | The operation result including message counts per channel. |

## Deprecated methods

### Fetch history (deprecated)

:::warning Deprecated
Use [PubnubClient->FetchHistory()](#fetch-history) (synchronous) or [PubnubClient->FetchHistoryAsync()](#fetch-history) (asynchronous) instead.
:::

#### Method(s) (deprecated)

```cpp
PubnubSubsystem->FetchHistory(
    FString Channel,
    FOnFetchHistoryResponse OnFetchHistoryResponse,
    FPubnubFetchHistorySettings FetchHistorySettings = FPubnubFetchHistorySettings()
);
```

| Parameter | Description |
| --- | --- |
| `Channel` *Type: `FString` | The channel to get the historical messages of. |
| `OnFetchHistoryResponse` *Type: `FOnFetchHistoryResponse` | The delegate for the operation's result. |
| `FetchHistorySettings`Type: `FPubnubFetchHistorySettings` | Struct defining history configuration. |

#### Returns (deprecated)

This function is void, but the delegate returns the `FOnFetchHistoryResponse` struct (Result, Messages).

### Delete messages from history (deprecated)

:::warning Deprecated
Use [PubnubClient->DeleteMessages()](#delete-messages-from-history) (synchronous) or [PubnubClient->DeleteMessagesAsync()](#delete-messages-from-history) (asynchronous) instead.
:::

#### Method(s) (deprecated)

```cpp
PubnubSubsystem->DeleteMessages(
    FString Channel,
    FOnDeleteMessagesResponse OnDeleteMessagesResponse,
    FPubnubDeleteMessagesSettings DeleteMessagesSettings = FPubnubDeleteMessagesSettings()
);
```

| Parameter | Description |
| --- | --- |
| `Channel` *Type: `FString` | The channel to get the historical messages of. |
| `OnDeleteMessagesResponse` *Type: `FOnDeleteMessagesResponse` | The delegate for the operation's result. |
| `DeleteMessagesSettings`Type: `FPubnubDeleteMessagesSettings` | Struct defining delete messages configuration. |

#### Returns (deprecated)

This function is void, but the delegate returns the `FOnDeleteMessagesResponse` struct (Result).

### Message counts (deprecated)

:::warning Deprecated
Use [PubnubClient->MessageCounts()](#message-counts) (synchronous) or [PubnubClient->MessageCountsAsync()](#message-counts) (asynchronous) instead.
:::

#### Method(s) (deprecated)

```cpp
PubnubSubsystem->MessageCounts(
    FString Channel,
    FString Timetoken,
    FOnMessageCountsResponse OnMessageCountsResponse
);
```

| Parameter | Description |
| --- | --- |
| `Channel` *Type: `FString` | The channel to get the message counts of. |
| `Timetoken` *Type: `FString` | The timetoken to fetch the message counts from. |
| `OnMessageCountsResponse` *Type: `FOnMessageCountsResponse` | The delegate for the operation's result. |

#### Returns (deprecated)

This function is void, but the delegate returns the `FOnMessageCountsResponse` struct (Result, MessageCounts).

## 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.
* **Message** - A unit of data transmitted between clients or between a client and a server in PubNub, containing information such as text, binary data, or structured data formats like JSON. Messages are sent over channels and can be tracked for delivery and read status.
* **PubNub** - PubNub is a real-time messaging platform that provides APIs and SDKs for building scalable applications. It handles the complex infrastructure of real-time communication, including: Message delivery and persistence, Presence detection, Access control, Push notifications, File sharing, Serverless processing with Functions and Events & Actions, Analytics and monitoring with BizOps Workspace, AI-powered insights with Illuminate.
* **Timetoken** - A unique identifier for each message that represents the number of 100-nanosecond intervals since January 1, 1970, for example, 16200000000000000.