# Messages

Messages

## Description

The **Messages** module provides access to messages exchanged within conversations. You can retrieve individual messages or lists of messages and also create new messages programmatically.

---

## Entity Model

### ExternalMessage

```graphql
type ExternalMessage {
   _id: ID
   sender: senderData
   conversation: ID
   messageType: MessageType
   channelType: ChannelType
   senderType: SenderType
   content: String
   contentHtml: String
   subject: String
   emailData: EmailDataType
   commentData: CommentDataType
   questionData: QuestionDataType
   media: [Media]
   template_cards: Object
   product_cards: Object
   channelMessageId: String
   ackStatus: AckType
   createdAt: Date
   autoCreate: Boolean
   failedReason: FailedReasonType
   surveyData: surveyDataForLivechat
   informativeButtons: InformativeButtonsType
   flowBotQuickReplyResponseId: String
   flowBotQuickReplyButtonsRequired: Boolean
   flowBotQuickReply: [FlowBotQuickReplyType]
   quotedMessage: QuotedMessageType
   reactions: ReactionEnum
   frontMsgId: String
   listMessage: ListMessageType
   catalogMessage: CatalogInteractiveType
   catalogOrderData: CatalogOrderDataType
}
```

| Field                              | Type                      | Description                                                         |
| ---------------------------------- | ------------------------- | ------------------------------------------------------------------- |
| `_id`                              | `ID`                      | Unique identifier of the message.                                   |
| `sender`                           | `senderData`              | Information about the sender of the message.                        |
| `conversation`                     | `ID`                      | Conversation this message belongs to.                               |
| `messageType`                      | `MessageType`             | Type of the message (e.g., text, image, email).                     |
| `channelType`                      | `ChannelType`             | Channel through which the message was sent (e.g., WhatsApp, Email). |
| `senderType`                       | `SenderType`              | Indicates if the sender is a user, system, or bot.                  |
| `content`                          | `String`                  | Plain text content of the message.                                  |
| `contentHtml`                      | `String`                  | HTML-formatted content.                                             |
| `subject`                          | `String`                  | Subject of the message (mainly for email).                          |
| `emailData`                        | `EmailDataType`           | Email-related metadata.                                             |
| `commentData`                      | `CommentDataType`         | Comment-related metadata.                                           |
| `questionData`                     | `QuestionDataType`        | Question-related metadata.                                          |
| `media`                            | `[Media]`                 | Attached media (images, videos, files).                             |
| `template_cards`                   | `Object`                  | Template cards associated with the message.                         |
| `product_cards`                    | `Object`                  | Product cards included in the message.                              |
| `channelMessageId`                 | `String`                  | Identifier of the message in the external channel.                  |
| `ackStatus`                        | `AckType`                 | Delivery status acknowledgment.                                     |
| `createdAt`                        | `Date`                    | Timestamp of when the message was created.                          |
| `autoCreate`                       | `Boolean`                 | Indicates if the message was auto-generated.                        |
| `failedReason`                     | `FailedReasonType`        | Reason for delivery failure, if applicable.                         |
| `surveyData`                       | `surveyDataForLivechat`   | Survey data for live chat interactions.                             |
| `informativeButtons`               | `InformativeButtonsType`  | Informative buttons included in the message.                        |
| `flowBotQuickReplyResponseId`      | `String`                  | Identifier for flow bot quick reply response.                       |
| `flowBotQuickReplyButtonsRequired` | `Boolean`                 | Indicates if quick reply buttons are required.                      |
| `flowBotQuickReply`                | `[FlowBotQuickReplyType]` | Flow bot quick reply options.                                       |
| `quotedMessage`                    | `QuotedMessageType`       | Reference to the quoted message, if any.                            |
| `reactions`                        | `ReactionEnum`            | Reactions to the message.                                           |
| `frontMsgId`                       | `String`                  | Frontend message ID.                                                |
| `listMessage`                      | `ListMessageType`         | List-type interactive message data.                                 |
| `catalogMessage`                   | `CatalogInteractiveType`  | Catalog message data.                                               |
| `catalogOrderData`                 | `CatalogOrderDataType`    | Order details for catalog messages.                                 |

---

## Queries

### Get Message

