Integrating AI Agents into an ERP System: OpenClaw Gateway × LINE Bot × Permission Binding
Background
At TechsFree, we implemented three major features into our ERP/Shop system in a single day:
- Connecting a Pi4 AI agent to the chat API
- Running a LINE Bot via OpenClaw Gateway
- Binding LINE users to ERP accounts with role-based permissions
Each of these had its own satisfying "it works!" moment, so here's a summary of the implementation highlights and the tricky parts we hit along the way.
1. Connecting the AI Agent to the Chat API: Message Bus vs. Direct HTTP
Initially, I planned to connect the ERP/Shop chat feature to the AI agent using our internal message bus (async queue style). But I quickly realized this is fundamentally incompatible with real-time chat.
Problems with the Message Bus approach:
- Flow: send → agent processes → poll for response
- Wait times can exceed 30 seconds
- Completely unusable in a chat UI
Solution: OpenClaw-compatible HTTP Endpoint
I confirmed that the Pi4 gateway (OpenClaw) exposes an OpenAI-compatible API, and switched to direct HTTP calls.
// chatController.ts (key excerpt)
const AGENT_GATEWAYS = {
pi4: {
url: process.env.PI4_GATEWAY_URL,
token: process.env.PI4_GATEWAY_TOKEN,
model: 'openclaw:pi4',
}
};
const response = await fetch(`${gateway.url}/v1/chat/completions`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${gateway.token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: gateway.model,
messages: [{ role: 'user', content: userMessage }],
max_tokens: 2000,
}),
signal: AbortSignal.timeout(30000),
});
This gave us a clean {"reply": "Hello! I'm the Pi4 agent...", "source": "agent"} response. Simple and fast.
Lesson: Decide up front whether your AI agent communication is "async notification" or "sync API". They require completely different architectures.
2. LINE Bot × OpenClaw: Two Connection Modes
There are two major approaches to connecting a LINE Bot.
Mode 1: OpenClaw Native LINE Channel
// openclaw.json (Pi4 gateway config)
{
"channels": {
"line": {
"channelAccessToken": "xxx",
"channelSecret": "yyy",
"enabled": true
}
},
"bindings": [
{ "channel": "line", "agent": "pi4" }
]
}
nginx config:
location /pi4/webhook {
proxy_pass http://localhost:18789/line/webhook;
}
OpenClaw receives the LINE webhook and treats it as an agent session natively. LINE messages arrive at the agent just like a Slack DM. Best for general-purpose AI agents.
Mode 2: Standalone Express Server (Fridge Bot style)
// Independent implementation using Express + @line/bot-sdk
app.post('/webhook', middleware(lineConfig), (req, res) => {
const events = req.body.events;
// Custom logic here
});
Daemonized with PM2, routed via nginx. Best for purpose-built bots (inventory management, task management, etc.).
We deployed both in production today. The right choice depends on the use case.
3. LINE × ERP Permission Binding System
When a LINE Bot queries ERP data, we need to know who is on the LINE side and map them to an ERP user account.
Database Changes
ALTER TABLE users
ADD COLUMN line_user_id VARCHAR(64) UNIQUE NULL,
ADD COLUMN line_display_name VARCHAR(255) NULL;
Permission Role Design
| Role | Allowed Operations |
|---|---|
| admin | Everything (sales/procurement/inventory/finance/staff management) |
| staff (user) | Inventory/products/procurement/sales/shipping |
| Unbound | Binding guide only |
Bind API
// POST /api/line/bind
// Binds a LINE user to an ERP account via phone number
const user = await User.findOne({ where: { phone } });
if (!user) return res.status(404).json({ error: 'User not found' });
await user.update({
line_user_id: lineUserId,
line_display_name: displayName,
});
return res.json({
success: true,
permissions: ROLE_PERMISSIONS[user.role],
});
The LINE Bot checks permissions via GET /api/line/user/:line_user_id and responds accordingly.
Pain Points We Hit
1. chatCompletions endpoint disabled by default
The /v1/chat/completions endpoint on the Pi4 gateway was off by default. Adding features.chatCompletions: true to gateway.json and restarting solved it. The symptom was confusing — instead of "unknown API endpoint", the response was an SPA HTML page, which took time to diagnose.
2. LINE channelAccessToken case sensitivity
Persistent 401 errors. Turned out that one character in the token had changed case during copy-paste (E → e). Issued a new token from the LINE Developer Console. A token validation script would have saved us here.
3. Router port forwarding not configured
HTTPS access to linebot.techsfree.com was returning 502 — not due to nginx or Pi4, but because port 443 on the external IP was blocked at the router. Running a curl from outside the network first would have saved 30 minutes.
Summary
The full stack for AI-in-ERP is now running:
- Chat feature → Pi4 OpenAI-compatible API (synchronous HTTP)
- LINE notifications/interactions → OpenClaw LINE Channel (native)
- Permission management → LINE user × ERP role binding via phone number
Next step: enable the Pi4 agent to autonomously call GET /api/sales/recent so users can ask "What were this week's sales?" over LINE. Tool use implementation is next.
Tags: ERP LINE-Bot OpenClaw AI-Agent TypeScript Sequelize TechsFree implementation
Top comments (0)