SMeetBot API

SMeet Bot API

Operations

What to watch and what to do when something goes wrong. The two situations that look alike but are not, a technical pause of the platform and an organisation switching bots off, have a section each.

Keeping secrets#

A bot has two secrets: the token its program uses to call the Bot API, and in webhook mode the webhook secret SMeet uses to sign deliveries.

  • Keep them in environment variables or a secret store. A .env file must be readable only by the service user and must never reach git.
  • Send the token only in the Authorization header. Never put it into a URL, a log, a chat, a screenshot or a support ticket. The examples log update ids, chat ids and error codes, never the token, the secret or message text.
  • SMeet shows each secret once and keeps only a hash of the token and an encrypted copy of the webhook secret. The API never returns either of them, and the token is never sent to your webhook.
  • Rotating the token: issue a new one on the protected screen of My bots; the old one stops at once, so put the new one into the program and restart it right away.
  • Rotating the webhook secret: save the webhook again on the Connection screen; every time webhook mode is set, a new secret is created and shown once. Until your program has it, deliveries signed with the new secret fail your check, your 401 pauses delivery and the updates wait (A paused endpoint). Put the new secret into the program, restart it and press Resume delivery; nothing is lost.
  • If a secret may have leaked, use the emergency reset: a new token, the long polling lease taken away and, in webhook mode, a new webhook secret, in one step.

Health checks#

  • getMe answers even while the bot is paused and during a technical pause of the platform. Call it at start: it confirms the token and shows status (active, paused_by_owner, suspended_by_admin) and delivery_mode.
  • getDeliveryInfo is the one call for monitoring (Queue diagnostics). It never returns a secret, and it also answers during a technical pause, with "maintenance": true.
  • My bots and the card of the bot in BotFather show one of four statuses:
StatusMeaning
WorkingThe program is connected and nothing is stuck.
Not connectedLong polling: no token yet, or the program has never called. Webhook: nothing delivered yet and nothing waiting.
Delivery errorLong polling: updates are waiting and the program has not called for 2 minutes. Webhook: delivery is paused until you resume it, the circuit breaker is open, or the platform switched the webhook off.
PausedThe owner paused the bot, the platform suspended it, its owner left the organisation, or the organisation switched bots off.

"Working" means only that the program is connected. It says nothing about whether its logic is right, and a webhook that refuses updates with 400, 413 or 422 gets no error status for that: watch the FAILED list and failed_update_count. In webhook mode SMeet BotFather also writes to you when delivery pauses or an update goes to FAILED (Notices to the owner).

Queue diagnostics#

JSON
{
  "ok": true,
  "result": {
    "mode": "polling",
    "config_version": "3",
    "pending_update_count": 12,
    "failed_update_count": 1,
    "oldest_pending_date": "2026-09-26T09:58:10Z",
    "confirmed_offset": "1840",
    "lease": {"consumer_id": "poller-host1", "epoch": "7", "expires_at": "2026-09-26T10:01:00Z"},
    "webhook": {"url": "", "state": "none", "pending_update_count": 12, "max_connections": 1},
    "maintenance": false,
    "retention_seconds": 604800
  }
}
FieldWhat to watch
pending_update_countUpdates waiting for confirmation. It grows when the program is down or does not confirm. At 10,000 updates or 50 MiB the queue is full, and people cannot write to the bot.
oldest_pending_dateThe oldest waiting update. When it is minutes old, the program is behind; after 7 days updates expire.
failed_update_countThe size of the FAILED list; review it in My bots.
confirmed_offsetLong polling: the server's position. Compare it with what your program stored.
leaseLong polling: who holds the lease now. Missing means nobody is polling. A consumer_id you do not expect means another copy is running.
webhookWebhook mode: state, next_attempt_date and last_error (Webhook problems).
maintenancetrue during a technical pause of the platform.