Use this query to get single message.

```graphql
type Query {
   externalGetMessage(input: ExternalGetMessageInput): ExternalMessageResponse!
}
```

**Input**:

```graphql
input ExternalGetMessageInput {
   messageId: ID!
}
```

**Response**:

```graphql
type ExternalMessageResponse {
   success: Boolean
   data: ExternalMessage!
   code: String
   message: String
}
```

### Get Message List

Use this query to get message lists for the conversation.

```graphql
type Query {
   externalGetMessageList(input: ExternalGetMessageListInput!): ExternalMessagesPaginatedResponse!
}
```

**Input**:

```graphql
input ExternalGetMessageListInput {
   conversationId: ID!
   offset: Int
   limit: Int
   type: MessageSearchType
}
```

**Response**:

```graphql
type ExternalMessagesPaginatedResponse {
   success: Boolean
   data: ExternalMessagesPaginate!
   code: String
   message: String
}

type ExternalMessagesPaginate {
   docs: [ExternalMessage]!
   hasNextPage: Boolean!
   totalDocs: Int!
}
```

## Mutations

### Create Message

Use this mutation to create a new message

```graphql
type Mutation {
   externalCreateMessage(input: ExternalCreateMessageInput!): ExternalCreatedMessageResponse!
}
```

**Input:**

```graphql
input ExternalCreateMessageInput {
   sender: ID!
   convId: ID
   pChannelId: String
   msgType: MessageType!
   content: String
   contentHtml: String
   media: [Media]
   template_cards: TemplateCardInput
   emailData: MailInfoInput
   subject: String
   msgId: String
   receiverIds: [String]
   channelType: ChannelType
   channelId: ID
   frontMsgId: String
   newTicketState: String
   isTicket: Boolean
}
```

**COMMENT message type requirements:**

When `msgType` is `COMMENT`, this mutation replies to an existing comment message. It does not create a standalone comment record. The existing message is updated with reply information in `commentData`.

| Field         | Description                                                       |
| ------------- | ----------------------------------------------------------------- |
| `msgType`     | Must be `COMMENT`.                                                |
| `msgId`       | Qpien internal `_id` of the original comment message to reply to. |
| `sender`      | Customer person / agent `_id` that sends the reply.               |
| `content`     | Reply text that will be sent to the external platform.            |
| `convId`      | Conversation `_id` that contains the original comment message.    |
| `pChannelId`  | Person channel `_id` for the customer/person in the conversation. |
| `channelId`   | Connected platform/channel `_id`.                                 |
| `channelType` | Channel type, for example `INSTAGRAM`.                            |
| `isTicket`    | Set to `false` unless the reply is part of a ticket flow.         |

> Important: `msgId` must be the internal message `_id`, not the platform `channelMessageId`.

**PRIVATE_REPLY message type requirements:**

When `msgType` is `PRIVATE_REPLY`, this mutation sends a private message reply for an existing public comment message. The target comment message is updated with private-reply information in `commentData`, and the created message is returned with `messageType: PRIVATE_REPLY`.

| Field         | Description                                                                    |
| ------------- | ------------------------------------------------------------------------------ |
| `msgType`     | Must be `PRIVATE_REPLY`.                                                       |
| `msgId`       | Qpien internal `_id` of the original comment message to privately reply to.    |
| `sender`      | Customer person / agent `_id` that sends the private reply.                    |
| `content`     | Private reply text that will be sent to the external platform.                 |
| `convId`      | Conversation `_id` that contains the original comment message.                 |
| `pChannelId`  | Person channel `_id` for the customer/person in the conversation.              |
| `channelId`   | Connected platform/channel `_id`.                                              |
| `channelType` | Supported channel type: `FACEBOOK`, `INSTAGRAM`, or `TIKTOK`.                 |
| `isTicket`    | Set to `false` unless the private reply is part of a ticket flow.              |

> Important: `msgId` must be the internal message `_id` of an existing `COMMENT` message, not the platform `channelMessageId`. Only one private reply can be sent for a comment.

**Response:**

```graphql
type ExternalCreatedMessageResponse {
   success: Boolean
   data: ExternalMessage!
   code: String
   message: String
}
```

### Create Message By Whatsapp

