Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Quick Start — User Account

A complete working example: connect, log in, send a message to Saved Messages, and listen for incoming messages.

use layer_client::{Client, Config, SignInError};
use layer_client::update::Update;
use std::io::{self, Write};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::connect(Config {
        session_path: "my.session".into(),
        api_id:       std::env::var("TG_API_ID")?.parse()?,
        api_hash:     std::env::var("TG_API_HASH")?,
        ..Default::default()
    }).await?;

    // ── Login (skipped if session file already has valid auth) ──
    if !client.is_authorized().await? {
        print!("Phone number (+1234567890): ");
        io::stdout().flush()?;
        let phone = read_line();

        let token = client.request_login_code(&phone).await?;

        print!("Verification code: ");
        io::stdout().flush()?;
        let code = read_line();

        match client.sign_in(&token, &code).await {
            Ok(name) => println!("✅ Signed in as {name}"),
            Err(SignInError::PasswordRequired(pw_token)) => {
                print!("2FA password: ");
                io::stdout().flush()?;
                let pw = read_line();
                client.check_password(pw_token, &pw).await?;
                println!("✅ 2FA verified");
            }
            Err(e) => return Err(e.into()),
        }
        client.save_session().await?;
    }

    // ── Send a message to yourself ──────────────────────────────
    client.send_to_self("Hello from layer! 👋").await?;
    println!("Message sent to Saved Messages");

    // ── Stream incoming updates ─────────────────────────────────
    println!("Listening for messages… (Ctrl+C to quit)");
    let mut updates = client.stream_updates();

    while let Some(update) = updates.next().await {
        match update {
            Update::NewMessage(msg) if !msg.outgoing() => {
                let text   = msg.text().unwrap_or("(no text)");
                let sender = msg.sender_id()
                    .map(|p| format!("{p:?}"))
                    .unwrap_or_else(|| "unknown".into());

                println!("📨 [{sender}] {text}");
            }
            Update::MessageEdited(msg) => {
                println!("✏️  Edited: {}", msg.text().unwrap_or(""));
            }
            _ => {}
        }
    }

    Ok(())
}

fn read_line() -> String {
    let mut s = String::new();
    io::stdin().read_line(&mut s).unwrap();
    s.trim().to_string()
}

Run it

TG_API_ID=12345 TG_API_HASH=yourHash cargo run

On first run you’ll be prompted for your phone number and the code Telegram sends. On subsequent runs, the session is reloaded from my.session and login is skipped automatically.


What each step does

StepMethodDescription
ConnectClient::connectOpens TCP, performs DH handshake, loads session
Check authis_authorizedReturns true if session has a valid logged-in user
Request coderequest_login_codeSends SMS/app code to the phone
Sign insign_inSubmits the code. Returns PasswordRequired if 2FA is on
2FAcheck_passwordPerforms SRP exchange — password never sent in plain text
Savesave_sessionWrites auth key + DC info to disk
Streamstream_updatesReturns an UpdateStream async iterator