oqimDocs
API referenceConsole

Start here

  • Introduction
  • Getting started

Guides

  • Telegram accounts
  • Recipients
  • Campaigns
  • Scheduling
  • Webhooks
  • AI writing assistant

AI Seller

  • AI Seller
  • Channels
  • Live inbox
  • Past conversations and privacy
  • Business insights

API

  • Authentication
  • API reference
  • SDK
  • Errors
  • Rate limits

Trust and operations

  • Security
  • Compliance
  • Administration
Docs / Telegram accounts

Start here

  • Introduction
  • Getting started

Guides

  • Telegram accounts
  • Recipients
  • Campaigns
  • Scheduling
  • Webhooks
  • AI writing assistant

AI Seller

  • AI Seller
  • Channels
  • Live inbox
  • Past conversations and privacy
  • Business insights

API

  • Authentication
  • API reference
  • SDK
  • Errors
  • Rate limits

Trust and operations

  • Security
  • Compliance
  • Administration

Telegram accounts

Campaigns are sent from Telegram accounts your organization owns or is authorized to operate. Oqim signs in to each account once, keeps its session encrypted, and sends from it at the pace you set.

Connect an account#

Connecting takes the accounts:manage permission (Owners and Admins) and an accepted acceptable-use policy. In the console it's Accounts → Connect account. Over the API it's up to three calls, all answering with the login state:

  1. POST /accounts with the phone number, and optionally a proxy_id. Telegram sends a login code; state.step is CODE_SENT and code_type says where it went: app, sms, call, flash_call or email.
  2. POST /accounts/login/{flow_id}/code with the code. The step becomes COMPLETED with the new account, or PASSWORD_REQUIRED if the account has two-step verification, with its password_hint when one is set.
  3. POST /accounts/login/{flow_id}/password with the two-step verification password.
Shell
# 1. Start sign-in; Telegram sends a code to the account
curl https://app.example.com/api/v1/accounts \
  -b cookies.txt -H "Origin: https://app.example.com" \
  -H "Content-Type: application/json" \
  -d '{"phone": "+998901234517"}'

# 2. Submit the code from the Telegram app
curl https://app.example.com/api/v1/accounts/login/flw_01j9r9k3m5p7r9t1v3x5z7b9d1/code \
  -b cookies.txt -H "Origin: https://app.example.com" \
  -H "Content-Type: application/json" \
  -d '{"code": "54210"}'

# 3. Only if step is PASSWORD_REQUIRED
curl https://app.example.com/api/v1/accounts/login/flw_01j9r9k3m5p7r9t1v3x5z7b9d1/password \
  -b cookies.txt -H "Origin: https://app.example.com" \
  -H "Content-Type: application/json" \
  -d '{"password": "…"}'
Response after the code, when a password is needed
{
  "state": {
    "flow_id": "flw_01j9r9k3m5p7r9t1v3x5z7b9d1",
    "step": "PASSWORD_REQUIRED",
    "phone_masked": "+998 •• ••• 45 17",
    "password_hint": "office safe",
    "expires_at": "2026-09-26T09:40:00Z"
  },
  "account": null
}

These calls use a console session (-b cookies.txt, with an Origin header for the origin check) because API keys can't connect accounts: sign-in needs someone who holds the phone. A login flow lasts 15 minutes and allows 5 attempts at the code and password.

When Telegram rejects a step, the call fails with Telegram's error as the code, in lowercase:

CodeStatusMeaning
phone_code_invalid422Wrong code. Try again with the latest code from Telegram.
phone_code_expired410The code expired. Start again for a new one.
password_hash_invalid422Wrong two-step verification password.
phone_number_invalid422Not a phone number Telegram recognises. Use international format, like +998901234567.
phone_number_unoccupied422The number isn't registered on Telegram.
phone_number_banned403Telegram banned the number; it can't be connected.
phone_number_flood429Telegram paused sign-in attempts for this number. Try later.
too_many_attempts429Five wrong attempts. Start again for a new code.
flow_expired, flow_failed410This sign-in attempt is over. Start again.
proxy_unavailable422The chosen proxy can't be reached.

What Oqim keeps

During sign-in the phone number is sealed with the app key. Afterwards Oqim keeps only a keyed hash, to recognise the number if it's connected again, and a masked form such as +998 •• ••• 45 17. The Telegram session is encrypted with a key only workers hold; the API forwards sign-in steps to a worker and never sees the session. See Security.

Account states#

status tells you whether an account can send. status_reason explains the last change and last_error holds the most recent error.

StatusConsole labelWhat it meansWhat to do
ACTIVEActiveSigned in and able to send. If cooldown_until is in the future the console shows it as cooling down after a flood wait.Nothing.
AUTH_REQUIREDSign-in neededTelegram no longer accepts the session (for example AUTH_KEY_UNREGISTERED or SESSION_REVOKED): it was ended from another device, the password changed, or it expired.Sign in again: Sign in again in the console, or POST /accounts/{id}/reauth.
PAUSEDPausedSomeone paused it, Oqim did after a flood wait longer than the platform allows, or a platform administrator disabled it. The session is kept; nothing is sent.Resume it. An account an administrator disabled can only be restored by the platform's support.
RESTRICTEDRestrictedTelegram limited or banned the account: PEER_FLOOD, USER_RESTRICTED, PHONE_NUMBER_BANNED, a deactivated or frozen account. Oqim stopped it and paused its campaigns.Appeal through @SpamBot, then resume with acknowledge_restriction.
DISCONNECTEDDisconnectedFive sends in a row couldn't reach Telegram (network errors or timeouts).Fix the network or proxy. A health check reconnects it once Telegram answers; you can also resume it or sign in again.
ERRORErrorThe account's proxy can't be reached, or a platform administrator disabled it. last_error has the detail.Fix or detach the proxy. A health check restores the account once Telegram answers.

