Skip to content

REST API

Authentication

Sign-in flows: identifier-first wizard, one-time codes, QR login, Google OAuth, sessions and devices.

Min has no cloud password or 2FA. The recommended flow is the identifier-first wizard: start → (password | request-code → verify-code) → token. New accounts finish with register. Each step is bound by a 48-character ticket.

flow
POST /api/auth/start {identifier}
   ├─ next=password ─▶ POST /api/auth/password {ticket,password} ─▶ {token,user}
   │                └▶ POST /api/auth/request-code {ticket} ─▶ POST /api/auth/verify-code {ticket,code} ─▶ {token,user}
   ├─ next=code ─────▶ POST /api/auth/verify-code ─▶ {next:"name"} ─▶ POST /api/auth/register {ticket,name,password}
   └─ next=invite ───▶ POST /api/auth/register {ticket,name,password,invite_code}

QR login#

  1. The signed-out device calls POST /api/auth/qr and shows qr (minchat-login:<token>) as a QR code.
  2. It subscribes to the public channel from channel (qr-login.<hash>) and/or polls POST /api/auth/qr/poll every 1–2 s.
  3. A signed-in phone scans it, calls inspect to show the request, then confirm or decline.
  4. poll returns status: confirmed with token and user exactly once.

Google OAuth (web)#

Open /auth/google in the browser. After the callback the user lands on /web with a one-time oauth_exchange cookie; the web app immediately calls POST /auth/oauth-exchange to receive the Bearer token.

Sign-in, registration, password#

POST /api/auth/start #

Start sign-in (identifier-first)

No auth Rate limit: 20/min

Step 1 of the sign-in wizard. Normalises the identifier (email → lowercase, phone → E.164), looks the account up and decides the next step. Returns a ticket (48 chars) that links the following steps. next is password for existing accounts, code for a new account outside Russia (a one-time code is sent), invite for a new account in Russia (registration by invite only). There is no cloud password / 2FA.

Parameters

Name Type Description
identifier
required body
string
Email or phone number.
max 255 chars

Request

curl
curl -X POST 'https://minchatapp.com/api/auth/start' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"identifier": "anna@example.com"}'

Response

HTTP 200
{
  "success": true,
  "next": "password",
  "ticket": "NOtN0Li5lPE01BIr6Gx6iBAOspXxUp9f9nBmnxWPOlsLcosG",
  "region": "other",
  "can_request_code": true
}
POST /api/auth/password #

Sign in with password

No auth Rate limit: 10/min

Step 2 for existing accounts. Returns a Sanctum token and the user.

Parameters

Name Type Description
ticket
required body
string
Ticket from /auth/start.
exactly 48 chars
password
required body
string
Account password.

Request

curl
curl -X POST 'https://minchatapp.com/api/auth/password' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"ticket": "<ticket>", "password": "Secret123"}'

Response

HTTP 200
{
  "success": true,
  "user": {
    "id": 3,
    "name": "Vera Kotova",
    "email": "vera@example.com",
    "created_at": "2026-10-20T11:12:46.000000Z",
    "updated_at": "2026-10-22T09:12:49.000000Z",
    "avatar": null,
    "last_seen_at": "2026-10-22T09:12:49.000000Z",
    "push_notifications_enabled": true,
    "invited_by_id": null,
    "invite_id": null,
    "locale": "ru",
    "default_history_ttl": 0,
    "phone": null,
    "about": null,
    "birthday": null,
    "username": null,
    "is_bot": false,
    "phone_verified_at": null,
    "avatar_url": null
  },
  "token": "17|Q2pXexampleSanctumToken0000000000000000000"
}
401 wrong
HTTP 401 · wrong
{
  "success": false,
  "code": "auth.ticket_invalid",
  "error": "Sign-in session expired. Start again.",
  "message": "Sign-in session expired. Start again."
}
POST /api/auth/request-code #

Request a one-time code

No auth Rate limit: 10/min

Sends a one-time login code instead of the password. Delivery: an active MinChat client of the account (in-app, realtime event LoginCodeRequested), SMS for non-RU phones, or email. In Russia only in-app delivery is available. Cooldown: SMS 60 s, email/in-app 30 s.

