DeBox Bot Go SDK Webhook Guide
Source repository:
This document covers DeBox bot Webhook integration for Go services. It is intended for backend developers who need a production-grade callback receiver, payload parser, and reply flow.
1. Webhook vs Long Polling (strictly mutually exclusive)
This guide implements Webhook mode. While a Webhook URL is configured in BotMother, Webhook is the only effective receiving path and Long Polling cannot receive messages. To return to Long Polling, clear the Webhook settings first.
For the complete mode-selection flow, see DeBox Bot Development Overview. For Long Polling implementation, see DeBox Bot Go SDK.
2. When to use Webhook
Use Webhook when:
- Your service is publicly reachable over HTTP/HTTPS.
- You need lower latency than polling.
- You want a push-based event flow.
- You need server-side handling for media messages or group join events.
3. BotMother Webhook configuration
In the BotMother Webhook settings, configure Webhook URL and Webhook Key.
Example Webhook URL:
https://your-domain.com/bot/webhook
Also ensure:
Webhook URLis stable, publicly reachable, and uses HTTPS.- Your backend validates that
X-API-KEYon each callback matches the configuredWebhook Key. - If you change
Webhook Key, update the value used by your backend validator at the same time.
4. Delivery contract
4.1 HTTP request
DeBox sends:
- Method:
POST - Content-Type:
application/json - Header:
X-API-KEY: <webhook-key>
Recommendations:
- Reject requests with missing or invalid
X-API-KEY. - Return
200 OKonly after your application has accepted the event. - Implement idempotency using your own event deduplication strategy if needed.
4.2 Top-level payload fields
Webhook callbacks use a flattened JSON payload. The most important fields are:
| Field | Type | Required | Description |
|---|---|---|---|
from_user_id | string | Yes | The event sender's DeBox user_id value. It is the same as the sender's uid and invite_code. In private chat, this is the other user. In group chat, this is the speaking user. For current join-group events, this is the joined member. |
to_user_id | string | Yes | The target bot account's DeBox user_id value; the same value as that account's uid and invite_code. |
name | string | No | Display name of from_user_id. |
pic | string | No | Avatar URL of from_user_id. |
address | string | No | Wallet address of from_user_id. |
language | string | No | User language, if available. |
group_id | string | No | DeBox group ID or chatroom ID. Empty for private chat. |
parse_mode | string | Yes | Type of the current payload, such as text, image, video, file, link, event:joinGroup. |
message | string | Yes | Normalized message body. Meaning depends on parse_mode. |
message_raw | string | Yes | Original content after DeBox parsing. Meaning depends on parse_mode. |
mention_users | array<object> | No | Mentioned users in group text messages. Present when the source message contains mentions. |
mention_users item structure:
| Field | Type | Description |
|---|---|---|
user_id | string | The mentioned user's DeBox user_id value; the same value as that user's uid and invite_code |
name | string | Display name |
pic | string | Avatar URL |
address | string | Wallet address |
4.3 parse_mode values
parse_mode | Meaning | message / message_raw |
|---|---|---|
text | Plain text or command-like text | Message text. Mentions are removed from message and preserved in message_raw. |
image | Image message | Image URL |
video | Video message | Video URL |
file | File message | File URL |
link | Shared link / dapp share | Shared link URL |
event:joinGroup | Group join event | Current joined member's user_id value |
Important behavior notes:
- For
image,video, andfile, the bot receives a URL string, not the binary file body. - For
text,messageis normalized text, whilemessage_rawpreserves the original text. - For
event:joinGroup, current payload semantics are event-oriented rather than conversational:group_idis the target group.from_user_idis the joined member exposed by the current callback implementation.messagecontains the same identifier value as the joined member'suser_id.
5. Payload examples by message type
5.1 Text message
{
"from_user_id": "u_alice",
"to_user_id": "u_bot",
"name": "Alice",
"pic": "https://cdn.example.com/alice.png",
"address": "0x1234",
"language": "en",
"group_id": "cc0onr82",
"parse_mode": "text",
"message": "hello bot",
"message_raw": "@MyBot hello bot",
"mention_users": [
{
"user_id": "u_bot",
"name": "MyBot",
"pic": "https://cdn.example.com/bot.png",
"address": ""
}
]
}
5.2 Image message
{
"from_user_id": "u_alice",
"to_user_id": "u_bot",
"name": "Alice",
"language": "en",
"group_id": "cc0onr82",
"parse_mode": "image",
"message": "https://cdn.example.com/image.png",
"message_raw": "https://cdn.example.com/image.png"
}
5.3 Video message
{
"from_user_id": "u_alice",
"to_user_id": "u_bot",
"name": "Alice",
"language": "en",
"group_id": "cc0onr82",
"parse_mode": "video",
"message": "https://cdn.example.com/video.mp4",
"message_raw": "https://cdn.example.com/video.mp4"
}
5.4 File message
{
"from_user_id": "u_alice",
"to_user_id": "u_bot",
"name": "Alice",
"language": "en",
"group_id": "cc0onr82",
"parse_mode": "file",
"message": "https://cdn.example.com/report.pdf",
"message_raw": "https://cdn.example.com/report.pdf"
}
5.5 Group join event
{
"from_user_id": "u_new_member",
"to_user_id": "u_bot",
"name": "New Member",
"pic": "https://cdn.example.com/new-member.png",
"address": "0xabcd",
"language": "en",
"group_id": "cc0onr82",
"parse_mode": "event:joinGroup",
"message": "u_new_member",
"message_raw": "u_new_member"
}
Use this event when your bot needs to:
- Send onboarding messages to new members.
- Trigger group welcome workflows.
- Record membership events in your own backend.
6. Go receiver design
Recommended server flow:
- Verify
X-API-KEY. - Parse JSON into a typed struct.
- Route logic by
parse_mode. - Infer chat context from
group_id. - Use Go SDK to send reply messages.
6.1 Suggested payload structs
type WebhookUser struct {
UserID string `json:"user_id"`
Name string `json:"name"`
Pic string `json:"pic"`
Address string `json:"address"`
}
type WebhookPayload struct {
FromUserID string `json:"from_user_id"`
ToUserID string `json:"to_user_id"`
Name string `json:"name"`
Pic string `json:"pic"`
Address string `json:"address"`
Language string `json:"language"`
GroupID string `json:"group_id"`
ParseMode string `json:"parse_mode"`
Message string `json:"message"`
MessageRaw string `json:"message_raw"`
MentionUsers []WebhookUser `json:"mention_users"`
}
6.2 Full sample (Gin + Go SDK)
package main
import (
"fmt"
"net/http"
"os"
"github.com/gin-gonic/gin"
boxbotapi "github.com/debox-pro/debox-chat-go-sdk/boxbotapi"
)
type WebhookUser struct {
UserID string `json:"user_id"`
Name string `json:"name"`
Pic string `json:"pic"`
Address string `json:"address"`
}
type WebhookPayload struct {
FromUserID string `json:"from_user_id"`
ToUserID string `json:"to_user_id"`
Name string `json:"name"`
Pic string `json:"pic"`
Address string `json:"address"`
Language string `json:"language"`
GroupID string `json:"group_id"`
ParseMode string `json:"parse_mode"`
Message string `json:"message"`
MessageRaw string `json:"message_raw"`
MentionUsers []WebhookUser `json:"mention_users"`
}
func main() {
webhookKey := os.Getenv("DEBOX_WEBHOOK_KEY")
apiKey := os.Getenv("DEBOX_BOT_API_KEY")
apiSecret := os.Getenv("DEBOX_BOT_API_SECRET")
if webhookKey == "" || apiKey == "" || apiSecret == "" {
panic("missing required env: DEBOX_WEBHOOK_KEY / DEBOX_BOT_API_KEY / DEBOX_BOT_API_SECRET")
}
bot, err := boxbotapi.NewBotAPI(apiKey, apiSecret)
if err != nil {
panic(err)
}
r := gin.Default()
r.POST("/bot/webhook", func(c *gin.Context) {
if c.GetHeader("X-API-KEY") != webhookKey {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid webhook key"})
return
}
var payload WebhookPayload
if err := c.ShouldBindJSON(&payload); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
chatType := "private"
chatID := payload.FromUserID
if payload.GroupID != "" {
chatType = "group"
chatID = payload.GroupID
}
switch payload.ParseMode {
case "text":
reply := boxbotapi.NewMessage(chatID, chatType, "Received: "+payload.Message)
reply.ParseMode = boxbotapi.ModeText
_, err = bot.Send(reply)
case "image":
reply := boxbotapi.NewMessage(chatID, chatType, "Image received: "+payload.Message)
reply.ParseMode = boxbotapi.ModeText
_, err = bot.Send(reply)
case "video":
reply := boxbotapi.NewMessage(chatID, chatType, "Video received: "+payload.Message)
reply.ParseMode = boxbotapi.ModeText
_, err = bot.Send(reply)
case "file":
reply := boxbotapi.NewMessage(chatID, chatType, "File received: "+payload.Message)
reply.ParseMode = boxbotapi.ModeText
_, err = bot.Send(reply)
case "event:joinGroup":
welcome := fmt.Sprintf("Welcome %s to the group.", payload.FromUserID)
reply := boxbotapi.NewMessage(chatID, chatType, welcome)
reply.ParseMode = boxbotapi.ModeText
_, err = bot.Send(reply)
default:
reply := boxbotapi.NewMessage(chatID, chatType, "Unsupported payload type: "+payload.ParseMode)
reply.ParseMode = boxbotapi.ModeText
_, err = bot.Send(reply)
}
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"ok": true})
})
_ = r.Run(":8080")
}
7. Sending media replies with Go SDK
The complete outbound message contract is in the OpenAPI message fields. The following example only shows how to send media with the Go SDK.
image := boxbotapi.NewMessage("cc0onr82", "group", "https://cdn.example.com/welcome.png")
image.ParseMode = boxbotapi.ModeImage
_, _ = bot.Send(image)
video := boxbotapi.NewMessage("cc0onr82", "group", "https://cdn.example.com/intro.mp4")
video.ParseMode = boxbotapi.ModeVideo
_, _ = bot.Send(video)
file := boxbotapi.NewMessage("cc0onr82", "group", "https://cdn.example.com/guide.pdf")
file.ParseMode = boxbotapi.ModeFile
_, _ = bot.Send(file)
8. Production recommendations
- Put webhook authentication and JSON parsing in middleware or a shared adapter.
- Log
parse_mode,from_user_id,to_user_id, andgroup_idfor traceability. - Do not trust media URLs indefinitely; download or process them according to your retention policy.
- For group bots, branch business logic by
group_idinstead of assuming one bot serves one group only. - Keep reply generation asynchronous if your downstream processing is slow.
9. Common pitfalls
- Webhook configured but no updates received:
- Check endpoint reachability, TLS, server logs, and
X-API-KEYverification.
- Check endpoint reachability, TLS, server logs, and
- Webhook and Long Polling both enabled:
- Only one receive mode is valid. With Webhook enabled, polling is not a valid receive path.
- Treating media payloads as binary uploads:
- Webhook delivers media URLs, not file streams.
- Ignoring
parse_mode:- Always branch on
parse_mode, not only on the existence ofmessage.
- Always branch on
- Local development without a public domain:
- Use a tunnel to expose your local endpoint temporarily.
10. Related docs
- Long Polling guide: DeBox Bot Go SDK