BOT Application Backend Development
1.1 Bot Application and Bot Application Server Interaction Flowchart
1.2 MosApp's Bot Session Sends Messages to Bot Application Server
After users send messages to Bot applications, MosApp will transparently forward the messages to the Bot application server through the webhook configured by the Bot application server.
1.2.1 Message Example
java
{
"reqId": "4E3FC140-73E6-4E18-BD98-99E19A4496B9",
"botAppId": "696290824258245",
"eventType": "MESSAGE",
"conversation": {
"conversationId": "696638485037509"
},
"message": {
"messageId": "1950519940851331072",
"text": "/start",
"timestamp": 1753875167470,
"type": -1
},
"miniApp": {
"openid": "47179fef0cff7ab186e2bcc3ac46790c"
},
"sender": {
"nickname": "mosUser"
},
"timestamp": 1753875167470
}
1.2.2 Webhook Parameter Description
Property | Type | Required | Description |
---|---|---|---|
reqId | String | Yes | Request id, unique for each request |
eventType | String | Yes | Event type: message/callbackQuery |
timestamp | Long | Yes | Event occurrence timestamp |
botAppId | String | Yes | bot application id |
sender | Sender info object | ||
--nickname | String | Yes | User nickname |
conversation | Conversation info object | ||
--conversationId | String | Yes | Conversation id |
message | User sent message content (Message object), only exists when eventType is message | ||
--messageId | String | No | Message id of user sent message |
--text | String | No | Sent text |
--timestamp | Long | No | Message send time |
callbackQuery | Inline button click event details (CallbackQuery object), only exists when eventType is callback_query | ||
--data | String | No | Callback data (usually defined by developer) |
--inlineMessageId | String | No | Inline message id |
miniApp | Mini-app info object, has value when BotApp is bound to mini-app | ||
--openid | String | No | User's openid in corresponding mini-app |
1.2.3 Java Usage Example
Request Parameters
java
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* Click inline button parameters
* @author admin001
* @date 2025/7/8 19:55
*/
@Data
@Accessors(chain = true)
public class WebhookParam implements Serializable {
private static final long serialVersionUID = 6142195922243220516L;
/**
* Request id, unique for each request
*/
private String reqId;
/**
* Event type: message/callbackQuery
*/
private String eventType;
/**
* Event occurrence timestamp
*/
private Long timestamp;
/**
* botApp id
*/
private String botAppId;
/**
* Sender information, represents the user who initiated the event.
*/
private UserInfo sender;
/**
* Conversation information
*/
private Conversation conversation;
/**
* User sent message content (Message object), only exists when eventType is message
*/
private Message message;
/**
* Inline button click event details (CallbackQuery object), only exists when eventType is callback_query.
*/
private CallbackQuery callbackQuery;
/**
* Mini-app information, has value when BotApp is bound to mini-app
*/
private MiniApp miniApp;
// Nested class: User information
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public static class UserInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* User nickname
*/
private String nickname;
}
// Nested class: Conversation information
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public static class Conversation implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Conversation id
*/
private String conversationId;
}
// Nested class: Message information
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public static class Message implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Message id of user sent message
*/
private String messageId;
/**
* Sent text
*/
private String text;
/**
* Message send time
*/
private Long timestamp;
}
// Nested class: Callback query (inline button click)
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public static class CallbackQuery implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Callback data (usually defined by developer)
*/
private String data;
/**
* Inline message id
*/
private String inlineMessageId;
}
// Nested class: Mini-app information
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public static class MiniApp implements Serializable {
private static final long serialVersionUID = 1L;
/**
* User's openid in corresponding mini-app
*/
private String openid;
}
}
Controller Class
java
@RestController
@RequestMapping("/botApp")
@Slf4j
public class BotAppController {
@PostMapping("/webhook")
public Void miniAppLogin(@RequestBody WebhookParam webhookParam) {
log.info("webhookParam: {}", webhookParam);
// other code
}
}
1.3 Bot Application Server Sends Messages to MosApp's Bot Session
1.3.1 MosApp Open API Address
https://mos-test.mos.me/open-apis/botApp/v1/sendMessage/{token}
The {token} in the address is a unique string generated after application creation, which can be viewed and copied in the Bot application details page; please keep it secure and do not leak it.
1.3.2 Message Example
java
{
"reqId": "2530D143-2C3E-4970-B4AE-8216CEA5653A",
"conversationId": "696638485037509",
"inlineMessageId": "",
"editCurrent": false,
"text": "Hello Bot app",
"inlineButtons": [
[
{
"data": "callbackData",
"text": "callback Button",
"type": "callback"
}
],
[
{
"data": "https://www.google.com/",
"text": "Google",
"type": "url"
}
],
[
{
"data": "",
"text": "Mini app",
"type": "miniApp"
}
]
]
}
1.3.3 Parameter Description
Property | Type | Required | Description |
---|---|---|---|
reqId | String | Yes | Request id, unique for each request |
conversationId | String | Yes | Conversation id |
editCurrent | Boolean | Yes | Whether to edit single message |
inlineMessageId | String | Yes | Inline message id |
text | String | Yes | Message content |
inlineButtons | List<List<InlineButton>> | inline button list object | |
--text | String | Yes | Button text |
--type | String | Yes | Button type (callback/url/miniApp) See "Inline Button Type Description" below for details |
--data | String | Yes | Button key value See "Inline Button Key Value Description" below for details |
Inline Button Type Description:
- callback (Callback type): When a user clicks, it triggers a message with eventType=callbackQuery, sent to the Bot application server via webhook; this message will not be displayed in the conversation, only passing the button's data value to the Bot application server.
- url (Jump link type): When clicked, it opens a browser to display the specified link; if it's an internal link (such as user, group, channel links), it will open within MosApp.
- miniApp (Mini-app jump type): If the Bot application is bound to a mini-app, users will directly enter the bound mini-app when clicked.
Inline Button Key Value Description:
- When the type is callback, data is a string configured by the Bot application server; when users click the button, MosApp will transparently pass this data content to the Bot application server, making it convenient for the Bot application server to distinguish which specific button the user clicked.
- When the type is url, data is an external URL link or MosApp internal link configured by the Bot application server.
- When the type is miniApp, data can configure page path information; when opening the mini-app, this path will be carried as a parameter in the URL.
1.3.4 Java Usage Example
Request Parameters
java
package com.wecloud.modules.openapi.bot.ao;
import lombok.Data;
import java.util.List;
@Data
public class BotAppMessageAo {
/**
* Request id
*/
private String reqId;
/**
* Conversation id
*/
private String conversationId;
/**
* Message content
*/
private String text;
/**
* Inline buttons 2D array
*/
private List<List<InlineButton>> inlineButtons;
/**
* Whether to edit single message
*/
private Boolean editCurrent;
/**
* Inline message id
*/
private String inlineMessageId;
@Data
public static class InlineButton {
/**
* Button text
*/
private String text;
/**
* Button type
*/
private String type;
/**
* Button key value, used by developer to distinguish which button
*/
private String data;
}
}
Process User Messages and Respond
java
@RestController
@RequestMapping("/botApp")
@Slf4j
public class BotAppController {
// bot app token
private static final String token = "bot app token";
// open api base Request
private static final String openApiBaseUrl = "https://mos.mos.me/open-apis/botApp/v1/sendMessage/";
// event type
private static final String EVENT_TYPE_CALLBACK_QUERY = "CALLBACK_QUERY";
private static final String EVENT_TYPE_MESSAGE = "MESSAGE";
@Autowired
private RestTemplate restTemplate;
@PostMapping("/webhook")
public Void miniAppLogin(@RequestBody WebhookParam webhookParam) {
log.info("webhookParam: {}", webhookParam);
BotAppMessageAo botAppMessageAo = new BotAppMessageAo();
WebhookParam.Conversation conversation = webhookParam.getConversation();
botAppMessageAo.setReqId(webhookParam.getReqId());
botAppMessageAo.setConversationId(conversation.getConversationId());
// Inline button request
if (EVENT_TYPE_CALLBACK_QUERY.equals(webhookParam.getEventType())) {
WebhookParam.CallbackQuery callbackQuery = webhookParam.getCallbackQuery();
String data = callbackQuery.getData();
botAppMessageAo.setText(data);
// Inline buttons
List<List<InlineButton>> inlineButtons = new ArrayList<>();
// First row
List<InlineButton> inlineButtonRow1 = new ArrayList<>();
InlineButton row1Column1 = new InlineButton();
row1Column1.setText("row1Column1");
row1Column1.setType("callback");
row1Column1.setData("row1Column1");
inlineButtonRow1.add(row1Column1);
InlineButton row2Column2 = new InlineButton();
row2Column2.setText("row2Column2");
row2Column2.setType("callback");
row2Column2.setData("row2Column2");
inlineButtonRow1.add(row2Column2);
inlineButtons.add(inlineButtonRow1);
// Second row
List<InlineButton> inlineButtonRow2 = new ArrayList<>();
InlineButton row2Column1 = new InlineButton();
row2Column1.setText("row2Column1");
row2Column1.setType("url");
row2Column1.setData("https://www.google.com/");
inlineButtonRow2.add(row2Column1);
inlineButtons.add(inlineButtonRow2);
// Third row
List<InlineButton> inlineButtonRow3 = new ArrayList<>();
InlineButton row3Column1 = new InlineButton();
row3Column1.setText("row3Column1");
row3Column1.setType("miniApp");
row3Column1.setData("https://www.google.com/");
inlineButtonRow3.add(row3Column1);
inlineButtons.add(inlineButtonRow3);
botAppMessageAo.setInlineButtons(inlineButtons);
botAppMessageAo.setEditCurrent(true);
botAppMessageAo.setInlineMessageId(callbackQuery.getInlineMessageId());
}
// Message request
else if (EVENT_TYPE_MESSAGE.equals(webhookParam.getEventType())) {
WebhookParam.Message message = webhookParam.getMessage();
String data = message.getText();
if ("/start".equals(data)) {
botAppMessageAo.setText(data);
// Inline buttons
List<List<InlineButton>> inlineButtons = new ArrayList<>();
// First row
List<InlineButton> inlineButtonRow1 = new ArrayList<>();
InlineButton row1Column1 = new InlineButton();
row1Column1.setText("row1Column1");
row1Column1.setType("callback");
row1Column1.setData("row1Column1");
inlineButtonRow1.add(row1Column1);
InlineButton row2Column2 = new InlineButton();
row2Column2.setText("row2Column2");
row2Column2.setType("callback");
row2Column2.setData("row2Column2");
inlineButtonRow1.add(row2Column2);
inlineButtons.add(inlineButtonRow1);
// Second row
List<InlineButton> inlineButtonRow2 = new ArrayList<>();
InlineButton row2Column1 = new InlineButton();
row2Column1.setText("row2Column1");
row2Column1.setType("url");
row2Column1.setData("https://www.google.com/");
inlineButtonRow2.add(row2Column1);
inlineButtons.add(inlineButtonRow2);
// Third row
List<InlineButton> inlineButtonRow3 = new ArrayList<>();
InlineButton row3Column1 = new InlineButton();
row3Column1.setText("row3Column1");
row3Column1.setType("miniApp");
row3Column1.setData("https://www.google.com/");
inlineButtonRow3.add(row3Column1);
inlineButtons.add(inlineButtonRow3);
botAppMessageAo.setInlineButtons(inlineButtons);
botAppMessageAo.setEditCurrent(false);
botAppMessageAo.setInlineMessageId("");
} else {
botAppMessageAo.setText(data);
botAppMessageAo.setEditCurrent(false);
botAppMessageAo.setInlineMessageId("");
}
}
try {
String url = openApiBaseUrl + token;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<BotAppMessageAo> requestEntity = new HttpEntity<>(botAppMessageAo, headers);
ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);
} catch (Exception e) {
log.error("error ", e);
}
}
}