# How to Send and Handle Message Reactions in OpenWA: REST API and SDK Guide

> Learn to send and handle message reactions in OpenWA using the REST API and SDK. This guide details the POST messages react and GET reactions endpoints for seamless integration.

- Repository: [Yudhi Armyndharis/OpenWA](https://github.com/rmyndharis/OpenWA)
- Tags: how-to-guide
- Published: 2026-05-21

---

**OpenWA enables sending and retrieving WhatsApp message reactions through the `POST /sessions/:sessionId/messages/react` endpoint and `GET .../reactions` endpoint, implemented via the [`whatsapp-web.js`](https://github.com/rmyndharis/OpenWA/blob/main/whatsapp-web.js) adapter layer.**

OpenWA is an open-source WhatsApp Web automation framework that exposes message reactions as part of its Extended Messaging API. The system provides type-safe TypeScript interfaces and a modular engine architecture, allowing developers to programmatically add emoji reactions to messages and retrieve reaction metadata using either direct HTTP requests or the official JavaScript SDK.

## API Architecture for Message Reactions

The reaction functionality follows a layered architecture that abstracts the underlying WhatsApp library behind a stable REST interface.

### Controller and Service Layer

The **API Layer** exposes HTTP endpoints through [`src/modules/message/message.controller.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/modules/message/message.controller.ts). The controller handles `POST` requests for adding or removing reactions and `GET` requests for retrieving reaction lists. Incoming requests are validated and forwarded to `MessageService.reactToMessage()` or `MessageService.getMessageReactions()` defined in [`src/modules/message/message.service.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/modules/message/message.service.ts).

The service layer manages session validation and acts as a proxy to the engine, ensuring business logic remains separate from transport concerns.

### Engine Interface Contract

All engine implementations must satisfy the `IWhatsAppEngine` interface declared in [`src/engine/interfaces/whatsapp-engine.interface.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/engine/interfaces/whatsapp-engine.interface.ts). This contract defines the method signatures:

- `reactToMessage(chatId: string, messageId: string, emoji: string): Promise<void>`
- `getMessageReactions(chatId: string, messageId: string): Promise<MessageReaction[]>`

This abstraction allows OpenWA to support multiple WhatsApp backend implementations while maintaining a consistent API surface.

### WhatsApp-Web-JS Adapter Implementation

The concrete implementation resides in [`src/engine/adapters/whatsapp-web-js.adapter.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/engine/adapters/whatsapp-web-js.adapter.ts). The `WhatsAppWebJsAdapter` class:

1. Locates the target chat and message by fetching the last 100 messages from the chat history
2. Invokes `Message.react(emoji)` to add reactions or `Message.getReactions()` to retrieve them
3. Transforms library-specific objects into the generic `MessageReaction` interface defined in [`src/engine/types/whatsapp-web-js.types.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/engine/types/whatsapp-web-js.types.ts)

## Sending Message Reactions

### REST Endpoint Specification

To add or remove a reaction, send a `POST` request to:

```

POST /sessions/:sessionId/messages/react

```

**Request body structure:**

```json
{
  "chatId": "12345@c.us",
  "messageId": "true_1234567890@c.us",
  "emoji": "👍"
}

```

**Key parameters:**
- `chatId`: The WhatsApp ID of the conversation (e.g., `12345@c.us` for individuals or `123456789@g.us` for groups)
- `messageId`: The serialized message ID (prefixed with `true_` for standard messages)
- `emoji`: The Unicode emoji character to react with; pass an empty string `""` to remove the reaction

### SDK Implementation

Using the official JavaScript SDK:

```typescript
import { OpenWASdk } from '@openwa/sdk';

const sdk = new OpenWASdk({ baseUrl: 'http://localhost:3000' });

await sdk.sessions('sess-1')
         .messages
         .react({
           chatId: '12345@c.us',
           messageId: 'true_1678901234@c.us',
           emoji: '👍'
         });

```

### Removing Reactions

To remove a reaction, pass an empty string as the emoji value:

```typescript
await sdk.sessions('sess-1')
         .messages
         .react({
           chatId: '12345@c.us', 
           messageId: 'true_1678901234@c.us',
           emoji: ''
         });

```

The underlying [`whatsapp-web.js`](https://github.com/rmyndharis/OpenWA/blob/main/whatsapp-web.js) library interprets the empty payload as a removal command.

## Retrieving Message Reactions

### GET Endpoint Structure

Fetch all reactions for a specific message using:

```

GET /sessions/:sessionId/messages/:chatId/:messageId/reactions

```

The controller method `MessageController.getReactions()` invokes the adapter's `getMessageReactions()` method, which:
- Validates the session readiness via `this.ensureReady()`
- Retrieves the chat instance and locates the message within the last 100 fetched messages
- Calls `Message.getReactions()` and maps the results to the `MessageReaction` type

### Response Format

The endpoint returns an array of `MessageReaction` objects:

```json
[
  {
    "emoji": "👍",
    "senders": [
      { "senderId": "12345@c.us", "emoji": "👍", "timestamp": 1706400000 }
    ]
  },
  {
    "emoji": "❤️",
    "senders": [
      { "senderId": "67890@c.us", "emoji": "❤️", "timestamp": 1706400100 }
    ]
  }
]

```

Each reaction object contains the emoji character and a list of senders who applied that reaction, including their WhatsApp ID, the specific emoji used, and the UNIX timestamp of the reaction.

## Implementation Examples

### Direct HTTP with cURL

**Add a reaction:**

```bash
curl -X POST "http://localhost:3000/api/sessions/sess-1/messages/react" \
     -H "Content-Type: application/json" \
     -d '{"chatId":"12345@c.us","messageId":"true_1678901234@c.us","emoji":"👍"}'

```

**Retrieve reactions:**

```bash
curl "http://localhost:3000/api/sessions/sess-1/messages/12345@c.us/true_1678901234@c.us/reactions"

```

### Adapter Internal Logic

The `WhatsAppWebJsAdapter.reactToMessage()` method in [`src/engine/adapters/whatsapp-web-js.adapter.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/engine/adapters/whatsapp-web-js.adapter.ts) (lines 95-104) implements the low-level interaction:

```typescript
async reactToMessage(chatId: string, messageId: string, emoji: string): Promise<void> {
  this.ensureReady();
  const chat = await this.client!.getChatById(chatId);
  const messages = await chat.fetchMessages({ limit: 100 });
  const message = messages.find(m => m.id._serialized === messageId);
  if (!message) throw new Error(`Message ${messageId} not found in chat ${chatId}`);
  await (message as MessageWithReactions).react(emoji);
  this.logger.log(`Reacted to message ${messageId} with ${emoji || '(removed)'}`);
}

```

For retrieval, `getMessageReactions()` (lines 107-136) handles the transformation:

```typescript
async getMessageReactions(chatId: string, messageId: string): Promise<MessageReaction[]> {
  this.ensureReady();
  const chat = await this.client!.getChatById(chatId);
  const messages = await chat.fetchMessages({ limit: 100 });
  const message = messages.find(m => m.id._serialized === messageId);
  if (!message) throw new Error(`Message ${messageId} not found in chat ${chatId}`);
  const msgWithReactions = message as MessageWithReactions;
  if (!msgWithReactions.hasReaction) return [];

  const reactions = await msgWithReactions.getReactions();
  if (!reactions) return [];

  return reactions.map(r => ({
    emoji: String(r.id),
    senders: (r.senders ?? []).map(s => ({
      senderId: String(s.senderId),
      emoji: String(s.reaction),
      timestamp: Number(s.timestamp),
    })),
  }));
}

```

## Summary

- **Reaction endpoints**: Use `POST /sessions/:sessionId/messages/react` to add or remove reactions, and `GET /sessions/:sessionId/messages/:chatId/:messageId/reactions` to retrieve them
- **Architecture flow**: Requests traverse `MessageController` → `MessageService` → `IWhatsAppEngine` interface → `WhatsAppWebJsAdapter` → [`whatsapp-web.js`](https://github.com/rmyndharis/OpenWA/blob/main/whatsapp-web.js) library
- **Data model**: Reactions are returned as `MessageReaction` arrays containing emoji characters and sender metadata with timestamps
- **Removal mechanism**: Pass an empty string `""` as the emoji parameter to remove an existing reaction
- **Scope limitation**: The adapter searches within the last 100 messages of a chat to locate the target message by its serialized ID

## Frequently Asked Questions

### How do I remove a reaction in OpenWA?

Pass an empty string `""` as the `emoji` value in the `POST /sessions/:sessionId/messages/react` request. The [`whatsapp-web.js`](https://github.com/rmyndharis/OpenWA/blob/main/whatsapp-web.js) library interprets empty payloads as removal commands, and the adapter logs this action accordingly.

### What is the maximum number of messages searched when adding a reaction?

The `WhatsAppWebJsAdapter` fetches the last 100 messages from the chat history using `chat.fetchMessages({ limit: 100 })` to locate the target message by its serialized ID. If the message is older than the 100 most recent messages, the operation will fail with a "Message not found" error.

### Can I use custom emojis or stickers for reactions?

No, OpenWA only supports standard Unicode emoji characters through the WhatsApp Web protocol. The `emoji` parameter accepts single Unicode emoji characters (e.g., `"👍"`, `"❤️"`, `"😂"`) but does not support custom images or stickers for the reaction feature.

### What data structure defines a reaction in the OpenWA codebase?

Reactions follow the `MessageReaction` interface defined in [`src/engine/types/whatsapp-web-js.types.ts`](https://github.com/rmyndharis/OpenWA/blob/main/src/engine/types/whatsapp-web-js.types.ts) (lines 37-45). Each reaction contains an `emoji` string and a `senders` array, where each sender object includes `senderId` (WhatsApp JID), `emoji` (the reaction character), and `timestamp` (UNIX epoch in milliseconds).