Use this mutation to create a new message by WhatsApp

```graphql
type Mutation {
   externalCreateMessageByWhatsapp(
      input: ExternalCreateMessageByWhatsappInput!
   ): ExternalCreatedMessageByWhatsappResponse!
}
```

**Input:**

```graphql
input ExternalCreateMessageByWhatsappInput {
   content: String
   channelType: ChannelType
   senderChannelId: String
   receiverIds: [String]
   templateId: String
   templateParams: [ExternalCreateMessageByWhatsappTemplateParam]
   media: [Media]
}
```

**Response:**

```graphql
type ExternalCreatedMessageByWhatsappResponse {
   success: Boolean
   data: Boolean!
   code: String
   message: String
}
```

---

## Example Usage

### Query Example — Get Message List

<Tabs>
  <Tab title="Bash (cURL)">
```bash
curl --location 'https://api.qpien.com/api/v1' \
--header 'Content-Type: application/json' \
--header 'Authorization: YOUR_ACCESS_TOKEN' \
--data '{
  "query": "query ExternalGetMessageList($input: ExternalGetMessageListInput!) { externalGetMessageList(input: $input) { success data { docs { _id   conversation messageType channelType senderType content contentHtml subject createdAt } hasNextPage totalDocs } code message } }",
  "variables": {
    "input": {
      "conversationId": "YOUR_CONVERSATION_ID",
      "offset": 0,
      "limit": 20
      
    }
  }
}'

````

  </Tab>
  <Tab title="Node.js">
```js
const query = `
  query ($input: ExternalGetMessageListInput!) {
    externalGetMessageList(input: $input) {
      success
      data {
        docs {
          _id
          content
          createdAt
          sender { id }
        }
        totalDocs
        hasNextPage
      }
    }
  }
`;

const variables = {
  input: {
    conversationId: "12345",
    limit: 10,
    offset: 0
  }
};

const response = await fetch("https://api.qpien.com/api/v1", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "<ACCESS_TOKEN>"
  },
  body: JSON.stringify({ query, variables })
});

const result = await response.json();
console.log(result);

````

  </Tab>
</Tabs>

### Mutation Example — Create Message

<Tabs>
  <Tab title="Bash (cURL)">
```bash
curl --location 'https://api.qpien.com/api/v1' \
--header 'Content-Type: application/json' \
--header 'Authorization: YOUR_ACCESS_TOKEN' \
--data '{
  "query": "mutation ExternalCreateMessage($input: ExternalCreateMessageInput!) { externalCreateMessage(input: $input) { success data { _id sender { _id firstName lastName email } conversation messageType channelType senderType content contentHtml subject createdAt } code message } }",
  "variables": {
    "input": {
      "sender": "SENDER_ID_HERE",
      "convId": "CONVERSATION_ID_HERE",
      "msgType": "TEXT",
      "content": "Hello, this is a test message",
      "channelType": "WHATS_APP_BUSINESS"
    }
  }
}'

````
  </Tab>
  <Tab title="Node.js">
```js
const mutation = `
  mutation ($input: ExternalCreateMessageInput!) {
    externalCreateMessage(input: $input) {
      success
      data {
        _id
        content
        messageType
        createdAt
      }
    }
  }
`;

const variables = {
  input: {
    sender: "67890",
    convId: "12345",
    msgType: "TEXT_MESSAGE",
    content: "Hello, this is a new message!"
  }
};

const response = await fetch("https://api.qpien.com/api/v1", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "<ACCESS_TOKEN>"
  },
  body: JSON.stringify({ query: mutation, variables })
});

const result = await response.json();
console.log(result);
````

  </Tab>
</Tabs>

---

### Mutation Example — Create Comment Reply Message

Use `externalCreateMessage` with `msgType: "COMMENT"` to reply to an existing comment message. The `msgId` value must be the Qpien internal `_id` of the original comment message.

<Tabs>
  <Tab title="Bash (cURL)">
