WTelegramClient: driving a Telegram user account from C# over MTProto
Telegram Client API (MTProto) library written 100% in C# and .NET
At a glance
- What is it?
- WTelegramClient is a pure C# and .NET implementation of the Telegram Client API, so a program can sign in as a user account and call the same methods a desktop client calls. It ships NuGet packages, a saved-session mechanism and a configuration callback for non-interactive logins, but the README asks beginners in C# to look elsewhere first.
- Who is it for?
- Adopt WTelegramClient when you need a program that acts as a Telegram user account rather than a bot, because it covers the whole Client API and keeps the login flow, including 2FA, sign-up and email association, inside a single call. Do not adopt it for a bot, since the README points at WTelegramBot as the easier route there, and do not adopt it if your team is new to asynchronous C#, because the library expects you to handle `Task` based calls and pattern matching yourself.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 27 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A user account client, not a bot
WTelegramClient is a library for the Telegram Client API, the MTProto interface that a full Telegram GUI client uses, written entirely in C# and .NET. The README's description of the scope is blunt: all the Telegram Client APIs are supported, so you can do everything the user could do with a full GUI client.
The first thing to settle is whether you want this at all. The library is for controlling a user account programmatically. If what you are building is a bot, the README says outright that WTelegramBot is much easier, and it is a separate NuGet package. The user account side is for things that only a user session can do, and the trade is that a user session is a login with a phone number, a verification code and possibly a password, which is a different risk profile from a bot token.
The project is the work of a single developer, and the README says so in a sentence that tells you what to expect from the project structure: the library was developed solely by one unemployed guy, with donations and Patreon memberships welcome. The API layer badge in the README header shows 229, which corresponds to the Telegram method list the library tracks.
The licence is MIT, and the package is on NuGet. There are no GitHub releases attached to the repository, so the version history lives on NuGet, which also publishes a separate prerelease feed for the dev build.
The first program, and what it asks you for
The README calls itself a quick but important tutorial and asks that you read it all, then gives a console program as the starting point.
static async Task Main(string[] _)
{
using var client = new WTelegram.Client();
var myself = await client.LoginUserIfNeeded();
Console.WriteLine($"We are logged-in as {myself} (id {myself.id})");
}That is genuinely the whole program. The constructor takes no arguments, so on the first run the library prompts you interactively for your application `api_hash` and `api_id`, which you obtain from Telegram's API development tools page, and then tries to connect to the Telegram servers. The README notes that those credentials represent your application and one can be used for handling many user accounts.
From there the login continues. You are asked for a `phone_number` and the `verification_code` that arrives by SMS, by email or in another Telegram client the user is signed into. If Telegram does not know the number, the flow can ask you to sign up, which means accepting the Terms of Service and supplying a `first_name` and a `last_name`. If the account already exists and has two-step verification enabled, a `password` is required. In some cases Telegram will ask you to associate an email with the account for receiving login codes, and the README says you may skip that step by leaving the email empty, otherwise the address receives an `email_verification_code` first.
The point worth remembering is that all of those branches are handled inside the single call to `LoginUserIfNeeded`. You do not orchestrate the login state machine yourself, you supply answers when asked.
After login, the API methods replace the dot with a low line
Once the session is established you have access to the full range of Telegram Client APIs. There is a convention to know before you write a line, and the README states it explicitly: all those API methods require the `using TL;` namespace and write the method name with a low line in place of the dot, like `await client.Method_Name(...)`.
That convention is the price of generating the method surface from the Telegram schema. Every method in the MTProto API layer gets a strongly typed wrapper, so the compiler catches argument mistakes, but the naming is a direct transliteration of the protocol rather than an idiomatic C# surface.
The repository layout backs this up. There is a `generator/` directory at the top level next to `src/`, which is where the API layer is produced from the Telegram schema, and the badge in the README header reports the current layer as 229. There is also an `EXAMPLES.md` file and an `Examples/` directory with runnable programs, including `Program_DownloadSavedMedia.cs`, `Program_GetAllChats.cs`, `Program_ListenUpdates.cs`, `Program_ReactorError.cs` and `Program_SecretChats.cs`, plus a Heroku example and two zipped applications, an ASP.NET web app and a WinForms app.
The `Program_ListenUpdates.cs` example is the one to look at if you are building anything event driven, because updates are how a user session learns about new messages, and the `Program_ReactorError.cs` example covers the case where the library reports an error that needs a decision.
The saved session file, and why you should keep it
Run the program a second time and something has changed. Only the `api_hash` is requested, the other prompts are gone, and you are logged in automatically.
The reason is that WTelegramClient saves its state and the authentication keys it negotiated with Telegram, so you do not have to sign in every time. The README says the file is typically `bin\WTelegram.session` and that it is encrypted, and it also says the path is configurable through the `session_pathname` setting.
The same paragraph tells you when to change or delete it, and the situations are the ones that bite in practice: changing the user or the server address, or write permissions. In those cases the stored keys no longer match what the server expects, and clearing the file is what forces a fresh authentication flow. That file is therefore a credential. It carries the negotiated authentication keys, so anyone who can read it has a session that does not need your phone number, and it should be treated with the same care as the session itself rather than left in a build output directory that gets published.
The second run behaviour also has a practical consequence for deployment. A container that starts from a clean filesystem will do a full interactive login every time, so any unattended deployment needs the session file to be persisted and mounted, or it needs the non-interactive configuration described next.
A config callback for services with no console
The README's next step is to stop prompting and start answering programmatically. The mechanism is a method you write, passed to the constructor, which the library calls with the name of whatever it needs.
static string Config(string what)
{
switch (what)
{
case "api_id": return "YOUR_API_ID";
case "api_hash": return "YOUR_API_HASH";
case "phone_number": return "+12025550156";
case "verification_code": Console.Write("Code: "); return Console.ReadLine();
case "first_name": return "John";
case "last_name": return "Doe";
case "password": return "secret!";
default: return null;
}
}Two rules come with it. The values shown are the only ones that have no default, so your method has to supply them; everything else the library queries can return `null` and it will pick a default for you. And the return value carries meaning beyond the string: returning `null` for `verification_code` or `password` produces a console prompt for a console application or an error otherwise, which the README points at FAQ entry 3 for WinForms, while returning an empty string for `verification_code` asks Telegram to resend the code through another system such as SMS or a call.
Two shortcuts are offered. You can pass `Environment.GetEnvironmentVariable` as the callback and define the configuration items as environment variables, with undefined variables falling back to the `null` behaviour. And if you want the library logs in your own logging stack rather than on the console, you install a delegate in the `WTelegram.Helpers.Log` static property, whose int argument is a severity compatible with the `LogLevel` enum.
Since version 3.0.0 there is a second approach, which the README suggests some people find easier: a constructor that takes the `api_id` and `api_hash` directly, with no config method, followed by repeated calls to `client.Login(loginInfo)` that return which configuration item is needed to continue.
Where the library expects you to be experienced
The README carries a warning that is worth repeating because it changes who should attempt this project. It requires understanding advanced C# techniques such as asynchronous programming or subclass pattern matching, and if you are a beginner in C#, starting a project based on this library might not be a great idea.
That is a real constraint rather than a formality. The example program is `async Task Main`, the API is `await` throughout, and the second login approach has you loop on the result of `client.Login(...)` and switch on the string it returns. The generated method surface means you are also expected to read the method names rather than discover them from an IDE, because the naming is a protocol transliteration.
The documentation set reflects that positioning. The homepage at wiz0u.github.io/WTelegramClient/ hosts the reference, and the repository carries both `FAQ.md` and `EXAMPLES.md` at the top level, next to the `generator/` and `src/` directories and the `Examples/` folder. A `FAQ.md` in the repository is a good sign for a project whose hardest part is not the code but the many ways a login can go sideways.
On the maintenance side, the last push to the repository was on 2026-09-26, and the repository is not archived, so it is being worked on. The version badge in the README header tracks the current Telegram API layer, which is the number that actually tells you whether the library is current with the protocol. The README also notes that it describes the main branch, so the published NuGet package may be a step behind what you see in the source.
Editorial conclusion
Adopt WTelegramClient when you need a program that acts as a Telegram user account rather than a bot, because it covers the whole Client API and keeps the login flow, including 2FA, sign-up and email association, inside a single call. Do not adopt it for a bot, since the README points at WTelegramBot as the easier route there, and do not adopt it if your team is new to asynchronous C#, because the library expects you to handle `Task` based calls and pattern matching yourself. Before you build on it, register an application at Telegram's API development tools page to get an `api_id` and `api_hash`, and decide where the session file lives, because the default path is `bin\WTelegram.session` and losing it forces a fresh sign-in.
Frequently asked questions
How do I log in to Telegram with WTelegramClient in a console program?
Create the client and call `LoginUserIfNeeded`, as in `using var client = new WTelegram.Client(); var myself = await client.LoginUserIfNeeded();`. On the first run the library prompts for your `api_id` and `api_hash`, then for the phone number, the verification code and, if needed, a first and last name or a two-step verification password.
How do I stop WTelegramClient from prompting on the console?
Write a configuration method that returns the requested value and pass it to the constructor, for example `new WTelegram.Client(Config)`. The README says the items shown in the example are the only ones without defaults, and that returning `null` for other items lets the library choose a default value.
What is the WTelegram.session file and where is it stored?
It is the encrypted file the library uses to save its state and the authentication keys negotiated with Telegram, typically at `bin\WTelegram.session`. The path is configurable through the `session_pathname` setting, and the README says you may want to change or delete it when the user or server address changes, or when write permissions are a problem.
How are the Telegram API methods named in WTelegramClient?
The methods require the `using TL;` namespace and write the method name with a low line instead of a dot, so a call looks like `await client.Method_Name(...)`. The README header shows the API layer the library currently tracks as 229.
Should I use WTelegramClient for a Telegram bot?
The README says the library is for controlling a user account programmatically, and that for a bot WTelegramBot is much easier. Choose this library when you need a user session rather than a bot token.
How do I send WTelegramClient logs to my own logger?
Install a delegate in the `WTelegram.Helpers.Log` static property. Its int argument is the log severity and is compatible with the `LogLevel` enum, so the library output can be routed into an existing logging stack.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/wiz0u-wtelegramclient)Was this useful?