If the bot is silent#

  1. Is the program running? Its log should show Running as @<address> and no errors.
  2. Does the token work? getMe with the token. 401 INVALID_TOKEN means it was revoked or mistyped: issue a new one in My bots.
  3. Is the bot running? getMe status: paused_by_owner means /resume in BotFather; suspended_by_admin means the platform suspended the bot or its owner left the organisation: contact support.
  4. Is the mode right? getMe delivery_mode. A polling program against a bot in webhook mode gets 409 DELIVERY_MODE_CONFLICT: switch the bot to long polling, or run your webhook receiver.
  5. Is another copy receiving? getDeliveryInfo lease.consumer_id. CONSUMER_CONFLICT that does not go away means a second copy holds the lease (A stuck lease).
  6. Did the person press Start? Nothing reaches the bot before Start or after Stop. In an organisation, the person must still be a member.
  7. Is it the platform or the organisation? 503 BOTS_MAINTENANCE is a technical pause: wait. 403 SPACE_BOTS_DISABLED means the organisation switched bots off.
  8. Webhook: getWebhookInfo state and last_error (Webhook problems), and the FAILED list. paused means your endpoint gave an answer only you can fix; fix it and press Resume delivery in My bots.
  9. Replies fail: 403 BOT_STOPPED_OR_BLOCKED (the person stopped the bot), 400 INVALID_REQUEST with error.field, 429 RATE_LIMITED. Keep the request_id of a failing call.

Errors by HTTP status#

StatusCodeWhat it meansWhat to do
401INVALID_TOKENThe token is missing, mistyped or revoked, or the bot was deleted.Issue a new token in My bots. Do not retry with the old one.
403BOT_SUSPENDEDThe owner paused the bot, the platform suspended it, or its owner left the organisation./resume, or contact support. Retrying does not help.
403SPACE_BOTS_DISABLEDThe organisation switched bots off.Stop; ask the organisation's administrators.
403BOT_STOPPED_OR_BLOCKEDThe person stopped or blocked the bot, or left the space.Stop writing to that chat and delete its subscriptions.
404BOT_NOT_FOUNDThe bot was deleted while the request was on its way.Stop: the token no longer works.
409CONSUMER_CONFLICTAnother copy holds the lease, or a long poll is still waiting.Wait retry_after and ask again with the same consumer_id, epoch and offset.
409DELIVERY_MODE_CONFLICTgetUpdates while the bot is in webhook mode.Switch the mode in My bots, or receive by webhook.
409CURSOR_BEHINDoffset is below the confirmed position.Continue from confirmed_offset in the error.
409IDEMPOTENCY_CONFLICTThe key was used with other parameters.A new operation needs a new key.
409FILE_NOT_READYThe file is still being checked.Repeat after retry_after with the same key.
413PAYLOAD_TOO_LARGEThe request body or the file is larger than allowed. limit gives the largest accepted size in bytes; a 413 from the proxy in front of the API may come without it.Send less; repeating the same body does not help.
429RATE_LIMITEDToo many requests, also from the proxy for one IP address.Wait retry_after, repeat with the same key.
429QUOTA_EXCEEDEDThe daily upload volume is used up.Wait retry_after, until midnight UTC.
503TEMPORARILY_UNAVAILABLEA transient failure.Repeat after retry_after with the same key, with a growing pause.
503BOTS_MAINTENANCEA technical pause of the platform.Repeat after retry_after with the same key and the same offset (below).

The full list is in the table of error codes.

Webhook problems#

getWebhookInfo shows the state of your endpoint:

stateMeaning
activeDeliveries run.
pausedYour endpoint gave an answer only you can fix, and delivery waits for you; last_error names the cause. Fix it and press Resume delivery in My bots (A paused endpoint).
circuit_openThree updates in a row used up their error budget; SMeet waits and then probes. next_attempt_date is the next probe (Circuit breaker).
disabled_by_platformThe platform switched this bot's webhook off. The queue waits; switch to long polling or contact support.
noneThe bot is in long polling mode.

next_attempt_date also shows a wait after a failed connection or a 429. last_error.code tells what happened last:

last_error.codeWhat happenedWhat SMeet doesWhat to check
HTTP_401, HTTP_403Your endpoint refused the delivery.Pauses until you resume.The secret your program checks the signature with.
HTTP_404, HTTP_410There is nothing at the address.Pauses until you resume.The webhook address and your routing.
REDIRECT_NOT_FOLLOWEDYour endpoint answered with a redirect.Pauses until you resume.Save the final address in My bots.
TLS_CERTIFICATE_ERRORThe certificate is not valid for this address.Pauses until you resume.Expiry, the name on the certificate, the chain.
ADDRESS_FORBIDDENThe host now resolves only to private or reserved addresses.Pauses until you resume.Public DNS records of the host.
HTTP_<status> of another status, for example HTTP_405An answer a webhook does not accept.Pauses until you resume.Answer 2xx, or 400, 413, 422 for an update you refuse.
HTTP_400, HTTP_413, HTTP_422Your program refused this update.Moves it to FAILED and goes on.Your program's log; the FAILED list.
HTTP_429Your endpoint asked to slow down.Waits Retry-After.Your own rate limits.
HTTP_408, HTTP_5xx such as HTTP_503, TIMEOUT, NO_RESPONSE, IO_ERRORAn error, no answer within 10 seconds, or a connection broken after the request was sent.Retries within the update's budget.Answer faster: store, reply 200, work afterwards.
DNS_ERROR, CONNECT_ERROR, CONNECT_TIMEOUT, TLS_ERRORThe request never reached your program.Waits and retries, 5 seconds up to 5 minutes.That the host resolves, the port is open, TLS works.
DISABLED_BY_PLATFORMThe platform switched the webhook off.Nothing until the platform allows it.Contact support.

