Integration guide
Connect your system to DaloChat
Your customers already talk to your Telegram bot. An integration lets your own system take part: send them messages, tell DaloChat who they are, and answer questions about their payments, orders or bookings, for your team and for the AI. It works for any system in any industry, and DaloChat never needs custom work for yours.
Overview
An integration is a connection between one DaloChat project and one other system (a shop, a booking engine, a payments app, a CRM). It has its own key. It can do any of three things, and each is optional:
1. Send messages
Your system sends a text to a customer through the project's bot. The team sees it in the customer's topic.
2. Say who someone is
When a customer arrives from your sign-in page, DaloChat asks your system who they are and keeps their account details on their card.
3. Look up their records
Payments, orders, bookings, tickets: your team can look one up from the chat, and the AI can answer from the live result.
- Your system keeps its data and decides who may see what. DaloChat asks narrow questions and shows only what comes back.
- A person must connect their Telegram to their account on your side before anything about them is looked up. DaloChat never searches your data on its own.
- The AI may only state what your system returned, and says where it came from. If your system has no answer, it tells the customer the team will check.
- One standard format for every system. You don't build anything specific to DaloChat beyond the endpoints below, and we don't build anything specific to you.
Quick start
- In the dashboard open Settings → Integrations → Add an integration. Give it a name (customers never see it, but your team does) and tick what it may do. Add the addresses of the endpoints you build (all optional, all
https). - Copy the key (Show key any time). Keep it as a secret on your server. It starts with
dc_. - Build the endpoints you want from the sections below.
- Press Send a test on the integration card to send a real test message to a person who has started your bot.
- Put a Telegram link next to the sign-in of your product:
https://t.me/<your bot>?start=<code>(see Linking a person).
Keys and signatures
Your system calling DaloChat (sending a message): send the key in a header, either one.
X-Partner-Token: dc_...
Authorization: Bearer dc_...
DaloChat calling your system (identity and records lookups): it sends the same key, so you know the call is meant for you, and signs the request so you can be sure it comes from DaloChat:
X-Partner-Token: dc_...
X-DaloChat-Timestamp: 1760865600
X-DaloChat-Signature: 9f1c... (hex HMAC-SHA256)
The signature is the hex HMAC-SHA256, with the key as the secret, of the text <timestamp>.<telegram_user_id>.<code or q>. For an identity lookup the last part is the start code (empty when there is none); for a records lookup it is q (empty when there is none). Checking it is recommended: reject a missing or wrong signature, and reject timestamps older than five minutes.
// Node
const crypto = require("crypto");
function valid(req, key, last) { // last = req.query.code || req.query.q || ""
const ts = req.get("X-DaloChat-Timestamp"), sig = req.get("X-DaloChat-Signature");
const id = req.query.telegram_user_id || req.query.user_id;
if (!ts || !sig || Math.abs(Date.now() / 1000 - ts) > 300) return false;
const want = crypto.createHmac("sha256", key).update(`${ts}.${id}.${last}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(want), Buffer.from(sig));
}
# Python
import hmac, hashlib, time
def valid(headers, args, key, last=""):
ts, sig = headers.get("X-DaloChat-Timestamp"), headers.get("X-DaloChat-Signature")
uid = args.get("telegram_user_id") or args.get("user_id")
if not ts or not sig or abs(time.time() - int(ts)) > 300: return False
want = hmac.new(key.encode(), f"{ts}.{uid}.{last}".encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(want, sig)
A key belongs to one integration in one project. If it leaks, press New key: the old one stops working immediately. Remove deletes the integration.
Linking a person to your account
Customers write to your bot anonymously. To connect a person to their account in your system:
- In your product, create a one-time code for the signed-in account (6 to 64 characters: letters, digits,
-or_; expiring in a day or so) and show the linkhttps://t.me/<your bot>?start=<code>. - The customer taps it and presses Start. Telegram sends
/start <code>to your bot. - DaloChat calls your lookup address, with the key and signature:
GET https://yourapp.com/api/who-is?code=abc12345&telegram_user_id=123456789
Answer 200 with whatever of these you have, as JSON. account_id is required; the rest is shown to your team on the customer's card.
{ "account_id": "acc_77", "email": "[email protected]", "name": "Sokha",
"store_name": "Sokha Coffee", "plan": "pro", "status": "active" }
| Field | Who sees it |
|---|---|
account_id | Your team. Required. |
email | Your team only. Never given to the AI. |
name, store_name (the business or account title), plan, status | Your team and the AI, so it can greet them properly and know what they're on. |
The customer is welcomed, labelled with the integration's label (default “<name> customer”), and their card is kept fresh: DaloChat asks again when someone writes after a day, or when the title is missing.
Answers: 404, 410 or 400 mean “not a valid code / not someone I know” (the customer is told the link has expired). Any other error or a timeout (4 seconds) is treated as temporary: the chat carries on and DaloChat tries again on their next message. A person who writes without a code is looked up once by telegram_user_id alone; answer 404 if you don't know them.
Sending messages to a customer
POST https://dalochat.dalo-chat.workers.dev/api/partner/messages
X-Partner-Token: dc_...
Content-Type: application/json
{ "telegram_user_id": "123456789", "text": "Payment received: $12.00" }
The customer receives the text from your bot. The team sees it in the customer's topic as “From <your integration>”, and on the dashboard in a purple bubble. It does not count as a reply to a question, so a chat waiting for the team keeps waiting. It is never read or changed by the AI.
| Status | Meaning | What to do |
|---|---|---|
200 {"ok":true} | Delivered. | Mark as sent. |
400 | Bad telegram_user_id (digits only), empty text, or over 4,000 characters. | Fix the call. |
401 | Missing or wrong key. | Check the key. |
403 reason: not_allowed | inactive | Sending is switched off for this integration, or the project isn't active. | Ask the project owner. |
404 reason: not_started | That person has never pressed Start in the bot. Telegram only lets a bot write to people who did. | Use another channel (email). |
502 reason: blocked | telegram | The person blocked the bot, or Telegram refused. | Use another channel. Don't retry in a loop. |
Looking up a customer's records
A “record” is whatever your system holds about a person that they may ask about: a payment, an order, a booking, a ticket, an invoice. You choose what to call them (for example Payments, Orders or Bookings) and give one address. DaloChat uses it in two places:
- The team sees a “Orders in <your system>” box in the customer's chat with a Look up button.
- The AI uses it when a customer's message contains one of your trigger words (you set them in the integration, for example
order, delivery, tracking) or a reference likeORD-20481. It looks up once and answers only from the result, saying where it came from.
GET https://yourapp.com/api/records?user_id=123456789[&q=ORD-20481]
- No
q: the person's latest records, newest first (up to 10 are used). qpresent: the matching record (or records). Answer404when nothing of this person matches. Never return another person's record.- If you don't know the person at all, answer
404 {"error":"account_not_found"}.
Answer with a list, an object holding the list, or a single record. The list may sit under records, payments, data or items, whichever your system already uses (extra keys such as account_id or query are ignored). DaloChat keeps this standard shape for each record. Common alternative field names are understood, so you don't have to rename anything:
| Field | What it is | Also understood |
|---|---|---|
id | Your internal id. | record_id |
reference | What the customer would quote. | reference_id, ref, number, code |
title | What it is, in a few words. | name, description, item, summary; or store_name + branch_name |
amount, currency | Money, if it has any. | total, price |
status | One short word or phrase: paid, shipped, confirmed, expired… | state |
date | When it was made (ISO 8601). | created_at, created, timestamp |
done_at | When it was completed (paid, delivered). | paid_at, completed_at, fulfilled_at |
expires_at | When it lapses. | due_at |
note | A plain sentence the customer may be told, repeated as written. Put the explanation here: “Expired: not paid within 5 minutes. Create a new payment to try again.” | reason, message, details |
flag | A short “needs attention” phrase. | attention |
test | true if it isn't real (a sandbox record). | livemode: false |
Anything else you send is ignored, so there is no risk in a richer answer. Don't include email addresses, links or internal metadata. Keep note to one clear sentence in the language you want the customer to hear.
{ "records": [
{ "id": "ord_881", "reference": "ORD-20481", "title": "2 x Iced latte, 1 x Croissant",
"amount": "9.50", "currency": "USD", "status": "out for delivery",
"date": "2026-10-18T03:15:00Z",
"note": "Your driver is on the way and should arrive by 4:30 PM." } ] }
Expect one call per customer message about a record, plus one per Look up press. Please rate-limit per key on your side (a generous limit is fine: 120 a minute) and answer within five seconds.
If something goes wrong
| Your system answers | The team sees | The AI does |
|---|---|---|
404 (nothing matches) | “No record … for this person.” | Says it can't find it and the team will check. |
404 account_not_found | “Isn't paired with an account.” | Says the team will check. |
401 / 403 | “Didn't accept the key.” | Says the team will check. |
429 | “Busy, try again in a minute.” | Says the team will check. |
Timeout or 5xx | “Didn't answer.” | Says the team will check. |
The AI never guesses an amount, date, status or reason. When it has nothing, a person on the team takes over.
Privacy and safety
- Nothing is searched without a link. Records are only asked for people who connected their Telegram to an account on your side.
- Records are not stored. They are fetched when needed, shown to the team or handed to the AI for that one reply. What DaloChat keeps is the account summary from the identity lookup (name, title, plan, status, email) on the customer's card.
- The AI never sees the email address. Your team does.
- Calls are over
httpsonly, to a website name (not an IP address or an internal address), and are signed. A lookup times out after 4 to 5 seconds and never blocks a chat. - You can switch it off at any time: clear an address, switch sending off, replace the key or remove the integration.
- Every team lookup is logged in the project's audit log.
Testing
- Send a test: on the integration card, type a Telegram id (someone who has pressed Start in your bot) and press Send.
- By hand:
curl -X POST https://dalochat.dalo-chat.workers.dev/api/partner/messages \ -H "X-Partner-Token: $KEY" -H "content-type: application/json" \ -d '{"telegram_user_id":"123456789","text":"Hello from my system"}' - Linking: open your own link, press Start, and check that the customer's card in the Inbox shows your account details.
- Records: open that customer's chat and press Look up. Try an empty search, a real reference and a made-up one.
- The AI: write to the bot from the same account with a message containing one of your trigger words and check the answer matches your system.
Limits today
- Up to 5 integrations per project, each with its own key.
- Messages are plain text up to 4,000 characters. No images, files or formatting yet.
- No idempotency key and no events sent back to your system yet (for example “the customer replied” or “blocked the bot”).
- Records are read-only: DaloChat can look them up but can't change them.
- The AI part needs the DaloChat AI plan. Sending messages and the team's lookups work on any plan that has the integration.
Tell us what you need next; this guide is the contract, and it only grows in ways that work for every system.