InterChat’s Bot API allows you to build powerful, automated integrations for your users without needing to understand or manage the underlying cryptography. Because InterChat relies on a zero-knowledge End-to-End Encrypted (E2EE) architecture, the InterChat primary node acts as a secure cryptographic proxy for your bot.
When your server sends a standard plaintext JSON reply, the InterChat node automatically encrypts it using your bot's dedicated Master Key before routing it to the customer.
1. Registration & Configuration
Before writing code, you need to register your bot inside the InterChat client application:
- Open InterChat and navigate to Settings > My Bots.
- Click Create Bot and fill in your Bot's Name, Username, and Description.
- In the Webhook URL field, enter the HTTPS endpoint of your external server (e.g., https://scripts.yourdomain.com/webhook).
- Click Generate New Token. Copy this API Token; you will use it as a Bearer token to authenticate your outbound messages.
- Save your bot.
2. Receiving Messages (The Webhook)
Whenever a user sends a message to your bot, InterChat will immediately dispatch an HTTP POST request to your configured Webhook URL.
Incoming JSON Payload:
{
"userId": "019f3c79-763a-7e60-a6ed-535febd4d0bd",
"text": "Show me info for my order",
"command": "order",
"timestamp": 1732049182394
}
Note: The command field is only populated if the user's message starts with a forward slash (e.g., /order). Otherwise, it is omitted.
Your server must process this payload and return an HTTP 200 OK status immediately to acknowledge receipt.
3. Sending Replies (The API)
To send a message back to the user, make an HTTP POST request to InterChat's Bot API endpoint.
- Endpoint: https://gobackend.interchat.co.za/bot/send-message
- Headers:
Content-Type: application/jsonAuthorization: Bearer YOUR_API_TOKEN
Outgoing JSON Payload:
{
"targetUserId": "019f3c79-763a-7e60-a6ed-535febd4d0bd",
"text": "Your order is out for delivery!",
"inlineKeyboard": ""
}
Note: inlineKeyboard accepts a stringified JSON array if you wish to attach interactive buttons to your message.
4. Example Server:
The provided main.go file is a zero-dependency, standalone Go web server that implements a complete mock logistics bot. It manages conversation state in-memory and demonstrates how to parse webhooks and send authenticated replies.
To run the server:
# Set your environment variables
export INTERCHAT_API_URL="https://gobackend.interchat.co.za/bot/send-message"
export BOT_API_TOKEN="your_generated_token_here"
export PORT="8080"
# Start the bot
go run main.go
./main.go
package main
import (
"bytes"
"encoding/json"
"io"
"log"
"net/http"
"os"
"strings"
"sync"
"time"
)
// InterChatWebhookPayload represents the incoming HTTP POST data from InterChat.
type InterChatWebhookPayload struct {
UserID string `json:"userId"`
Text string `json:"text"`
Command string `json:"command,omitempty"`
Timestamp int64 `json:"timestamp"`
}
// DevMessageRequest represents the required JSON structure to send a message back.
type DevMessageRequest struct {
TargetUserID string `json:"targetUserId"`
Text string `json:"text"`
InlineKeyboard string `json:"inlineKeyboard"`
}
var (
apiToken string
interchatURL string
// Thread-safe in-memory store to track user conversation flows
stateMutex sync.RWMutex
userStates = make(map[string]string)
)
func main() {
// 1. Load Configuration
apiToken = os.Getenv("BOT_API_TOKEN")
if apiToken == "" {
log.Fatal("CRITICAL: BOT_API_TOKEN environment variable is not set.")
}
interchatURL = os.Getenv("INTERCHAT_API_URL")
if interchatURL == "" {
// Fallback to standard production URL if not explicitly set
interchatURL = "https://gobackend.interchat.co.za/bot/send-message"
}
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
// 2. Setup Routes
mux := http.NewServeMux()
mux.HandleFunc("POST /webhook", handleWebhook)
// Basic health check endpoint
mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Bot Sandbox is Online"))
})
// 3. Start Server
log.Printf("🚀 Starting InterChat Bot Sandbox on port %s", port)
log.Printf("Targeting API: %s", interchatURL)
server := &http.Server{
Addr: ":" + port,
Handler: mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
}
log.Fatal(server.ListenAndServe())
}
// handleWebhook intercepts the JSON payload from InterChat's DispatchIfBot routing.
func handleWebhook(w http.ResponseWriter, r *http.Request) {
bodyBytes, err := io.ReadAll(r.Body)
if err != nil {
log.Printf("Error reading webhook body: %v", err)
http.Error(w, "Failed to read body", http.StatusBadRequest)
return
}
defer r.Body.Close()
var payload InterChatWebhookPayload
if err := json.Unmarshal(bodyBytes, &payload); err != nil {
log.Printf("Error unmarshaling JSON payload: %v", err)
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
log.Printf("Received message from User [%s]. Command: [%s], Text: [%s]", payload.UserID, payload.Command, payload.Text)
// Acknowledge receipt immediately so InterChat doesn't hold the connection open
w.WriteHeader(http.StatusOK)
// Process the business logic asynchronously
go processConversationFlow(payload)
}
// processConversationFlow evaluates the user's input and determines the appropriate reply.
func processConversationFlow(payload InterChatWebhookPayload) {
userText := strings.ToLower(strings.TrimSpace(payload.Text))
var replyText string
stateMutex.RLock()
currentState := userStates[payload.UserID]
stateMutex.RUnlock()
// Business Logic: Order Tracking Flow
if currentState == "waiting_for_order_id" {
// Mock database lookup
replyText = "📦 Order ID " + userText + " found.\nStatus: In transit and out for delivery today!"
log.Printf("Flow complete for user %s, clearing state.", payload.UserID)
stateMutex.Lock()
delete(userStates, payload.UserID)
stateMutex.Unlock()
} else {
// Evaluate starting commands
if payload.Command == "order" {
replyText = "Sure! Please enter your 5-digit Order ID:"
log.Printf("Starting order flow for user %s.", payload.UserID)
stateMutex.Lock()
userStates[payload.UserID] = "waiting_for_order_id"
stateMutex.Unlock()
} else if payload.Command == "start" {
replyText = "Welcome to Logistics Corp! 🚚\n\nSend /order to check your tracking status."
} else {
replyText = "I didn't quite catch that. Send /order to track a shipment."
}
}
// Dispatch the reply via InterChat API
sendReply(payload.UserID, replyText)
}
// sendReply constructs the HTTP POST to InterChat using the bot's API Token.
func sendReply(targetUserID, text string) {
reqBody := DevMessageRequest{
TargetUserID: targetUserID,
Text: text,
InlineKeyboard: "", // Stringified JSON array if interactive buttons are needed
}
jsonPayload, err := json.Marshal(reqBody)
if err != nil {
log.Printf("Error marshaling outgoing message: %v", err)
return
}
req, err := http.NewRequest("POST", interchatURL, bytes.NewBuffer(jsonPayload))
if err != nil {
log.Printf("Error creating outbound HTTP request: %v", err)
return
}
// Securely append headers required by SendMessageAsBot
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+apiToken)
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
if err != nil {
log.Printf("Network error sending reply to InterChat: %v", err)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
respBytes, _ := io.ReadAll(resp.Body)
log.Printf("API Error: InterChat rejected message (Status %d): %s", resp.StatusCode, string(respBytes))
} else {
log.Printf("Successfully pushed reply to user %s", targetUserID)
}
}