New codes may appear; treat an unknown one by the state that comes with it.

Technical pause: BOTS_MAINTENANCE#

The operators of SMeet can pause the whole bot platform, for example while a release is rolled back or during an incident. It is a pause, not a revocation: everything is kept.

During the pause:

  • data methods of the Bot API answer 503 BOTS_MAINTENANCE with retry_after (30 seconds) and the same Retry-After header; waiting long polls end with this error;
  • getMe, getMyCommands, getDeliveryInfo and getWebhookInfo still answer, and getDeliveryInfo shows "maintenance": true;
  • a webhook delivery already under way finishes and counts; no new deliveries or file checks start;
  • people's messages to bots are not sent: their app says that bots are paused for maintenance and keeps the text in the input field;
  • the queue, FAILED updates, Idempotency-Keys, offsets, the long polling lease and Start permissions are kept;
  • Stop, Block, leaving a space and deletions still take effect and still cancel what they cancel;
  • the retention clock keeps running: an update whose 7 days end during the pause expires.

What your program does:

  • wait retry_after, then repeat the same request with the same key and the same offset; never drop or reset the saved position because of this error;
  • after the pause, getUpdates with the same consumer_id, epoch and offset continues under the same lease. If the pause outlasted the lease, the call gets a new one, and the saved offset still confirms, because nobody took the lease in between. Nothing is lost;
  • a webhook receiver does nothing: deliveries resume by themselves, in order.

The client of the examples does exactly this: BOTS_MAINTENANCE is one of the codes smeet.py retries with the same body and key.

An organisation revokes its permission#

An owner or administrator of an organisation can switch Running bots off (Organisations and permissions). This is a decision about the organisation's data, not a technical pause, and it cancels:

  • every bot of the organisation gets 403 SPACE_BOTS_DISABLED, and people see that bots are turned off in this organisation;
  • every undelivered update of these bots is cancelled, FAILED updates included; they cannot be replayed and do not come back when running is switched on again;
  • chats and Start permissions stay.

What your program does: stop calling in a loop (the examples exit with code 2 and a message), and talk to the organisation's administrators. When running is switched on again, start the program: it receives only what happens from then on, and the cancelled range is reported as skipped with the reason cancelled.

Technical pauseOrganisation revokes its permission
WhoSMeet operatorsThe organisation's owners or administrators
Bot API answer503 BOTS_MAINTENANCE with retry_after403 SPACE_BOTS_DISABLED
Waiting updatesKept, delivered afterwardsCancelled for good
FAILED updatesKept, can be replayed afterwardsCancelled, cannot be replayed
Idempotency-Keys and offsetsKeptKept, but nothing is left to deliver
Your programRetries the same requestStops

Pause and suspension#

SituationBot APIWaiting updatesHow it ends
The owner paused the bot403 BOT_SUSPENDED; getMe shows paused_by_ownerKept, delivered after /resume within the 7 days/resume in BotFather
The platform suspended the bot403 BOT_SUSPENDED; getMe shows suspended_by_adminCancelled; FAILED keptThe platform lifts the suspension
The owner left the organisation or their account was disabled403 BOT_SUSPENDED; getMe shows suspended_by_adminCancelled; FAILED keptPlatform support gives the bot back to the owner

A stuck lease#

When a long polling program dies, its lease lives on for up to 60 seconds after the server's last answer to it, and a long poll it left open counts until its timeout. A restarted program that kept its epoch continues at once; one that lost it gets CONSUMER_CONFLICT until the lease expires. getDeliveryInfo shows the holder in lease.

If you are sure no other copy runs, press Reset the connection on the Connection screen of My bots. The old epoch then becomes foreign: a copy that still sends it confirms nothing with it, and the updates it had not confirmed come again. The next call gets a new lease from the confirmed position.

Getting help#

Write to support@scrile.com with the bot's address, the time, the method and the request_id of a failing call (it is in every error body and in the X-Request-Id header). Never send the token or the webhook secret.