Telegram, Zalo and Lark notifications
Besides webhooks, TinoPay posts a notification for every transaction to Telegram, Zalo or Lark. Each notification app is tied to one bank account and filters by virtual account like a webhook. The routes are in the Notifications group of the API Reference; calling, authentication and error codes are in Getting started with TinoPay.
Updated: 2026-10-25. Sources: Tino's TinoPay module and the TinoPay API v1 documentation.
App types
type | Bot | endpoint (where it posts) |
|---|---|---|
telegram | the shared bot @allpay_telebot by default; send bot_token to use your own bot | shared bot: a group ID starting with - (add @allpay_telebot to the group); own bot: a group ID (-…) or a private chat (positive number) |
zalo | your own bot is required (bot_token from Zalo Bot Creator) | the Zalo chat_id of a private chat or a group (groups start with zgr-) |
lark | a Lark bot webhook URL, no bot_token | https://open.larksuite.com/open-apis/bot/v2/hook/… (or open.feishu.cn) |
bot_token is never returned: lists carry only bot_token_masked. In a UI, make the token field a password field and do not refill it when editing.
Adding an app (own bot)
- Check the bot token:
{type, bot_token}→{valid, bot_name, error}. Show the bot name; whenvalidisfalse, showerror. - Find a chat:
{type, bot_token}→{chats: [{id, title, type}], error}; the user picks one, and itsidbecomes theendpoint. - Send a test message:
{type, endpoint, bot_token}sends a real message →{connected, chat_title}. Allow saving only whenconnectedistrue; Telegram returnschat_titleto prefill the name. - Create the app:
type,name(up to 250 characters),endpoint,bot_token,bank_account_id,virtual_accounts(empty means every virtual account),status(activeby default,inactive) → 201.typecannot change after creation.
Step 2 by type:
- Telegram returns right away the groups and people that messaged the bot in the last 24 hours. A non-null
error(the bot is attached to another system's webhook): let the user enter the ID by hand. - Zalo keeps no old messages: the request waits up to about 20 seconds and only catches messages sent to the bot meanwhile (groups: mention the bot). Tell the user to message the bot now, and set the HTTP timeout to at least 30 seconds. When nothing arrives,
chatsis empty: let them retry or enter the ID by hand.
Shared Telegram bot: skip steps 1 and 2; enter the group ID, and step 3 sends no bot_token. Lark: only steps 3 and 4, with the webhook URL as endpoint.
Steps 2 and 3 are not retried on network errors (a retry would multiply the wait or send the test message twice): let the user try again.
Editing an app
- When editing, steps 1–3 send
app_idinstead ofbot_tokento use the stored token;app_idmust be an app of this merchant, otherwise 404RESOURCE_NOT_FOUND. - Update the app: send only the fields to change, never
type.
bot_token when editing | Result |
|---|---|
| not sent | keep the stored token |
| a new string | replace the token |
null | Telegram goes back to the shared bot (endpoint must be a group ID -…); Zalo cannot drop its token |
A bank_account_id that does not belong to the merchant: 404 BANK_ACCOUNT_NOT_FOUND.
Watching delivery errors
The app list carries last_error and last_error_at: the error of the latest delivery (token revoked, bot removed from the group…). Show a "connection error" warning with last_error; the next successful delivery resets it to null. A suspended merchant sends no notifications, as with webhooks.