Files
LangBot/en/usage/platforms/http-bot.mdx
T
Junyan Chin 00a1896bd9 docs(platforms): HTTP Bot adapter tutorial (zh/en/ja) (#98)
* docs(platforms): add HTTP Bot adapter tutorial (zh/en/ja)

Server-to-server HTTP integration guide for the new http_bot platform
adapter: signed inbound webhook, signed outbound callbacks, N->1 aggregation,
1->M multi-reply, session reset, sync convenience mode, error codes, and a
5-minute reference-client demo. Registered in docs.json nav for all three
locales; adds the platform icon.

* docs(http-bot): link the interactive playground in all locales

Add a section pointing at examples/http-bot/playground.py (browser debug
console: sign -> POST -> 202 -> live callbacks) ahead of the CLI reference
clients, in zh/en/ja.

* style(platforms): use </> code icon for http-bot logo
2026-06-22 11:15:07 +08:00

233 lines
9.6 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "HTTP Bot"
description: "Integrate any backend with LangBot over plain HTTP: push messages in via a signed webhook, receive replies on a callback URL. Server-to-server, no long-lived connection."
icon: "/images/platforms/http-bot.svg"
---
The `HTTP Bot` adapter integrates **any backend system** with a LangBot pipeline over plain HTTP. Ticketing systems, CRMs, internal tools, custom web apps — all can drive a pipeline through it:
- **Inbound**: your backend POSTs a signed message to a fixed LangBot URL;
- **Outbound**: LangBot POSTs replies to a callback URL you configure.
It needs **no long-lived connection** and fully preserves two native pipeline capabilities:
- **Message aggregation (N→1)**: a user fires several messages in a row, merged into one turn;
- **Multi-part replies (1→M)**: one turn may produce several replies (function calls, multi-message plugins, streamed chunks).
<Note>
If you want an **in-browser**, real-time chat widget, use the [Web Page Bot](/en/usage/platforms/webpage) instead. HTTP Bot is designed for backend-to-backend integration.
</Note>
## How it works
```
Your backend ──(1) POST signed message──► LangBot /bots/<bot_uuid>
(pipeline: aggregate → think → reply)
Your callback ◄─(2) POST signed reply(s)── LangBot one POST per reply part
```
- **(1) Inbound** is *fire-and-collect*: LangBot returns `202 Accepted` immediately and does **not** carry the pipeline result on that response;
- **(2) Outbound** replies arrive later as separate signed POSTs to your `callback_url`; a single turn may produce several callbacks;
- Everything is keyed by a **`session_id` you choose** (e.g. a ticket number); each `session_id` maps to one isolated session.
## Create the bot
In the LangBot WebUI, go to **Bots > Create Bot**, fill in a name, and pick `HTTP Bot` as the platform/adapter.
## Configuration
| Field | Required | Notes |
|-------|----------|-------|
| Inbound Signing Secret | yes | Your backend signs inbound requests with this; LangBot verifies every inbound request. |
| Outbound Callback URL | yes | Where LangBot POSTs replies. **Config-only** — cannot be overridden per message (SSRF protection). |
| Outbound Signing Secret | no | LangBot signs callbacks with this; defaults to the inbound secret if blank. |
| Default Session Type | no | `person` (default) or `group`. |
| Require Inbound Signature | no | Keep enabled in production. |
| Callback Timeout (seconds) | no | Per-callback HTTP timeout, default 15. |
| Callback Max Retries | no | Retries on timeout or 5xx with exponential backoff, default 3. |
After binding a **pipeline** and **enabling** the bot, the config page shows the **Inbound Webhook URL**, like `https://your-langbot/bots/<bot_uuid>`. Copy it.
## Signature scheme
Both directions use the same dependency-free HMAC-SHA256 scheme:
```
signing_string = "{timestamp}." + raw_body_bytes
signature = "sha256=" + hex(HMAC_SHA256(secret, signing_string))
```
Sent as headers:
| Header | Meaning |
|--------|---------|
| `X-LB-Timestamp` | Unix seconds. Rejected if more than **±300s** from server time. |
| `X-LB-Signature` | `sha256=<hex>` over `"{timestamp}." + body`. |
| `X-LB-Idempotency-Key` | *(optional, inbound)* dedup key; a repeat returns `409`. |
Verify outbound callbacks the same way, using the **outbound** secret (or the inbound secret if left blank).
## Send your first message (curl)
```bash
BOT="https://your-langbot/bots/<bot_uuid>"
SECRET="your-inbound-secret"
BODY='{"session_id":"ticket-10293","message":[{"type":"Plain","text":"Export keeps failing on the dashboard."}]}'
TS=$(date +%s)
SIG="sha256=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -r | cut -d' ' -f1)"
curl -sS -X POST "$BOT" \
-H "Content-Type: application/json" \
-H "X-LB-Timestamp: $TS" \
-H "X-LB-Signature: $SIG" \
-d "$BODY"
# -> 202 {"code":0,"msg":"accepted","data":{"session_id":"ticket-10293","accepted_message_id":"in_...","aggregating":true}}
```
Replies will be POSTed to your configured callback URL shortly after.
## Inbound request format
`POST /bots/{bot_uuid}`
```json
{
"session_id": "ticket-10293",
"session_type": "person",
"sender": { "id": "user-5567", "name": "Alice" },
"message": [
{ "type": "Plain", "text": "Export keeps failing on the dashboard." },
{ "type": "Image", "url": "https://example.com/screenshot.png" }
]
}
```
- `session_id` (**required**): your stable id, mapped 1:1 to a LangBot session;
- `message` (**required**): a LangBot message chain. Text uses `{"type":"Plain","text":"..."}`, images use `{"type":"Image","url":"..."}` (or `base64`); other types: `Voice`, `File`, `At`, `Quote`.
<Warning>
The callback URL is **not** accepted in the body — it is taken only from bot config. This is deliberate: even if the inbound secret leaks, an attacker cannot redirect replies to an arbitrary host.
</Warning>
### Aggregation (N → 1)
If the pipeline has **message aggregation** enabled, send several messages with the **same `session_id`** inside the aggregation window and they merge into **one** turn. No special flag — just reuse the `session_id`.
## Outbound callback format
LangBot POSTs each reply part to your callback URL:
```json
{
"session_id": "ticket-10293",
"reply_to": "in_01H...",
"sequence": 1,
"is_final": false,
"stream": false,
"message": [ { "type": "Plain", "text": "Looking into it…" } ],
"timestamp": "2026-06-22T09:00:01Z"
}
```
Your endpoint should return `2xx` quickly. Non-2xx / timeout → LangBot retries with exponential backoff.
### Multi-part replies (1 → M)
One turn may emit multiple callbacks, delivered **in `sequence` order** for a given session:
```
seq=1 is_final=false "Checking your export logs…"
seq=2 is_final=false "Found 2 failed exports."
seq=3 is_final=true "Fixed — please try again."
```
Stitch by `session_id` + `sequence`; the turn is complete when `is_final: true` arrives.
## Reset a session
Start a fresh conversation for a `session_id` (drops history):
```
POST /bots/{bot_uuid}/reset
{ "session_id": "ticket-10293", "session_type": "person" }
→ 200 { "code":0, "msg":"reset", "data": { "session_id":"ticket-10293", "removed": true } }
```
Signed exactly like an inbound message.
## Synchronous convenience mode
If you don't need streaming/multi-part and just want one reply back on the same HTTP call, POST to `/sync`. LangBot waits for the turn to finish and returns all reply parts **collapsed** into one array:
```
POST /bots/{bot_uuid}/sync
{ "session_id": "ticket-10293", "message": [ { "type":"Plain", "text":"hi" } ] }
→ 200 { "code":0, "msg":"ok",
"data": { "session_id":"ticket-10293", "reply_to":"in_...", "message": [ ... ] } }
```
<Warning>
Sync mode is **lossy** (you lose `sequence` and streaming boundaries) and blocks up to `callback_timeout × 4` seconds. Prefer the callback model for anything real-time or multi-part. Only one in-flight `/sync` per `session_id`.
</Warning>
## Error codes
```json
{ "code": 40101, "msg": "invalid signature: signature_mismatch", "data": null }
```
| HTTP | code | meaning |
|------|------|---------|
| 202 | 0 | accepted |
| 400 | 40001 | malformed body / missing `session_id` or `message` |
| 401 | 40101 | bad/expired signature |
| 409 | 40901 | duplicate idempotency key |
| 413 | 41301 | message too large (>1 MiB) |
| 500 | 50001 | internal error |
## Reference clients & 5-minute demo
The main repo's [`examples/http-bot/`](https://github.com/langbot-app/LangBot/tree/master/examples/http-bot) ships an **interactive playground** plus Python and TypeScript reference clients.
### Interactive playground (run this first)
[`playground.py`](https://github.com/langbot-app/LangBot/blob/master/examples/http-bot/playground.py) is a single-file web app: type a message in your browser → it is signed and POSTed to a **running** `http_bot` bot → replies stream back into the page, with a debug panel showing the signature, the `202` ack, and each callback's `sequence` / verification.
```bash
# From the LangBot repo root, with the backend running:
PUBLIC_IP=<your-host-ip> ./.venv/bin/python examples/http-bot/playground.py
# then open http://<your-host-ip>:8920/
```
On startup it reads the API key + the `http_bot` bot from `data/langbot.db` and points that bot's `callback_url` + secrets back at itself via the LangBot API (live reload, no restart). Requires an enabled `http_bot` bot bound to a working pipeline.
### Command-line reference clients
[`examples/http-bot/`](https://github.com/langbot-app/LangBot/tree/master/examples/http-bot) also ships Python and TypeScript reference clients (with a callback receiver):
```bash
cd examples/http-bot
pip install flask requests
# Terminal 1: callback receiver (point the bot's callback_url here; use cloudflared / ngrok locally)
python client.py serve --port 8900 --secret SHARED_SECRET
# Terminal 2: push a message
python client.py push \
--url https://your-langbot/bots/<bot_uuid> \
--secret SHARED_SECRET \
--session ticket-1 \
--text "hello"
```
Terminal 1 prints each reply part (`[part ]` / `[FINAL]`) with its sequence number — that's 1→M multi-reply with signature verification, live.
A machine-readable contract is in the main repo at [`docs/http-bot-openapi.json`](https://github.com/langbot-app/LangBot/blob/master/docs/http-bot-openapi.json).
## Security checklist
- Keep **Require Inbound Signature** on in production;
- Use **HTTPS** callback URLs, set only in config (no per-message override);
- Treat secrets like passwords; rotate via the dashboard;
- The inbound route is unauthenticated at the framework level **by design** — security comes entirely from the HMAC signature, so never disable it on a public deployment.