Parameters

Name Type Description
ticket
required body
string
Ticket from /auth/start.
exactly 48 chars

Request

curl
curl -X POST 'https://minchatapp.com/api/auth/request-code' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"ticket": "<ticket>"}'

Response

Responds with HTTP 200.

POST /api/auth/resend-code #

Resend the one-time code

No auth Rate limit: 10/min

Same as request-code, respects the cooldown.

Parameters

Name Type Description
ticket
required body
string
Ticket from /auth/start.
exactly 48 chars

Request

curl
curl -X POST 'https://minchatapp.com/api/auth/resend-code' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"ticket": "<ticket>"}'

Response

Responds with HTTP 200.

POST /api/auth/verify-code #

Verify the one-time code

No auth Rate limit: 20/min

Existing account → returns token + user. New account (outside Russia) → {"next":"name"}, continue with /auth/register.

Parameters

Name Type Description
ticket
required body
string
Ticket from /auth/start.
exactly 48 chars
code
required body
string
6-digit code.
max 12 chars

Request

curl
curl -X POST 'https://minchatapp.com/api/auth/verify-code' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"ticket": "<ticket>", "code": "123456"}'

Response

Responds with HTTP 200.

POST /api/auth/register #

Finish registration

No auth Rate limit: 5/10 min

invite_code is required only for the ru region. Returns token + user.

Parameters

Name Type Description
ticket
required body
string
Ticket from /auth/start.
exactly 48 chars
name
required body
string
Display name.
max 255 chars
password
required body
string
New password.
requires password_confirmationmin 8, letters + digits
invite_code
optional body
string
Invite code (RU only).
max 32 chars

Request

curl
curl -X POST 'https://minchatapp.com/api/auth/register' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"ticket": "<ticket>", "name": "Anna Smith", "password": "Secret123", "password_confirmation": "Secret123"}'

Response

Responds with HTTP 200.

POST /api/login #

Sign in with email + password (legacy)

No auth Rate limit: 10/min