Only ACTIVE accounts send. When you pause an account, or it cools down after a short flood wait, its campaigns keep going on their other accounts. When Oqim stops an account itself (sign-in needed, restricted, disconnected, error or a long flood wait), it also pauses the campaigns that use it and returns the messages queued for it to those campaigns, instead of handing them to another account. A campaign can't launch unless at least one of its accounts is active and none needs sign-in, is restricted, disconnected or in error.

Pacing#

Each account has two limits, which apply across every campaign it sends for:

FieldDefaultMeaning
daily_limit150Most messages the account sends per UTC day; the count resets at midnight UTC. Platform maximum: 500 by default.
min_interval_seconds8Shortest gap between two sends from the account. Platform minimum: 4 seconds by default.

Platform administrators set the defaults and bounds. New accounts start at the defaults; change them in the account's Pacing panel or with PATCH /accounts/{id}. An account sends one message at a time. At the defaults it sends its 150 messages in about 20 minutes of window time (150 × 8 seconds), then waits for the next UTC day. An account in two running campaigns shares one daily limit and one interval between them, taking the campaigns in turn.

Higher limits don't buy tolerance

Telegram judges accounts on its own terms. New accounts, and accounts messaging people who don't have them as contacts, are the most likely to be restricted. Start low and raise limits only for accounts with a history of clean delivery.

Flood waits#

When an account asks too much of Telegram, Telegram answers FLOOD_WAIT_X (or FLOOD_PREMIUM_WAIT_X), where X is the number of seconds to wait. Oqim obeys it exactly:

  • The account goes into a cooldown until cooldown_until. The message stays queued and is retried after the wait; the account's other sends wait too.
  • The campaign's other accounts keep sending at their own pace.
  • A wait longer than the platform's max_flood_wait_seconds (15 minutes by default) pauses the account and its campaigns instead, so a person can look at what's happening.

Restrictions#

PEER_FLOOD means Telegram has limited the account for writing to too many people who don't have it in their contacts. When a send comes back with PEER_FLOOD or another account-level error (USER_RESTRICTED, PHONE_NUMBER_BANNED, USER_DEACTIVATED_BAN, a frozen account), Oqim:

  1. marks the account RESTRICTED with the reason and stops dispatching from it at once;
  2. pauses every campaign the account belongs to;
  3. emits account.restricted and notifies the organization in the console.
ACTIVE→RESTRICTEDand every campaign using it→PAUSED

Oqim never retries a restricted account on its own and never works around a restriction, for example by moving its messages to another account. A restricted account stays stopped until a person acts.

Recover a restricted account

  1. Open Telegram on the restricted account and message @SpamBot. It tells you what the restriction is and how long it lasts, and lets you appeal if you think it's a mistake.
  2. Before sending again, find out why it happened: check the campaign's audience and consent records.
  3. Once Telegram has lifted the restriction, resume the account and confirm that you checked. The API requires the confirmation explicitly, from a signed-in person: an API key can't resume a restricted account.
Shell
curl https://app.example.com/api/v1/accounts/acc_01j9r3a8f2k5m7p9s1t3v5x7z9/resume \
  -b cookies.txt -H "Origin: https://app.example.com" \
  -H "Content-Type: application/json" \
  -d '{"acknowledge_restriction": true}'

Resuming the account doesn't resume its campaigns. Review each one and resume it separately.

Proxies#

You can pin an account to a proxy your organization controls, for example so its traffic leaves from your office network. Oqim supports SOCKS5, HTTP (CONNECT) and MTProto proxies, one account per proxy. It checks each proxy by dialing a Telegram data centre through it and marks it UNREACHABLE or AUTH_FAILED when that fails. Proxy passwords and MTProto secrets are encrypted at rest.

Proxies are for network placement. Oqim doesn't rotate them, and they are not a way around Telegram's limits.

A platform administrator can disable a proxy, for example one that's being misused. Its status becomes DISABLED with the reason in disabled_reason, and you're notified. Oqim stops connecting through it and checking it, and the account using it stops sending with its campaigns paused. It never falls back to a direct connection on its own: give the account another proxy or a direct connection, then resume it.

Health checks and removal#

  • Every 10 minutes the scheduler asks workers to check accounts that haven't been heard from in 30 minutes. POST /accounts/{id}/check runs a check now. An account whose session was ended elsewhere moves to AUTH_REQUIRED; a disconnected or errored account becomes active again once Telegram answers, while its campaigns stay paused for you to resume.
  • Ending the session from Telegram (Settings → Devices) always works; Oqim notices and marks the account.
  • DELETE /accounts/{id} logs the session out and deletes it and the account. It's refused while a running campaign uses the account. Delivery history stays.
PreviousGetting startedNext Recipients