Documentation Index Fetch the complete documentation index at: https://mintlify.com/danog/MadelineProto/llms.txt
Use this file to discover all available pages before exploring further.
MadelineProto provides full support for Telegram’s secret chats, which offer end-to-end encryption with perfect forward secrecy. All messages, media, and files in secret chats are encrypted on the client side.
Secret Chat Overview
Secret chats offer:
End-to-end encryption - Messages encrypted on your device
Perfect forward secrecy - New encryption keys for each session
Self-destructing messages - Automatic message deletion (TTL)
No server storage - Messages not stored on Telegram servers
Screenshot notifications - Know when screenshots are taken
Device-specific - Chats tied to specific devices
Secret Chat Class
The SecretChat class represents an active secret chat:
use danog\MadelineProto\SecretChats\ SecretChat ;
// Secret chat properties
$chat -> chatId ; // int - Secret chat ID
$chat -> creator ; // bool - Whether we created this chat
$chat -> otherID ; // int - User ID of other participant
$chat -> created ; // int - Creation timestamp
Creating Secret Chats
Request a Secret Chat
use danog\MadelineProto\EventHandler\Attributes\ Handler ;
use danog\MadelineProto\EventHandler\Message\ PrivateMessage ;
use danog\MadelineProto\EventHandler\SimpleFilter\ Incoming ;
class SecretChatBot extends SimpleEventHandler
{
#[ Handler ]
public function handlePrivateMessage ( Incoming & PrivateMessage $message ) : void
{
if ( $message -> message === 'request' ) {
// Request a secret chat
$this -> requestSecretChat ( $message -> senderId );
$message -> reply ( "Secret chat requested!" );
}
}
}
Get Secret Chat Object
public function getSecretChatInfo ( int $chatId ) : void
{
$secretChat = $this -> getSecretChat ( $chatId );
$this -> logger ( "Chat ID: { $secretChat -> chatId }" );
$this -> logger ( "Other user: { $secretChat -> otherID }" );
$this -> logger ( "Creator: " . ( $secretChat -> creator ? 'yes' : 'no' ));
$this -> logger ( "Created: " . date ( 'Y-m-d H:i:s' , $secretChat -> created ));
}
Handling Secret Messages
Receive Secret Messages
use danog\MadelineProto\EventHandler\Message\ SecretMessage ;
#[ Handler ]
public function handleSecretMessage ( Incoming & SecretMessage $message ) : void
{
$this -> logger ( "Secret message: { $message -> message }" );
$this -> logger ( "From chat: { $message -> chatId }" );
$this -> logger ( "Sender: { $message -> senderId }" );
// Reply in secret chat
$message -> reply ( "Got your secret message!" );
}
Send Secret Messages
public function sendSecretMessage ( int $secretChatId ) : void
{
// Send text message
$this -> sendMessage (
peer : $secretChatId ,
message : "This is a secret message!"
);
// Send with TTL (self-destruct timer)
$this -> sendMessage (
peer : $secretChatId ,
message : "This will self-destruct in 10 seconds" ,
ttl : 10
);
}
Send Photos
use danog\MadelineProto\ LocalFile ;
public function sendSecretPhoto ( int $secretChatId ) : void
{
$this -> sendPhoto (
peer : $secretChatId ,
file : new LocalFile ( 'photo.jpg' ),
caption : 'Secret photo' ,
ttl : 10 // Self-destruct after 10 seconds
);
}
Send Documents
public function sendSecretDocument ( int $secretChatId ) : void
{
$this -> sendDocument (
peer : $secretChatId ,
file : new LocalFile ( 'document.pdf' ),
caption : 'Encrypted document' ,
fileName : 'secret.pdf'
);
}
Send Videos
public function sendSecretVideo ( int $secretChatId ) : void
{
$this -> sendVideo (
peer : $secretChatId ,
file : new LocalFile ( 'video.mp4' ),
caption : 'Secret video' ,
ttl : 15 // Auto-delete after viewing
);
}
Send Audio
public function sendSecretAudio ( int $secretChatId ) : void
{
$this -> sendAudio (
peer : $secretChatId ,
file : new LocalFile ( 'audio.mp3' ),
caption : 'Secret audio'
);
}
Send Voice Messages
public function sendSecretVoice ( int $secretChatId ) : void
{
$this -> sendVoice (
peer : $secretChatId ,
file : new LocalFile ( 'voice.ogg' )
);
}
Send Stickers
public function sendSecretSticker ( int $secretChatId ) : void
{
$this -> sendSticker (
peer : $secretChatId ,
file : new LocalFile ( 'sticker.webp' ),
mimeType : 'image/webp'
);
}
Send GIFs
public function sendSecretGif ( int $secretChatId ) : void
{
$this -> sendGif (
peer : $secretChatId ,
file : new LocalFile ( 'animation.gif' ),
caption : 'Secret animation'
);
}
Download from Secret Messages
#[ Handler ]
public function downloadSecretMedia ( Incoming & SecretMessage $message ) : void
{
if ( $message -> media ) {
// Download and decrypt automatically
$path = $message -> media -> downloadToDir ( '/tmp' );
$this -> logger ( "Downloaded to: $path " );
$message -> reply ( "File received: $path " );
// Media is automatically decrypted
$this -> logger ( "Encrypted: { $message -> media -> encrypted }" ); // true
}
}
#[ Handler ]
public function analyzeSecretMedia ( Incoming & SecretMessage $message ) : void
{
if ( $message -> media ) {
$media = $message -> media ;
// Standard properties
$size = $media -> size ;
$fileName = $media -> fileName ;
$mimeType = $media -> mimeType ;
// Encryption properties
$isEncrypted = $media -> encrypted ; // true for secret chats
$key = $media -> key ; // Encryption key
$iv = $media -> iv ; // Initialization vector
// Secret chat specific
$thumb = $media -> thumb ; // Thumbnail (encrypted)
$thumbWidth = $media -> thumbWidth ; // Thumbnail dimensions
$thumbHeight = $media -> thumbHeight ;
// TTL
$ttl = $media -> ttl ; // Self-destruct timer
$this -> logger ( "Encrypted file: $fileName ( $size bytes)" );
}
}
Message Properties
Secret messages have all standard message properties:
#[ Handler ]
public function analyzeSecretMessage ( Incoming & SecretMessage $message ) : void
{
// Basic properties
$text = $message -> message ; // Message text
$chatId = $message -> chatId ; // Secret chat ID
$senderId = $message -> senderId ; // Sender ID
$messageId = $message -> id ; // Message ID (random_id)
$date = $message -> date ; // Timestamp
// Secret chat specific
$ttl = $message -> ttlPeriod ; // TTL in seconds
// Standard flags
$isOut = $message -> out ; // Is outgoing
$isReply = $message -> isReply (); // Is reply
// Media
$media = $message -> media ; // Encrypted media
$this -> logger ( "Secret message from { $senderId }: $text " );
}
Self-Destructing Messages (TTL)
Set TTL for Messages
public function sendWithTTL ( int $secretChatId ) : void
{
// Message deletes after 5 seconds
$this -> sendMessage (
peer : $secretChatId ,
message : "Self-destructing in 5 seconds" ,
ttl : 5
);
}
Set Chat-Wide TTL
public function setChatTTL ( SecretMessage $message ) : void
{
// All messages auto-delete after 1 day
$message -> enableTTL ( 86400 );
// Disable TTL
$message -> disableTTL ();
}
public function sendMediaWithTTL ( int $secretChatId ) : void
{
// Photo deletes immediately after viewing
$this -> sendPhoto (
peer : $secretChatId ,
file : new LocalFile ( 'photo.jpg' ),
ttl : 1 // Delete after viewing
);
// Document deletes after 30 seconds
$this -> sendDocument (
peer : $secretChatId ,
file : new LocalFile ( 'document.pdf' ),
ttl : 30
);
}
Complete Secret Chat Example
use danog\MadelineProto\EventHandler\Attributes\ Handler ;
use danog\MadelineProto\EventHandler\Message\ PrivateMessage ;
use danog\MadelineProto\EventHandler\Message\ SecretMessage ;
use danog\MadelineProto\EventHandler\SimpleFilter\ Incoming ;
use danog\MadelineProto\ LocalFile ;
use danog\MadelineProto\ Logger ;
use danog\MadelineProto\ Settings ;
use danog\MadelineProto\ SimpleEventHandler ;
class SecretChatBot extends SimpleEventHandler
{
private array $sent = [];
public const ADMIN = "username" ;
public function getReportPeers ()
{
return [ self :: ADMIN ];
}
/**
* Handle normal messages - request secret chats
*/
#[ Handler ]
public function handleNormalMessage ( Incoming & PrivateMessage $message ) : void
{
if ( $message -> message === 'request' ) {
// Request secret chat
$this -> requestSecretChat ( $message -> senderId );
$message -> reply ( "Secret chat requested!" );
}
if ( $message -> message === 'ping' ) {
$message -> reply ( 'pong' );
}
}
/**
* Handle secret chat messages
*/
#[ Handler ]
public function handleSecretMessage ( Incoming & SecretMessage $message ) : void
{
// Download media if present
if ( $message -> media ) {
$path = $message -> media -> downloadToDir ( '/tmp' );
$message -> reply ( "Downloaded to: $path " );
}
// Send welcome messages once per chat
if ( isset ( $this -> sent [ $message -> chatId ])) {
return ;
}
$chatId = $message -> chatId ;
// Send photo
$this -> sendPhoto (
peer : $chatId ,
file : new LocalFile ( 'tests/faust.jpg' ),
caption : 'Encrypted photo from MadelineProto' ,
);
// Send photo as document
$this -> sendDocumentPhoto (
peer : $chatId ,
file : new LocalFile ( 'tests/faust.jpg' ),
caption : 'Photo as document' ,
);
// Send GIF
$this -> sendGif (
peer : $chatId ,
file : new LocalFile ( 'tests/pony.mp4' ),
caption : 'Encrypted GIF' ,
);
// Send sticker
$this -> sendSticker (
peer : $chatId ,
file : new LocalFile ( 'tests/lel.webp' ),
mimeType : "image/webp"
);
// Send document
$this -> sendDocument (
peer : $chatId ,
file : new LocalFile ( 'tests/60' ),
fileName : 'encrypted-file'
);
// Send video
$this -> sendVideo (
peer : $chatId ,
file : new LocalFile ( 'tests/swing.mp4' ),
);
// Send audio
$this -> sendAudio (
peer : $chatId ,
file : new LocalFile ( 'tests/mosconi.mp3' ),
);
// Send voice
$this -> sendVoice (
peer : $chatId ,
file : new LocalFile ( 'tests/mosconi.mp3' ),
);
// Send multiple messages
for ( $i = 0 ; $i < 10 ; $i ++ ) {
$this -> logger ( "Sending message $i to $chatId " );
$this -> sendMessage (
peer : $chatId ,
message : "Message # $i "
);
}
$this -> sent [ $chatId ] = true ;
}
}
// Configure and start
$settings = new Settings ;
$settings -> getLogger () -> setLevel ( Logger :: ULTRA_VERBOSE );
SecretChatBot :: startAndLoop ( 'user.madeline' , $settings );
Secret Chat Settings
Configure secret chat behavior:
use danog\MadelineProto\ Settings ;
use danog\MadelineProto\Settings\ SecretChats ;
$settings = new Settings ;
$secretSettings = $settings -> getSecretChats ();
// Secret chats are enabled by default
Security Features
Encryption
Algorithm : MTProto 2.0 with AES-256-IGE
Key Exchange : Diffie-Hellman key exchange
Perfect Forward Secrecy : New keys for each session
Verification : Visual emoji-based key verification
Screenshot Detection
Secret chats notify when screenshots are taken (on supported platforms).
Best Practices
Secret chats only work with user accounts , not bots: if ( $this -> isSelfBot ()) {
// Cannot use secret chats as bot
return ;
}
Secret chats are device-specific and may fail if:
User is offline
User switches devices
Network issues occur
Always handle these cases gracefully.
Use appropriate TTL values:
1-2 seconds: View-once media
10-60 seconds: Temporary messages
86400 (1 day): Daily cleanup
Limitations
User accounts only - Bots cannot use secret chats
Device-specific - Chat exists only on creating device
No cloud backup - Messages not stored on servers
No forwarding - Messages cannot be forwarded
Single device - Cannot access from multiple devices
No groups - Only 1-on-1 chats
Debugging Secret Chats
Enable verbose logging:
use danog\MadelineProto\ Logger ;
use danog\MadelineProto\ Settings ;
$settings = new Settings ;
$settings -> getLogger () -> setLevel ( Logger :: ULTRA_VERBOSE );
// This will log all encryption operations