Fast, simple, async php telegram api server: MadelineProto and Amp Http Server
Architecture Example
git clone https://github.com/xtrime-ru/TelegramApiServer.git TelegramApiServer
cd TelegramApiServer
cp .env.docker.example .env.docker
docker compose pull
Please only use old and valid accounts. All new accounts will be banned by telegram. If your account was banned read this: https://docs.madelineproto.xyz/docs/LOGIN.html#getting-permission-to-use-the-telegram-api
.env.docker
.docker compose run --rm api
command
.TelegramApiServer ready.
Number of sessions: 1.
Ctrl + C
docker compose up -d
.git pull
or git fetch && git reset --hard origin/master
rm -rf vendor/
.env.docker
or .env
with corresponding .env.example
. Update if needed.docker compose pull
docker compose down
docker compose up -d
Please be careful with settings, otherwise you can expose your telegram session and lose control. Default settings allow to access API only from localhost/127.0.0.1.
.env settings:
IP_WHITELIST
- allow specific IP's to make requests without password.PASSWORDS
- protect your api with basic auth.IP_WHITELIST
is ignored
How to make requests with basic auth:
curl --user 'username:password' "http://127.0.0.1:9503/getSelf"
curl "http://username:password@127.0.0.1:9503/getSelf"
docker-compose.yml:
port
- port forwarding rules from host to docker container.
Remove 127.0.0.1 to listen all interfaces and forward all requests to container.
Make sure to use IP_WHITELIST and/or PASSWORDS settings to protect your account.Access Telegram API with simple GET/POST requests. Regular and application/json POST supported. It's recommended to use http_build_query, when using GET requests.
Rules:
http://%address%:%port%/api[/%session%]/%class%.%method%/?%param%=%val%
Important: api available only from ip in whitelist.
By default it is: 127.0.0.1
You can add a client IP in .env file to IP_WHITELIST
(separate with a comma)
In docker version by default api available only from localhost (127.0.0.1).
To allow connections from the internet, need to change ports in docker-compose.yml to 9503:9503
and recreate the container: docker compose up -d
.
This is very insecure, because this will open TAS port to anyone from the internet.
Only protection is the IP_WHITELIST
, and there are no warranties that it will secure your accounts.
http://127.0.0.1:9503/api/contacts.getContacts
?data[peer]=@xtrime&data[message]=Hello!
. Order of parameters does't matter in this case.http://127.0.0.1:9503/api/getInfo/?id=@xtrime
or http://127.0.0.1:9503/api/getInfo/?abcd=@xtrime
works the sameExamples:
http://127.0.0.1:9503/api/getInfo/?id=@xtrime
http://127.0.0.1:9503/api/getSelf
http://127.0.0.1:9503/api/messages.forwardMessages/?data[from_peer]=@xtrime&data[to_peer]=@xtrime&data[id]=1234
http://127.0.0.1:9503/api/messages.getHistory/?data[peer]=@breakingmash&data[limit]=10
http://127.0.0.1:9503/api/getHistoryHtml/?data[peer]=@breakingmash&data[limit]=10
http://127.0.0.1:9503/api/searchGlobal/?data[q]=Hello%20World&data[limit]=10
http://127.0.0.1:9503/api/messages.sendMessage/?data[peer]=@xtrime&data[message]=Hello!
http://127.0.0.1:9503/api/copyMessages/?data[from_peer]=@xtrime&data[to_peer]=@xtrime&data[id][0]=1
Telegram is event driven platform. For example: every time your account receives a message you immediately get an update. There are multiple ways of getting updates in TelegramApiServer / MadelineProto:
curl "127.0.0.1:9503/api/getUpdates?data[limit]=3&data[offset]=0&data[timeout]=10.0" -g
curl "127.0.0.1:9503/api/setWebhook?url=http%3A%2F%2Fexample.com%2Fsome_webhook" -g
There are few options to upload and send media files:
sendMedia
supports upload from form:
curl "http://127.0.0.1:9503/api/messages.sendMedia?data[peer]=xtrime&data[message]=Hello" -g \
-F "file=@/Users/xtrime/Downloads/test.txt"
use custom uploadMediaForm
method and then pass result to messages.sendMedia
:
curl "http://127.0.0.1:9503/api/uploadMediaForm" -g -F "file=@/Users/xtrime/Downloads/test.txt"
Method supports application/x-www-form-urlencoded
and multipart/form-data
.
Send result from uploadMediaForm
to messages.sendMedia
or sendMedia
:
curl --location --request POST 'http://127.0.0.1:9503/api/sendMedia' \
--header 'Content-Type: application/json' \
--data-raw '{
"data":{
"peer": "@xtrime",
"media": {
"_": "inputMediaUploadedDocument",
"file": {
"_": "inputFile",
"id": 1164670976363200575,
"parts": 1,
"name": "test.txt",
"mime_type": "text/plain",
"md5_checksum": ""
},
"attributes": [
{
"_": "documentAttributeFilename",
"file_name": "test.txt"
}
]
}
}
}'
curl --location --request POST '127.0.0.1:9503/api/downloadToResponse' \
--header 'Content-Type: application/json' \
--data-raw '{
"media": {
"_": "messageMediaDocument",
"document": {
"_": "document",
"id": 5470079466401169993,
"access_hash": -6754208767885394084,
"file_reference": {
"_": "bytes",
"bytes": "AkKdqJkAACnyXshwzMhdzeC5RkdVZeh58sAB/UU="
},
"date": 1551713685,
"mime_type": "video/mp4",
"size": 400967,
"dc_id": 2,
"attributes": [
{
"_": "documentAttributeFilename",
"file_name": "одолдол.mp4"
}
]
}
}
}'
Also see: https://docs.madelineproto.xyz/docs/FILES.html#downloading-files
Its recommended to run every session in separate container.
To add more containers create docker-compose.override.yml
file.
Docker will automatically merge it with default docker-compose file.
Example of docker-compose.override.yml
with two additional containers/sessions (3 in total):
services:
api-2:
extends:
file: docker-compose.base.yml
service: base-api
ports:
- "127.0.0.1:9512:9503"
command:
- "-s=session-2"
api-3:
extends:
file: docker-compose.base.yml
service: base-api
ports:
- "127.0.0.1:9513:9503"
command:
- "-s=session-3"
WARNING: running multiple sessions in one instance/container is unstable. Crash/error in one session will crash all of them.
When running multiple sessions, need to define which session to use for request.
Each session stored in sessions/{$session}.madeline
. Nested folders supported.
Examples:
php server.php --session=bot --session=users/xtrime --session=users/user1
http://127.0.0.1:9503/api/bot/getSelf
http://127.0.0.1:9503/api/users/xtrime/getSelf
http://127.0.0.1:9503/api/users/user1/getSelf
sessions/bot.madeline
, sessions/users/xtrime.madeline
and sessions/users/user1.madeline
--session=*
to use all sessions/*.madeline
files (in subfolders too).--session=users/* --session=bots/*
to use all session files from sessions/bots
and sessions/users
folders. Use --env
argument to define the relative path to env file.
Example: php server.php --env=.env
, php server.php --env=sessions/.env.session
This is helpful to define unique settings for different instances of TelegramApiServer.
You can start multiple instances of TelegramApiServer with different sessions on different ports with their own settings.
Another way to manage settings - put %sessionName%.settings.json in sessions folder.
Example of session.settings.json
to add proxy for the one session:
{
"connection": {
"proxies": {
"\\danog\\MadelineProto\\Stream\\Proxy\\SocksProxy": [
{
"address": "127.0.0.1",
"port": 1234,
"username": "user",
"password": "pass"
}
],
"\\danog\\MadelineProto\\Stream\\Proxy\\HttpProxy": [
{
"address": "127.0.0.1",
"port": 1234,
"username": "user",
"password": "pass"
}
]
}
}
}
Methods to work with settings files:
http://127.0.0.1:9503/system/saveSessionSettings?session=session&settings[app_info][app_id]=xxx&settings[app_info][app_hash]=xxx
http://127.0.0.1:9503/system/unlinkSessionSettings?session=session
Provide settings as second argument when adding session: http://127.0.0.1:9503/system/addSession?session=users/xtrime&settings[app_info][app_id]=xxx&&settings[app_info][app_hash]=xxx
These settings will be saved into json file and will apply after the restart.
Examples:
http://127.0.0.1:9503/system/getSessionList
http://127.0.0.1:9503/system/addSession?session=users/xtrime
http://127.0.0.1:9503/system/removeSession?session=users/xtrime
Due to madelineProto issue its instance still might be in memory and continue working even after the remove.~~http://127.0.0.1:9503/system/unlinkSessionFile?session=users/xtrime
Don`t forget to logout and call removeSession first!~~http://127.0.0.1:9503/system/exit
Full list of system methods available in SystemApiExtensions class
WARNING: it is recomended to use interactive mode to authorize sessions! If there is no authorization in session, or session file is blank, authorization required:
User:
http://127.0.0.1:9503/api/users/xtrime/phoneLogin?phone=%2B7123...
, %2B - is urlencoded "+" signhttp://127.0.0.1:9503/api/users/xtrime/completePhoneLogin?code=123456
http://127.0.0.1:9503/api/users/xtrime/complete2falogin?password=123456
http://127.0.0.1:9503/api/users/xtrime/completeSignup?firstName=MyExampleName
Bot:
http://127.0.0.1:9503/api/bot/botLogin?token=34298141894:aflknsaflknLKNFS
Save new session to file immediately: http://127.0.0.1:9503/api/bot/serialize
Also, session can be authorized in cli/shell on server start.
Connect to ws://127.0.0.1:9503/events
to get all events in json.
This is efficient alternative for webhooks.
Each event is json object in json-rpc 2.0 format. Example:
When using multiple sessions, name of session can be added to path of websocket endpoint:
This endpoint will send events only from users/xtrime
session: ws://127.0.0.1:9503/events/users/xtrime
PHP websocket client example: websocket-events.php
php examples/websocket-events.php --url=ws://127.0.0.1:9503/events
Connect to ws://127.0.0.1:9503/log[/%level%]
to get logs in real time.
%level%
is optional parameter to filter logs.
If filter is specified, then only messages with equal or greater level will be send.
This endpoint will send only alert and emergency logs: ws://127.0.0.1:9503/log/alert
Available levels: debug, info, notice, warning, error, critical, alert, emergency.
PHP websocket client example: websocket-events.php
php examples/websocket-events.php --url=ws://127.0.0.1:9503/log
TelegramApiServer extends madelineProto with some handful methods.
Full list of custom methods and their parameters available in ApiExtensions class
getHistoryHtml
- message entities converted to htmlformatMessage
- converts entities to htmlcopyMessages
- copy message from one peer to onother. Like forwardMessages, but without the link to original.getMedia
- download media to stream/browsergetMediaPreview
- download media preview to stream/browseruploadMediaForm
- upload document from POST request.