Telegram SDK (MT4/MT5) — Developer Guide (Send Messages + Photos + Threading)
This article is a step-by-step guide for developers who bought Telegram SDK (compiled library) and want to integrate Telegram notifications into their own MQL4/MQL5 code. It covers both versions: MT4 and MT5.
SDK update note: Telegram SDK v1.10 improves chat targeting by normalizing the chat_id you pass to the SDK. You can now safely pass numeric IDs (-100...), @channelusername, or a public link like https://t.me/channelusername (auto-converted to @channelusername). No function signatures were changed.
Products
Not a coder? Use the ready-to-run "Send To Telegram" utilities
If you do not write code and you want a solution you can just attach to a chart and configure via inputs, use these products instead (they are full-featured, highly customizable, and ready to run):
1) Who this SDK is for (important)
- Developers only: You must be able to write/compile an EA or Script and use #import.
- This is a compiled library ( .ex4 / .ex5 ). You call its functions from your own program.
- No chart UI, no inputs panel, no "drag & drop to use" behavior (that’s what the Utilities are for).
Limitations you must know
- WebRequest is required. If WebRequest is blocked or not whitelisted, sending will fail.
- Strategy Tester: WebRequest is typically restricted in the tester, so treat this as a live/demo chart feature, not a backtest feature.
- Custom Indicators: WebRequest usage is restricted in indicators on many builds — use an EA/Script/Service for Telegram sending.
2) After purchase: where the files are & how to install
Important note about #import paths (MQL4/MQL5)
In both MQL4 and MQL5, #import searches relative to the Libraries folder:
- MT4: <Data Folder>\MQL4\Libraries\
- MT5: <Data Folder>\MQL5\Libraries\
Therefore, to use this SDK as an imported library, you must place the .ex4 / .ex5 file into Libraries and then import it by filename.
Step 2.1 — Open your terminal data folder
- In MetaTrader: File → Open Data Folder
- Go to the MQL4 or MQL5 folder depending on your platform.
Step 2.2 — Download from Market (inside terminal)
- Open the Market tab:
- MT4: View → Terminal → Market → Purchased
- MT5: View → Toolbox → Market → Purchased
- Find the product and click Download/Install.
Step 2.3 — Where the Market puts the downloaded file (actual location)
After installation, this product is placed under the Scripts\Market folder inside the terminal Data Folder:
- MT4: <Data Folder>\MQL4\Scripts\Market\Telegram SDK.ex4
- MT5: <Data Folder>\MQL5\Scripts\Market\Telegram SDK.ex5
Step 2.4 — Required step: copy the SDK file into Libraries and import
Because #import resolves libraries from the Libraries folder, you must copy the compiled file from Scripts\Market to Libraries:
- MT4: copy Telegram SDK.ex4 from MQL4\Scripts\Market\ to MQL4\Libraries\
- MT5: copy Telegram SDK.ex5 from MQL5\Scripts\Market\ to MQL5\Libraries\
Then import by filename:
#import "Telegram SDK.ex4" // declarations... #import
#import "Telegram SDK.ex5" // declarations... #import
Tip: After copying, restart MetaEditor (and/or the terminal) if MetaEditor does not detect the library immediately.
Tip: MetaEditor can generate an import/include stub automatically from an exported library (Tools → Generate Include File). This helps avoid prototype mistakes.
3) Telegram prerequisites (Token + Target chat)
Step 3.1 — Create a bot token
- In Telegram, search for @BotFather
- Create a bot and copy the bot token (looks like 123456789:AA....)
Step 3.2 — Understand what you must pass as chat_id
Telegram Bot API methods require a chat_id (target). In practice, you have these common target types:
| Target | What to use as chat_id | Must-know rule |
|---|---|---|
| Private user (DM) | Numeric user chat id (usually positive) | User must press Start / send /start to your bot at least once. Bots cannot DM users first. |
| Group / Supergroup | Numeric chat id (often -100...) | Bot must be added to the group (and allowed to send messages). |
| Public channel | @channelusername (or numeric -100...) | To post to a channel, add bot as Administrator (so it can post messages). |
| Private channel/group (no @username) | Numeric chat id (-100...) | Public username targeting will not work. Use numeric id. |
Step 3.3 — New in v1.10: chat_id normalization (quality-of-life)
In Telegram SDK v1.10, the SDK automatically normalizes chat_id inside TG_Init() and send calls:
- Numeric IDs remain unchanged: "123456789" or "-1001234567890".
- @channelusername stays unchanged.
- Public links are converted: "https://t.me/channelusername" → "@channelusername".
- Important: private invite links like "t.me/+xxxx" or "t.me/joinchat/xxxx" are NOT public usernames. Use numeric chat_id for private chats.
4) MetaTrader settings (WebRequest whitelist)
You must allow WebRequest for Telegram API in terminal options, otherwise calls fail.
- Go to: Tools → Options → Expert Advisors
- Enable: Allow WebRequest for listed URL
- Add this URL:
https://api.telegram.org
5) Import stub (copy/paste)
This is the full import stub for both MT4 and MT5. If you prefer, MetaEditor can generate it automatically (Tools → Generate Include File).
MT4 Import Stub
#import "Telegram SDK.ex4"
int TG_Init(string token, string chat_id);
void TG_SetTimeoutMs(int ms);
void TG_SetRetries(int n);
void TG_SetDebug(bool on);
string TG_Version();
// Base send (manual reply id)
int TG_SendMessage(string token, string chat_id, string text,
string parse_mode, bool disable_preview, bool disable_notification,
int reply_to_message_id);
int TG_SendMessageDefault(string text, string parse_mode, bool disable_preview, bool disable_notification,
int reply_to_message_id);
// Threading (ROOT/REPLY flow)
int TG_SendMessageThread(string token, string chat_id, string thread_key,
string text, string parse_mode,
bool disable_preview, bool disable_notification,
bool saveAsRoot, bool replyToRoot);
int TG_SendMessageThreadDefault(string thread_key,
string text, string parse_mode,
bool disable_preview, bool disable_notification,
bool saveAsRoot, bool replyToRoot);
// Legacy int key (MT4 ticket)
int TG_SendMessageThreadInt(string token, string chat_id, int key,
string text, string parse_mode,
bool disable_preview, bool disable_notification,
bool saveAsRoot, bool replyToRoot);
int TG_SendMessageThreadIntDefault(int key,
string text, string parse_mode,
bool disable_preview, bool disable_notification,
bool saveAsRoot, bool replyToRoot);
// Photo base
int TG_SendPhotoFile(string token, string chat_id, string file_path,
string caption, string parse_mode,
bool disable_notification, int reply_to_message_id);
// Photo default
int TG_SendPhotoFileDefault(string file_path,
string caption, string parse_mode,
bool disable_notification, int reply_to_message_id);
// Photo threading
int TG_SendPhotoFileThread(string token, string chat_id, string thread_key,
string file_path,
string caption, string parse_mode,
bool disable_notification,
bool saveAsRoot, bool replyToRoot);
int TG_SendPhotoFileThreadDefault(string thread_key,
string file_path,
string caption, string parse_mode,
bool disable_notification,
bool saveAsRoot, bool replyToRoot);
// Photo threading legacy int key
int TG_SendPhotoFileThreadInt(string token, string chat_id, int key,
string file_path,
string caption, string parse_mode,
bool disable_notification,
bool saveAsRoot, bool replyToRoot);
int TG_SendPhotoFileThreadIntDefault(int key,
string file_path,
string caption, string parse_mode,
bool disable_notification,
bool saveAsRoot, bool replyToRoot);
// Map (optional, power-user)
bool TG_SaveRootMessageId(string key, int message_id);
int TG_GetRootMessageId(string key);
// Validate
bool TG_ValidateToken(string token);
bool TG_ValidateChatID(string token, string chat_id);
// Last error
int TG_GetLastHttpCode();
int TG_GetLastErrorCode();
string TG_GetLastErrorMessage();
string TG_GetLastResponseRaw();
#import MT5 Import Stub
#import "Telegram SDK.ex5"
int TG_Init(string token, string chat_id);
void TG_SetTimeoutMs(int ms);
void TG_SetRetries(int n);
void TG_SetDebug(bool on);
string TG_Version();
// Base send (manual reply id)
int TG_SendMessage(string token, string chat_id, string text,
string parse_mode, bool disable_preview, bool disable_notification,
int reply_to_message_id);
int TG_SendMessageDefault(string text, string parse_mode, bool disable_preview, bool disable_notification,
int reply_to_message_id);
// Threading (ROOT/REPLY flow)
int TG_SendMessageThread(string token, string chat_id, string thread_key,
string text, string parse_mode,
bool disable_preview, bool disable_notification,
bool saveAsRoot, bool replyToRoot);
int TG_SendMessageThreadDefault(string thread_key,
string text, string parse_mode,
bool disable_preview, bool disable_notification,
bool saveAsRoot, bool replyToRoot);
// Legacy MT5 ticket key (ulong)
int TG_SendMessageThreadULong(string token, string chat_id, ulong key,
string text, string parse_mode,
bool disable_preview, bool disable_notification,
bool saveAsRoot, bool replyToRoot);
int TG_SendMessageThreadULongDefault(ulong key,
string text, string parse_mode,
bool disable_preview, bool disable_notification,
bool saveAsRoot, bool replyToRoot);
// Photo base
int TG_SendPhotoFile(string token, string chat_id, string file_path,
string caption, string parse_mode,
bool disable_notification, int reply_to_message_id);
// Photo default
int TG_SendPhotoFileDefault(string file_path,
string caption, string parse_mode,
bool disable_notification, int reply_to_message_id);
// Photo threading
int TG_SendPhotoFileThread(string token, string chat_id, string thread_key,
string file_path,
string caption, string parse_mode,
bool disable_notification,
bool saveAsRoot, bool replyToRoot);
int TG_SendPhotoFileThreadDefault(string thread_key,
string file_path,
string caption, string parse_mode,
bool disable_notification,
bool saveAsRoot, bool replyToRoot);
// Photo threading legacy ulong key
int TG_SendPhotoFileThreadULong(string token, string chat_id, ulong key,
string file_path,
string caption, string parse_mode,
bool disable_notification,
bool saveAsRoot, bool replyToRoot);
int TG_SendPhotoFileThreadULongDefault(ulong key,
string file_path,
string caption, string parse_mode,
bool disable_notification,
bool saveAsRoot, bool replyToRoot);
// Map (optional, power-user)
bool TG_SaveRootMessageId(string key, int message_id);
int TG_GetRootMessageId(string key);
// Validate
bool TG_ValidateToken(string token);
bool TG_ValidateChatID(string token, string chat_id);
// Last error
int TG_GetLastHttpCode();
int TG_GetLastErrorCode();
string TG_GetLastErrorMessage();
string TG_GetLastResponseRaw();
#import 6) Quick Start (minimal working example)
This minimal EA sends 1 message on startup. Notes:
- The SDK supports |n as a newline placeholder.
- For v1.10: chat_id can be "-100..." or "@channelusername" or "https://t.me/channelusername".
MT4 Minimal EA
#property strict
#import "Telegram SDK.ex4"
int TG_Init(string token, string chat_id);
void TG_SetDebug(bool on);
string TG_Version();
int TG_SendMessageDefault(string text, string parse_mode, bool disable_preview, bool disable_notification,
int reply_to_message_id);
int TG_GetLastHttpCode();
int TG_GetLastErrorCode();
string TG_GetLastErrorMessage();
#import
int OnInit()
{
TG_SetDebug(true);
// Put your real token/chat_id here:
// Examples for chat_id:
// "-1001234567890" (group/channel numeric ID)
// "@MyChannel" (public channel username)
// "https://t.me/MyChannel" (v1.10 auto-normalized to @MyChannel)
TG_Init("123456789:AA....YOUR_TOKEN....", "-1001234567890");
Print("Telegram SDK version: ", TG_Version());
int mid = TG_SendMessageDefault("Hello from MT4|n<b>Telegram SDK</b>", "HTML", true, false, 0);
Print("mid=", mid,
" http=", TG_GetLastHttpCode(),
" err=", TG_GetLastErrorCode(),
" msg=", TG_GetLastErrorMessage());
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason) {}
void OnTick() {} MT5 Minimal EA
#property strict
#import "Telegram SDK.ex5"
int TG_Init(string token, string chat_id);
void TG_SetDebug(bool on);
string TG_Version();
int TG_SendMessageDefault(string text, string parse_mode, bool disable_preview, bool disable_notification,
int reply_to_message_id);
int TG_GetLastHttpCode();
int TG_GetLastErrorCode();
string TG_GetLastErrorMessage();
#import
int OnInit()
{
TG_SetDebug(true);
// Put your real token/chat_id here:
TG_Init("123456789:AA....YOUR_TOKEN....", "-1001234567890");
Print("Telegram SDK version: ", TG_Version());
int mid = TG_SendMessageDefault("Hello from MT5|n<b>Telegram SDK</b>", "HTML", true, false, 0);
Print("mid=", mid,
" http=", TG_GetLastHttpCode(),
" err=", TG_GetLastErrorCode(),
" msg=", TG_GetLastErrorMessage());
return(INIT_SUCCEEDED);
} 7) SDK settings (recommended before real usage)
These functions control network behavior and logging. Call them once (usually in OnInit).
- TG_SetTimeoutMs(ms): HTTP timeout in milliseconds (example: 10000).
- TG_SetRetries(n): retry count for short network outages (example: 2 or 3).
- TG_SetDebug(true/false): prints detailed logs (turn OFF in production if you want a clean Journal).
- TG_Version(): returns SDK version string (useful to confirm you’re on v1.10).
8) Text messages (Base API)
8.1 TG_Init + Default calls
- Call TG_Init(token, chat_id) once (e.g., in OnInit()).
- Then use ...Default() methods so you don’t pass token/chat_id every time.
- Return value: on success you get a message_id (positive integer). On failure you get 0.
8.2 parse_mode
- Use "HTML" if you want formatting like <b>bold</b> , <i>italic</i> , etc.
- Use "MarkdownV2" if you prefer MarkdownV2 syntax.
- Use "" (empty) for plain text.
8.3 disable_preview / disable_notification
- disable_preview=true avoids link previews (cleaner channels).
- disable_notification=true sends silently (no notification sound).
8.4 Replying to a specific message (manual reply_to_message_id)
You can reply to an existing message by passing reply_to_message_id (message_id of a message in the same chat).
// Reply to message_id=123 (same chat)
int reply_mid = TG_SendMessageDefault("This is a reply", "HTML", true, false, 123); 9) Threading (ROOT/REPLY flow)
Threading helps you keep a clean timeline per trade/order. You send one ROOT message, then later updates are sent as replies under that ROOT.
9.1 The core idea
- thread_key identifies the thread (example: ticket id, order id, custom string like "EURUSD#A1").
- saveAsRoot = store the returned message_id as the ROOT for that key.
- replyToRoot = automatically reply to the stored ROOT message_id.
Important: ROOT mapping is kept in memory. If you restart the terminal/EA, you must send ROOT again (or store/reload mapping yourself).
9.2 Minimal ROOT/REPLY demo — MT4 (int key)
#property strict
#import "Telegram SDK.ex4"
int TG_Init(string token, string chat_id);
void TG_SetDebug(bool on);
int TG_SendMessageThreadIntDefault(int key,
string text, string parse_mode,
bool disable_preview, bool disable_notification,
bool saveAsRoot, bool replyToRoot);
int TG_GetLastHttpCode();
int TG_GetLastErrorCode();
string TG_GetLastErrorMessage();
#import
int OnInit()
{
TG_SetDebug(true);
TG_Init("123456789:AA....YOUR_TOKEN....", "-1001234567890");
int ticket = 10001;
// 1) ROOT message
int root_mid = TG_SendMessageThreadIntDefault(ticket,
"Order opened (ROOT)|nTicket=" + IntegerToString(ticket),
"HTML", true, false,
true, false);
// 2) REPLY message (goes under ROOT)
int reply_mid = TG_SendMessageThreadIntDefault(ticket,
"Update (REPLY)|nSL moved...",
"HTML", true, false,
false, true);
Print("root_mid=", root_mid, " reply_mid=", reply_mid,
" http=", TG_GetLastHttpCode(),
" err=", TG_GetLastErrorCode(),
" msg=", TG_GetLastErrorMessage());
return(INIT_SUCCEEDED);
} 9.3 Minimal ROOT/REPLY demo — MT5 (ulong key)
#property strict
#import "Telegram SDK.ex5"
int TG_Init(string token, string chat_id);
void TG_SetDebug(bool on);
int TG_SendMessageThreadULongDefault(ulong key,
string text, string parse_mode,
bool disable_preview, bool disable_notification,
bool saveAsRoot, bool replyToRoot);
int TG_GetLastHttpCode();
int TG_GetLastErrorCode();
string TG_GetLastErrorMessage();
#import
int OnInit()
{
TG_SetDebug(true);
TG_Init("123456789:AA....YOUR_TOKEN....", "-1001234567890");
ulong ticket = 10001;
int root_mid = TG_SendMessageThreadULongDefault(ticket,
"MT5 ROOT|nTicket=" + (string)ticket,
"HTML", true, false,
true, false);
int reply_mid = TG_SendMessageThreadULongDefault(ticket,
"MT5 REPLY|nTP changed...",
"HTML", true, false,
false, true);
Print("root_mid=", root_mid, " reply_mid=", reply_mid,
" http=", TG_GetLastHttpCode(),
" err=", TG_GetLastErrorCode(),
" msg=", TG_GetLastErrorMessage());
return(INIT_SUCCEEDED);
} 10) Send photos (sendPhoto)
10.1 Where to put image files
The SDK reads image files using the terminal sandbox. The simplest rule:
- Put your image into:
- MT4: <Data Folder>\MQL4\Files\
- MT5: <Data Folder>\MQL5\Files\
- Then pass file_path as just the filename (example: "shot.png") or a subfolder path inside Files.
10.2 Photo examples
Send photo (default)
// caption supports parse_mode too (e.g. "HTML")
int mid = TG_SendPhotoFileDefault("shot.png",
"Chart screenshot|n<b>XAUUSD</b>",
"HTML",
false,
0); Send photo threaded (save ROOT + reply later)
// ROOT photo
int root_photo = TG_SendPhotoFileThreadDefault("trade#10001",
"shot.png",
"ROOT screenshot",
"",
false,
true, // saveAsRoot
false); // replyToRoot 11) Validation helpers (recommended during setup)
- TG_ValidateToken(token): calls Telegram getMe and returns true/false (good for quick token check).
- TG_ValidateChatID(token, chat_id): sends a silent test message and returns true/false (good for verifying chat permissions).
Note: If chat validation returns “chat not found”, it is usually wrong chat_id or the bot has no access (not in group/channel, not admin in channel, or the user never started the bot in private DM).
12) Error handling & debugging (must-read)
12.1 Always check these after a send
- TG_GetLastHttpCode() — HTTP response code (200 = OK)
- TG_GetLastErrorCode() — Telegram error code or internal code
- TG_GetLastErrorMessage() — human-readable message
- TG_GetLastResponseRaw() — raw JSON response (useful for troubleshooting)
12.2 Common failure causes
- WebRequest not allowed: You forgot to whitelist https://api.telegram.org in Options.
- Wrong token: HTTP 401/403 or “Unauthorized”.
- Wrong chat_id / no access: HTTP 400 “chat not found” or “Forbidden”.
- Rate limits (429): Too many messages too fast. Reduce sending frequency and keep retries reasonable.
- Photo send errors: file not found, empty bytes, or wrong path — place files in MQL4/Files or MQL5/Files.
12.3 Performance tip
Do not send a message on every tick. Instead, trigger only on events (new trade, close, SL/TP change, etc.), or implement a simple throttling/queue.
13) Recommended settings
- TG_SetTimeoutMs(10000) for a stable network environment.
- TG_SetRetries(2) or 3 to survive short outages, but don’t spam.
- TG_SetDebug(true) while integrating; turn OFF in production if you want a clean Journal.
14) Final notes + please support the product ❤️
If Telegram SDK saved you development time and worked well for your project, please consider leaving a 5-star review on the Market page. It helps a lot with product ranking and future updates.
- Telegram SDK (MT4): Leave a review
- Telegram SDK (MT5): Leave a review
And again — if you want a ready-to-run version for non-coders:
- MT5 Send To Telegram: Market page
- MT4 Send To Telegram: Market page