One-step login kept for older clients; new clients should use /auth/*. After 5 failed attempts in 15 minutes from one IP the endpoint answers 429.

Parameters

Name Type Description
email
required body
string
Account email.
email
password
required body
string
Password.

Request

curl
curl -X POST 'https://minchatapp.com/api/login' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"email": "anna@example.com", "password": "Secret123"}'

Response

HTTP 200
{
  "success": true,
  "user": {
    "id": 3,
    "name": "Vera Kotova",
    "email": "vera@example.com",
    "created_at": "2026-10-20T11:12:46.000000Z",
    "updated_at": "2026-10-22T09:12:48.000000Z",
    "avatar": null,
    "last_seen_at": "2026-10-22T09:12:48.000000Z",
    "push_notifications_enabled": true,
    "invited_by_id": null,
    "invite_id": null,
    "locale": "ru",
    "default_history_ttl": 0,
    "phone": null,
    "about": null,
    "birthday": null,
    "username": null,
    "is_bot": false,
    "phone_verified_at": null,
    "avatar_url": null
  },
  "token": "17|Q2pXexampleSanctumToken0000000000000000000"
}
401 401
HTTP 401 · 401
{
  "success": false,
  "code": "auth.invalid_credentials",
  "error": "Invalid email or password",
  "message": "Invalid email or password"
}
POST /api/register #

Register with email (legacy)

No auth Rate limit: 5/10 min

Legacy registration. Same response as /login.

Parameters

Name Type Description
name
required body
string
Display name.
max 255 chars
email
required body
string
Email.
emailunique
password
required body
string
Password.
requires password_confirmationmin 8, letters + digits
invite_code
optional body
string
Invite code (when invites are required).

Request

curl
curl -X POST 'https://minchatapp.com/api/register' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"name": "Anna Smith", "email": "anna@example.com", "password": "Secret123", "password_confirmation": "Secret123", "invite_code": "ABCDEF"}'

Response

Responds with HTTP 200.

POST /api/logout #

Sign out

Bearer token

Revokes the current token, or all tokens of the account with ?all=1 (or {"all":true}). Revoked sessions receive SessionsRevoked.

Parameters

Name Type Description
all
optional body
boolean
Revoke every token of the account.

Request

curl
curl -X POST 'https://minchatapp.com/api/logout' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Accept: application/json'

Response

HTTP 200
{
  "success": true,
  "code": "auth.logged_out",
  "message": "Logged out."
}
POST /api/forgot-password #

Send a password reset link

No auth Rate limit: 5/10 min

Always answers with a neutral message. client: desktop → minchat://reset-password/…, android/app → minchatapp://reset-password/…, otherwise the web URL /password/reset/{token}.

Parameters

Name Type Description
email
required body
string
Email address.
emailmax 255 chars
client
optional body
string
Where the link should open: desktop, android, app or web (default).

Request

curl
curl -X POST 'https://minchatapp.com/api/forgot-password' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"email": "anna@example.com", "client": "android"}'

Response

HTTP 200
{
  "success": true,
  "code": "password.reset_sent",
  "message": "If an account exists, we sent a password reset email."
}
POST /api/reset-password #

Reset the password

No auth Rate limit: 10/10 min

Uses the token from the email.

Parameters

Name Type Description
token
required body
string
Token from the reset email.
email
required body
string
Email address.
email
password
required body
string
Password.
requires password_confirmationmin 8, letters + digits

Request

curl
curl -X POST 'https://minchatapp.com/api/reset-password' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"token": "<from-email>", "email": "anna@example.com", "password": "NewSecret123", "password_confirmation": "NewSecret123"}'

Response

Responds with HTTP 200.

POST /api/change-password #

Change the password

Bearer token Rate limit: 10/10 min

Requires the current password.

Parameters

Name Type Description
current_password
required body
string
Current password.
password
required body
string
Password.
requires password_confirmationmust differ from current_passwordmin 8, letters + digits

Request

curl
curl -X POST 'https://minchatapp.com/api/change-password' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"current_password": "Secret123", "password": "NewSecret123", "password_confirmation": "NewSecret123"}'

Response

HTTP 422 · wrong
{
  "success": false,
  "code": "password.wrong_current",
  "error": "Current password is incorrect.",
  "message": "Current password is incorrect."
}
POST /api/auth/qr #

Create a QR login request

No auth Rate limit: 20/min

Called by a signed-out desktop/web client. Render qr as a QR code; it lives expires_in seconds (90). Then either poll /auth/qr/poll with poll_token or subscribe to the public channel channel and wait for QrLoginUpdated.

Parameters

No parameters.

Request

curl
curl -X POST 'https://minchatapp.com/api/auth/qr' \
  -H 'Accept: application/json'

Response

HTTP 200
{
  "qr": "minchat-login:sBopO38GonBMQ39qB3d2lEGwXPEdkKV6QYR96PqYFQ1Bq4M8",
  "poll_token": "3KFapxV62nDlATwjomaI5HqHB9HyBCVTYo7TqNX6pxdNsVjp",
  "channel": "qr-login.e4a27d213ac0f5cc88a2d3df9fb46f3c53315953b9f5082e89e088fd78844e5a",
  "expires_at": "2026-10-22T09:07:43+00:00",
  "expires_in": 90
}
POST /api/auth/qr/poll #

Poll a QR login request

No auth Rate limit: 90/min

status: pending, confirmed (the response then contains token and user — the token is handed out once), consumed, declined, expired. An unknown token also returns expired.

Parameters

Name Type Description
poll_token
required body
string
poll_token from /auth/qr.
max 128 chars

Request

curl
curl -X POST 'https://minchatapp.com/api/auth/qr/poll' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"poll_token": "<poll_token>"}'

Response

HTTP 200
{
  "status": "expired"
}
POST /api/auth/qr/inspect #

Inspect a scanned QR code

Bearer token Rate limit: 20/min

The signed-in phone shows who is asking to sign in (device, platform, IP, location) before confirming.

Parameters

Name Type Description
token
required body
string
The scanned QR payload (minchat-login:…) or its token part.

Request

curl
curl -X POST 'https://minchatapp.com/api/auth/qr/inspect' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"token": "minchat-login:<token>"}'

Response

Responds with HTTP 200.

POST /api/auth/qr/confirm #

Confirm QR login

Bearer token Rate limit: 10/min

Issues a new session for the requesting device. The requester receives QrLoginUpdated {status:"confirmed"}.

Parameters

Name Type Description
token
required body
string
The scanned QR payload (minchat-login:…) or its token part.

Request

curl
curl -X POST 'https://minchatapp.com/api/auth/qr/confirm' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"token": "minchat-login:<token>"}'

Response

Responds with HTTP 200.

POST /api/auth/qr/decline #

Decline QR login

Bearer token Rate limit: 20/min

The requester receives QrLoginUpdated {status:"declined"}.

Parameters

Name Type Description
token
required body
string
The scanned QR payload (minchat-login:…) or its token part.

Request

curl
curl -X POST 'https://minchatapp.com/api/auth/qr/decline' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"token": "minchat-login:<token>"}'

Response

Responds with HTTP 200.

GET /auth/google #

Google sign-in (web redirect)

No auth Rate limit: 20/min

Browser redirect to Google. Optional ?invite=CODE is kept in the session for registration. Not under /api.

Parameters

Name Type Description
invite
optional query
string
Invite code for new accounts.

Request

curl
curl 'https://minchatapp.com/auth/google' \
  -H 'Accept: application/json'

Response

Responds with HTTP 200.

GET /auth/google/callback #

Google OAuth callback

No auth Rate limit: 20/min

On success redirects to /web and sets a short-lived httpOnly cookie oauth_exchange (2 minutes). Errors redirect to /?error=… (invite_required, account_banned, google_auth_failed, …).

Parameters

No parameters.

Request

curl
curl 'https://minchatapp.com/auth/google/callback' \
  -H 'Accept: application/json'

Response

Responds with HTTP 200.

POST /auth/oauth-exchange #

Exchange the Google OAuth code for a token

No auth Rate limit: 10/min

The web app calls this right after the redirect. Reads the oauth_exchange cookie (one-time) and returns {success:true, token}; 204 when there is nothing to exchange, 401 auth.oauth_expired when it has expired.

Parameters

No parameters.

Request

curl
curl -X POST 'https://minchatapp.com/auth/oauth-exchange' \
  -H 'Accept: application/json'

Response

Responds with HTTP 200.

Sessions & devices#

GET /api/user/sessions #

List sessions (devices)

Bearer token

Every Sanctum token of the account is a session. current marks the token of this request. platform/client/app_version/device_name come from the X-Client-Platform, X-Client-Version, X-Device-Name headers and the User-Agent; location is derived from the IP.

Parameters

No parameters.

Request

curl
curl 'https://minchatapp.com/api/user/sessions' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Accept: application/json'

Response

HTTP 200
{
  "sessions": [
    {
      "id": 1,
      "current": true,
      "label": "Laptop",
      "device_name": "Chrome, macOS",
      "client": "web",
      "app_version": null,
      "ip": "203.0.113.10",
      "location": "Moscow, Russia",
      "platform": "Web",
      "created_at": "2026-10-20T11:12:45+00:00",
      "last_used_at": "2026-10-22T09:06:13+00:00"
    },
    {
      "id": 19,
      "current": false,
      "label": "Chrome",
      "device_name": "Mac",
      "client": "desktop",
      "app_version": "1.0.44",
      "ip": "203.0.113.10",
      "location": null,
      "platform": "macOS",
      "created_at": "2026-10-21T07:17:33+00:00",
      "last_used_at": "2026-10-21T07:18:34+00:00"
    }
  ]
}
DELETE /api/user/sessions/{id} #

Terminate a session

Bearer token

Revokes one token; that device receives SessionsRevoked.

Parameters

Name Type Description
id
required path
integer
Session (token) id.

Request

curl
curl -X DELETE 'https://minchatapp.com/api/user/sessions/19' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Accept: application/json'

Response

HTTP 200
{
  "success": true
}
DELETE /api/user/sessions #

Terminate all other sessions

Bearer token

Revokes every token except the current one.

Parameters

No parameters.

Request

curl
curl -X DELETE 'https://minchatapp.com/api/user/sessions' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Accept: application/json'

Response

HTTP 200
{
  "success": true,
  "terminated": 11
}