```bash
curl --location 'https://api.qpien.com/api/v1' \
--header 'Content-Type: application/json' \
--header 'Authorization: YOUR_ACCESS_TOKEN' \
--data '{
  "query": "mutation ExternalCreateMessage($input: ExternalCreateMessageInput!) { externalCreateMessage(input: $input) { success data { _id conversation messageType channelType senderType content commentData { status reply repliedCPerson replyDate postUrl postImageUrl postDescription parentComment parentCommentId } createdAt } code message } }",
  "variables": {
    "input": {
      "channelId": "69f33137fce1c7e67d4cb105",
      "channelType": "INSTAGRAM",
      "content": "Tabiki alabilirsiniz",
      "convId": "6a58d36d88a1622d8c516e33",
      "msgId": "6a58d47488a1622d8c516f44",
      "msgType": "COMMENT",
      "pChannelId": "6a58d36d88a1622d8c516d4b",
      "sender": "6853d9cffd28f00199cc3225",
      "isTicket": false
    }
  }
}'

````
  </Tab>
  <Tab title="Node.js">
```js
const mutation = `
  mutation ExternalCreateMessage($input: ExternalCreateMessageInput!) {
    externalCreateMessage(input: $input) {
      success
      data {
        _id
        conversation
        messageType
        channelType
        content
        commentData {
          status
          reply
          repliedCPerson
          replyDate
        }
      }
      code
      message
    }
  }
`;

const variables = {
  input: {
    channelId: "69f33137fce1c7e67d4cb105",
    channelType: "INSTAGRAM",
    content: "Tabiki alabilirsiniz",
    convId: "6a58d36d88a1622d8c516e33",
    msgId: "6a58d47488a1622d8c516f44",
    msgType: "COMMENT",
    pChannelId: "6a58d36d88a1622d8c516d4b",
    sender: "6853d9cffd28f00199cc3225",
    isTicket: false
  }
};

const response = await fetch("https://api.qpien.com/api/v1", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "<ACCESS_TOKEN>"
  },
  body: JSON.stringify({ query: mutation, variables })
});

const result = await response.json();
console.log(result);
````

  </Tab>
</Tabs>

---

### Mutation Example — Create Private Reply Message

Use `externalCreateMessage` with `msgType: "PRIVATE_REPLY"` to send a private reply to an existing public comment message. The `msgId` value must be the Qpien internal `_id` of the original comment message.

<Tabs>
  <Tab title="Bash (cURL)">
```bash
curl --location 'https://api.qpien.com/api/v1' \
--header 'Content-Type: application/json' \
--header 'Authorization: YOUR_ACCESS_TOKEN' \
--data '{
  "query": "mutation ExternalCreateMessage($input: ExternalCreateMessageInput!) { externalCreateMessage(input: $input) { success data { _id conversation messageType channelType senderType content createdAt failedReason { code message } } code message } }",
  "variables": {
    "input": {
      "channelId": "69f33137fce1c7e67d4cb105",
      "channelType": "INSTAGRAM",
      "content": "We sent you a private reply with more details.",
      "convId": "6a58d36d88a1622d8c516e33",
      "msgId": "6a58d47488a1622d8c516f44",
      "msgType": "PRIVATE_REPLY",
      "pChannelId": "6a58d36d88a1622d8c516d4b",
      "sender": "6853d9cffd28f00199cc3225",
      "isTicket": false
    }
  }
}'

````
  </Tab>
  <Tab title="Node.js">
```js
const mutation = `
  mutation ExternalCreateMessage($input: ExternalCreateMessageInput!) {
    externalCreateMessage(input: $input) {
      success
      data {
        _id
        conversation
        messageType
        channelType
        senderType
        content
        createdAt
      }
      code
      message
    }
  }
`;

const variables = {
  input: {
    channelId: "69f33137fce1c7e67d4cb105",
    channelType: "INSTAGRAM",
    content: "We sent you a private reply with more details.",
    convId: "6a58d36d88a1622d8c516e33",
    msgId: "6a58d47488a1622d8c516f44",
    msgType: "PRIVATE_REPLY",
    pChannelId: "6a58d36d88a1622d8c516d4b",
    sender: "6853d9cffd28f00199cc3225",
    isTicket: false
  }
};

const response = await fetch("https://api.qpien.com/api/v1", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "<ACCESS_TOKEN>"
  },
  body: JSON.stringify({ query: mutation, variables })
});

const result = await response.json();
console.log(result);
````

  </Tab>
</Tabs>

