SMeet Mini Apps
Author API reference
The reference below the first sections is generated from the machine-readable description of the API, which you can also download as openapi.json. Method names, JSON fields and error codes are the same in every language of this documentation.
Requests#
- Base URL:
https://messenger.scrile.com/mini-app-api/v1. A method is called asPOST https://messenger.scrile.com/mini-app-api/v1/<method>with a JSON body in UTF-8 andContent-Type: application/json. - A body may be at most 64 KiB; a larger one is refused with
413 PAYLOAD_TOO_LARGEandlimitin bytes before it is read. - A path that is not a method, or another HTTP method than
POST, answers400 INVALID_REQUEST. - The API answers no CORS requests and sets no cookies: it is for servers only.
- An answer that SMeet's proxy gives itself, a
429or a413, has the same envelope with an emptyrequest_id.
Authentication#
Every call carries the key of one environment of the Mini App:
Authorization: Bearer smac1_<key id>_<secret>The key decides the Mini App and the environment. A login code of another app or environment is refused (APP_MISMATCH, ENVIRONMENT_MISMATCH); a session of another app or environment is reported as not_found. Keys are issued and revoked on the Mini App's screen in My bots (Keys).
Limits#
| What | Limit |
|---|---|
| Calls with one key | 50 a second |
| Calls of one Mini App, all keys | 200 a second |
| All Mini Apps together | 1000 a second |
| Body | 64 KiB |
Over a limit the answer is 429 RATE_LIMITED with retry_after; repeat the same request with the same key after it.
Generated from the contract SMeet Mini Apps author API 1.0.0 (OpenAPI 3.1.0). Base URL: https://messenger.scrile.com/mini-app-api/v1. Machine-readable: openapi.json.
The API the server of a Mini App calls to turn a login code into a session and to check and revoke sessions.
Methods#
Every method is called as POST https://messenger.scrile.com/mini-app-api/v1/<method> with a JSON body; there are no GET methods. Authentication: The key of one environment of the Mini App, shown once in "My bots" when it is issued. Keep it on the server only, never in the page, a link or a log. Each environment has up to two active keys, so a key can be replaced without a pause. A revoked or unknown key fails with 401 INVALID_CREDENTIALS.
| Method | HTTP | Idempotency-Key | Description |
|---|---|---|---|
| SessionsSigning a person in and checking that they may still use the Mini App. | |||
exchangeLaunchCode | POST | required | Exchange a login code and its PKCE verifier for a Mini App session. |
checkSession | POST | optional | Check a Mini App session now, before a protected operation. |
revokeSession | POST | optional | End a Mini App session, for example when the person signs out of your app. |
exchangeLaunchCode#
POST /exchangeLaunchCodeSessions
Exchange a login code and its PKCE verifier for a Mini App session.
The code comes from authorize() in the page and lives 60 seconds; the verifier is the one the SDK made for it. Exchange it once: the same Idempotency-Key with the same body within 60 seconds of the exchange repeats the answer (a lost response), anything else with a used code fails with CODE_ALREADY_USED. A wrong verifier revokes the code. When the person may not use the Mini App any more, the answer is ACCESS_DENIED with the reason. The session lives 15 minutes at most; the page renews it with a new authorize() and a new exchange.
Headers#
| Header | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | IdempotencyKey | Yes | One key per sign-in, for example bound to your login attempt (login:<attempt id>). Send the same key with the same body when you repeat the request after a timeout, 429 or 503. |
Request body (JSON)#
| Field | Type | Required |
|---|---|---|
code | LoginCode | Yes |
code_verifier | CodeVerifier | Yes |
Result#
The result field holds Session. The session and who signed in.
On failure the answer is an error object with a code from the table of error codes.
checkSession#
POST /checkSessionSessions
Check a Mini App session now, before a protected operation.
Call it without a cache before every operation that acts for the person: creating or changing their data, uploading or downloading a file, reading what belongs to them. Every state of the session is an answer 200: active: true with the current details, or active: false with the reason. An unknown token, a wrong secret and a session of another application or environment all give reason: not_found. During a pause of the platform the answer is active: false, reason: maintenance.
Headers#
| Header | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | IdempotencyKey | No | Accepted and not needed; the method changes nothing or is idempotent by itself. |
Request body (JSON)#
| Field | Type | Required |
|---|---|---|
session_token | SessionToken | Yes |
Result#
The result field holds SessionCheck. The state of the session.
On failure the answer is an error object with a code from the table of error codes.
revokeSession#
POST /revokeSessionSessions
End a Mini App session, for example when the person signs out of your app.
Revokes only a session of the key's application and environment. The answer is the same for an unknown token, a wrong secret, a session of another application or environment and a session that is already revoked, and nothing changes then. Works during a pause of the platform too.
Headers#
| Header | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | IdempotencyKey | No | Accepted and not needed; the method changes nothing or is idempotent by itself. |
Request body (JSON)#
| Field | Type | Required |
|---|---|---|
session_token | SessionToken | Yes |
Result#
Always the same answer. The result field holds an object with these fields.
| Field | Type | Required | Description |
|---|---|---|---|
revoked | boolean | Yes | Always true. |
On failure the answer is an error object with a code from the table of error codes.
Types#
Simple types#
Strings with a fixed format. Fields refer to them by name.
| Name | Type | Description |
|---|---|---|
Id | string | A decimal identifier passed as a string. Pattern: ^[0-9]{1,20}$. Example: 1000. |
LoginCode | string | A one-time login code from authorize(); it lives 60 seconds. Pattern: ^smlc_[A-Za-z0-9_-]{43}$. |
CodeVerifier | string | The PKCE verifier (RFC 7636) that the SDK made for the code; SMeet checks it with S256. Pattern: ^[A-Za-z0-9._~-]{43,128}$. |
SessionToken | string | A Mini App session. Your server keeps it; it never reaches the page. Pattern: ^smas1_([0-9a-f]{16})_([A-Za-z0-9_-]{43})$. |
AuthorKey | string | The key of one environment of the Mini App, sent as Authorization: Bearer. Pattern: ^smac1_([0-9a-f]{16})_([A-Za-z0-9_-]{43})$. |
IdempotencyKey | string | 1 to 128 characters. Pattern: ^[A-Za-z0-9._:-]{1,128}$. |
Timestamp | string (date-time) | RFC 3339, UTC. Example: 2026-10-10T12:15:00Z. |
Revision | string | The revision of the person's conversation with the bot. Pass it to the Bot API as expected_access_revision; compare it only for equality. 1-64 characters. Example: 1088. |
Environment | string | One of: production, test. |
SpaceKind | string | SMeet's public space or an organisation. One of: public, organization. |
LanguageCode | string | The language of the person's SMeet interface. One of: en, ru. |
Scope | string | What the person agreed to share beyond the id and the language; profile is the display name. One of: profile. |
SessionReason | string | Why a session is not active. Consumers must accept unknown values. One of: not_found, maintenance, expired, revoked, launch_closed, parent_session_revoked, operator_session, account_disabled, chat_stopped, membership_revoked, app_unavailable, space_disabled, bot_unavailable, test_access_removed, user_revoked, config_changed. |
AccessDeniedReason | string | Why an exchange is refused with ACCESS_DENIED. Consumers must accept unknown values. One of: launch_closed, parent_session_revoked, operator_session, account_disabled, chat_stopped, membership_revoked, app_unavailable, space_disabled, bot_unavailable, test_access_removed, user_revoked, config_changed. |
App#
The Mini App the key belongs to.
| Field | Type | Required | Description |
|---|---|---|---|
id | Id | Yes | |
bot_id | string or null | Yes | The bot's id, the same as id of getMe in the Bot API. |
title | string or null | Yes | The title of the configuration the person opened. |
Space#
Where the person opened the Mini App.
User#
The person who signed in.
| Field | Type | Required | Description |
|---|---|---|---|
id | Id | Yes | The same id the bot sees as from.id in the Bot API. |
display_name | string | No | Present only when the Mini App asks for profile and the person agreed. |
language_code | LanguageCode | Yes |
Chat#
The person's private chat with the bot.
| Field | Type | Required | Description |
|---|---|---|---|
id | Id | Yes | Use it as chat_id in the Bot API. |
type | string | Yes | Always private. |
access_revision | Revision | Yes |
Session#
A new Mini App session and who it is for.
| Field | Type | Required | Description |
|---|---|---|---|
session_token | SessionToken | Yes | |
expires_at | Timestamp | Yes | 15 minutes after the exchange at most, and never after the person's SMeet sign-in ends. |
environment | Environment | Yes | |
app | App | Yes | |
space | Space | Yes | |
user | User | Yes | |
chat | Chat | Yes | |
scopes | array of Scope | Yes | What the person agreed to share; empty when the Mini App asks only for the id and the language. |
start_param | string or null | Yes | The parameter of the button or the link that opened the Mini App; null when there was none. Pattern: ^[A-Za-z0-9_-]{0,64}$. |
SessionCheck#
The state of a session. active: false comes with reason only; active: true with the session's details, read now: chat.access_revision is the revision to put into what you send the person after this check.
| Field | Type | Required | Description |
|---|---|---|---|
active | boolean | Yes | |
reason | SessionReason | No | Present when active is false. |
expires_at | Timestamp | No | Present when active is true. |
environment | Environment | No | |
app | App | No | |
space | Space | No | |
user | User | No | |
chat | Chat | No |
Errors#
Any failure. See ErrorCode for the meaning of each code and the HTTP status it comes with. The Retry-After header is set whenever the body carries retry_after. A 502, 503 or 504 without this JSON body comes from a proxy in front of SMeet: treat it as TEMPORARILY_UNAVAILABLE.
Headers of an error answer: Retry-After, X-Request-Id, WWW-Authenticate.
Error object#
Every failed call answers with this envelope and a matching HTTP status.
| Field | Type | Required | Description |
|---|---|---|---|
ok | boolean | Yes | Always false. |
error | Error | Yes | |
request_id | string | Yes | Quote it when you write to support. Empty when the proxy in front of SMeet answered. |
The error field:
| Field | Type | Required | Description |
|---|---|---|---|
code | ErrorCode | Yes | |
message | string | Yes | Human-readable, English, free of secrets. Do not parse it. |
retry_after | integer | No | Seconds to wait before retrying. Present only when a retry makes sense. At least 1. |
reason | string | No | With ACCESS_DENIED, a value of AccessDeniedReason; with CODE_ALREADY_USED, replay_unavailable when a repeat of the exchange cannot be answered any more. |
field | string | No | Present with INVALID_REQUEST, the field at fault (code, code_verifier, session_token, idempotency_key, body, or method for a path that is no method). |
limit | integer | No | Present with PAYLOAD_TOO_LARGE, the largest accepted body in bytes. |
Error codes#
| Code | HTTP | Meaning |
|---|---|---|
INVALID_CREDENTIALS | 401 | The key is missing, unknown or revoked. Do not retry |
INVALID_REQUEST | 400 | A field is missing or malformed; field names it |
PAYLOAD_TOO_LARGE | 413 | The body is larger than 64 KiB; limit gives the size in bytes |
RATE_LIMITED | 429 | Too many requests; wait retry_after and repeat with the same key |
MINI_APPS_MAINTENANCE | 503 | Mini Apps are paused; exchangeLaunchCode only, retry_after 30 |
TEMPORARILY_UNAVAILABLE | 503 | Nothing was changed; repeat the same request with the same key after retry_after |
IDEMPOTENCY_KEY_REQUIRED | 400 | exchangeLaunchCode needs an Idempotency-Key header |
IDEMPOTENCY_CONFLICT | 409 | The key was used for this code with another code_verifier |
APP_MISMATCH | 403 | The code belongs to another Mini App than the key |
ENVIRONMENT_MISMATCH | 403 | The code belongs to the other environment of the key's Mini App |
CODE_NOT_FOUND | 400 | No such code. The page signs in again |
CODE_EXPIRED | 400 | The code lived its 60 seconds. The page signs in again |
CODE_REVOKED | 400 | The code was revoked: the window closed, access ended, or a wrong verifier was sent. The page signs in again |
CODE_ALREADY_USED | 400 | The code was exchanged already; with reason replay_unavailable a repeat cannot be answered any more. The page signs in again |
CODE_VERIFIER_MISMATCH | 400 | The verifier does not match the code, and the code is revoked now. The page signs in again |
ACCESS_DENIED | 403 | The person may not use the Mini App now; reason says why |