---
source_url: https://www.pubnub.com/docs/sdks/python/api-reference/message-actions
title: Message Actions API for Python SDK
updated_at: 2026-06-12T11:26:23.371Z
sdk_name: PubNub Python SDK
sdk_version: 10.7.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


# Message Actions API for Python SDK

PubNub Python SDK, use the latest version: 10.7.0

Install:

```bash
pip install pubnub@10.7.0
```

Use message actions to add or remove metadata on published messages. Common uses include receipts and reactions. Clients subscribe to a channel to receive message action events. Clients can also fetch past message actions from Message Persistence, either on demand or when fetching original messages.

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

:::tip Reactions
"Message Reactions" is a specific application of the Message Actions API for emoji or social reactions.
:::

:::note Message Actions vs. Message Reactions
**Message Actions** is the flexible, low-level API for adding any metadata to messages (read receipts, delivery confirmations, custom data), while **Message Reactions** specifically refers to using Message Actions for emoji/social reactions.
In PubNub [Core](https://www.pubnub.com/docs/sdks) and [Chat](https://www.pubnub.com/docs/chat/overview) SDKs, the same underlying Message Actions API is referred to as **Message Reactions** when used for emoji reactions - it's the same functionality, just different terminology depending on the use case.
:::

## Add message action

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

Add an action to a published message. The response includes the added action.

### Method(s)

Use this Python method:

```python
pubnub.add_message_action() \
    .channel(String) \
    .message_action(PNMessageAction) \
    .pn_async(Function message_action_callback)
```

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| channel | String | Yes |  | Channel name to add the message action to. |
| message_action | PNMessageAction | Yes |  | Message action payload. |
| message_action.type | String | Yes |  | Message action type. |
| message_action.value | String | Yes |  | Message action value. |
| message_action.message_timetoken | Integer | Yes |  | Timetoken of the target message. |
| message_action_callback | Function | Yes |  | Callback for success or error. Details in [PNMessageAction callback](#pnmessageaction). |

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

```python
import os
import time
from pubnub.pnconfiguration import PNConfiguration
from pubnub.pubnub import PubNub
from pubnub.models.consumer.message_actions import PNMessageAction

def add_message_action(pubnub: PubNub):
    msg_action = PNMessageAction()
    msg_action.type = "reaction"
    msg_action.value = "smiley_face"
    msg_action.message_timetoken = str(int(time.time()))

    result = pubnub.add_message_action() \
        .channel("chats.room1") \
        .message_action(msg_action) \
        .sync()

    if result.status.is_error():
        print(f"Error: {result.status.error_data}")
    else:
        print("Message action added successfully.")
        print(f"Response: {result.result.__dict__}")

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)

    # Add message action
    add_message_action(pubnub)

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

###### Named Arguments

```python
import os
import time
from pubnub.pnconfiguration import PNConfiguration
from pubnub.pubnub import PubNub
from pubnub.models.consumer.message_actions import PNMessageAction

def add_message_action(pubnub: PubNub):
    msg_action = PNMessageAction()
    msg_action.type = "reaction"
    msg_action.value = "smiley_face"
    msg_action.message_timetoken = str(int(time.time()))

    result = pubnub.add_message_action(
        channel="chats.room1",
        message_action=msg_action
    ).sync()

    if result.status.is_error():
        print(f"Error: {result.status.error_data}")
    else:
        print("Message action added successfully.")
        print(f"Response: {result.result.__dict__}")

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)

    # Add message action
    add_message_action(pubnub)

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

### Returns

The `add_message_action()` operation returns an `Envelope` with the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNAddMessageActionResult](#pnaddmessageactionresult) | Operation result. |
| status | `PNStatus` | Operation status. |

#### PNAddMessageActionResult

```json
{
  'action_timetoken': '15956343330507960',
  'message_timetoken': '1595634332',
  'type': 'reaction',
  'uuid': 'my_uuid',
  'value': 'smiley_face'
}
```

## Remove message action

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

Remove a previously added action from a published message. The response is empty.

### Method(s)

Use this Python method:

```python
pubnub.remove_message_action() \
    .channel(String) \
    .action_timetoken(Integer) \
    .message_timetoken(Integer) \
    .pn_async(message_action_callback)
```

| Parameter | Description |
| --- | --- |
| `channel` *Type: String | Channel name to remove the message action from. |
| `action_timetoken` *Type: Integer | Timetoken of the message action to remove. |
| `message_timetoken` *Type: Integer | Timetoken of the target message. |
| `message_action_callback` *Type: Function | Callback for success or error. Details in [PNMessageAction callback](#pnmessageaction). |

### Sample code

#### Builder Pattern

```python
pubnub.remove_message_action()\
    .channel("chats.room1")\
    .action_timetoken(15956346328442840)\
    .message_timetoken(1595634632)\
    .pn_async(message_action_callback)
```

#### Named Arguments

```python
from pubnub.models.consumer.message_actions import PNMessageAction

msg_action = PNMessageAction()
msg_action.type = "reaction"
msg_action.value = "smiley_face"
msg_action.message_timetoken = str(int(time.time()))

pubnub.remove_message_action(channel="chats.room1",
                             action_timetoken=15956346328442840,
                             message_timetoken=1595634632) \
    .pn_async(message_action_callback)
```

### Returns

The `remove_message_action()` operation returns an `Envelope` with the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNRemoveMessageActionResult](#pnremovemessageactionresult) | Operation result. |
| status | `PNStatus` | Operation status. |

#### PNRemoveMessageActionResult

```python
# in case of success (empty object)
{}
```

## Get message actions

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

Get a list of message actions in a channel. The response sorts actions by the action timetoken in ascending order.

### Method(s)

Use this Python method:

```python
pubnub.get_message_actions() \
  .channel(String) \
    .start(String) \
    .end(String) \
    .limit(Integer) \
    .pn_async(message_action_callback)
```

| Parameter | Description |
| --- | --- |
| `channel` *Type: String | Channel name to list message actions for. |
| `start`Type: String | Message action timetoken for the start of the range (exclusive). |
| `end`Type: String | Message action timetoken for the end of the range (inclusive). |
| `limit`Type: Integer | Maximum number of actions to return. If exceeded, results include a `more` token. See the [REST API documentation](https://www.pubnub.com/docs/sdks/rest-api/get-actions). |
| `message_action_callback` *Type: Function | Callback for success or error. Details in [PNMessageAction callback](#pnmessageaction). |

### Sample code

#### Builder Pattern

```python
# Retrieve all actions on a single message

pubnub.get_message_actions() \
    .channel("chats.room1") \
    .start("15956342921084731") \
    .end("15956342921084730") \
    .limit(50) \
    .pn_async(message_action_callback)
```

#### Named Arguments

```python
pubnub.get_message_actions(channel="chats.room1",
                           start="15956342921084731",
                           end="15956342921084730",
                           limit=50) \
    .pn_async(message_action_callback)
```

### Returns

The `get_message_actions` operation returns an `Envelope` with the following fields:

| Field | Type | Description |
| --- | --- | --- |
| result | [PNGetMessageActionsResult](#pngetmessageactionsresult) | Operation result. |
| status | `PNStatus` | Operation status. |

#### PNGetMessageActionsResult

```json
{
  'actions': [
    {
      'actionTimetoken': '15956373593404068',
      'messageTimetoken': '15956342921084730',
      'type': 'reaction',
      'uuid': 'my_uuid',
      'value': 'smiley_face'
    }
  ]
}
```

## PNMessageAction

The structure of a `PNMessageAction` is as follows:

```python
action = PNMessageAction({
    'uuid': 'user1',
    'type': 'reaction',
    'value': 'smiley_face',
    'actionTimetoken': '15901706735798836',
    'messageTimetoken': '15901706735795200',
})
```

The following is a sample `message_action_callback` method you can use as a starting point for your own implementation:

```python
def message_action_callback(envelope, status):
    if status.is_error():
        print(f"Uh oh. We had a problem sending the message. :( \n {status}")
        return
    if isinstance(envelope, PNAddMessageActionResult):
        print(f"Message Action type: {envelope.type}")
        print(f"Message Action value: {envelope.value}")
        print(f"Message Action timetoken: {envelope.message_timetoken}")
        print(f"Message Action uuid: {envelope.uuid}")
        print(f"Message Action timetoken: {envelope.action_timetoken}")
    elif isinstance(envelope, PNRemoveMessageActionResult):
        # Envelope here is an empty dictionary {}
        pass
    elif isinstance(envelope, PNGetMessageActionsResult):
        print("Message Actions Result:\n")
        for action in envelope.actions:
            print(f"Message Action type: {action.type}")
            print(f"Message Action value: {action.value}")
            print(f"Message Action timetoken: {action.message_timetoken}")
            print(f"Message Action uuid: {action.uuid}")
            print(f"Message Action timetoken: {action.action_timetoken}")
            print("")
```

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