Skip to content

REST API

Realtime (WebSocket)

Connect to Reverb over the Pusher protocol, authorize private channels and handle events.

Realtime updates are delivered by Laravel Reverb over the Pusher protocol, so any Pusher client (pusher-js, Laravel Echo, PusherSwift, …) works. Get the connection settings from GET /api/broadcasting/client-config — production uses wss://ws.minchatapp.com:8443.

GET /api/broadcasting/client-config
{
  "enabled": true,
  "key": "<app-key>",
  "host": "ws.minchatapp.com",
  "port": 8443,
  "scheme": "https"
}

Connecting#

Laravel Echo
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

const cfg = await fetch('https://minchatapp.com/api/broadcasting/client-config', {
  headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' },
}).then(r => r.json());

const echo = new Echo({
  broadcaster: 'reverb',
  Pusher,
  key: cfg.key,
  wsHost: cfg.host,
  wsPort: cfg.port,
  wssPort: cfg.port,
  forceTLS: cfg.scheme === 'https',
  enabledTransports: ['ws', 'wss'],
  authEndpoint: 'https://minchatapp.com/broadcasting/auth',
  auth: { headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' } },
});

echo.private(`users.${me.id}`)
  .listen('.MessageSent', (m) => console.log('new message', m.conversation_id, m.content))
  .listen('.ConversationCreated', (c) => console.log('added to', c.name));

echo.private('conversation.12')
  .listen('.UserActivity', (a) => console.log(a.name, a.action));

Channel authorization#

Private channels are authorized by POST /broadcasting/auth (form fields socket_id, channel_name) with the same Bearer token. Banned users are refused.

bash
curl -X POST https://minchatapp.com/broadcasting/auth \
  -H "Authorization: Bearer $TOKEN" -H 'Accept: application/json' \
  -d 'socket_id=123.456' -d 'channel_name=private-users.1'
# → {"auth":"<key>:<signature>"}

Channels#

ChannelWho can subscribePurpose
private-users.{userId}The user onlyEverything addressed to the user across all chats — the recommended single subscription
private-conversation.{id}Members of the conversationEvents of one open chat (typing, reads, messages)
qr-login.{hash}Anyone (public)QrLoginUpdated for a QR sign-in request
Most message events are sent to both the conversation channel and every member's users.{id} channel, so de-duplicate by event + id if you subscribe to both. Event names are the class names (with Echo use a leading dot: .MessageSent).

Events#

WS MessageSent #
private-conversation.{id}private-users.{id} (members)

New message. Payload is the full message object plus conversation_id, conversation_type, conversation_name, conversation_avatar. is_own/can_delete are always false — compare user.id with yours.

Example payload
{
  "id": 55,
  "content": "Realtime demo https://example.com",
  "type": "text",
  "attachments": [],
  "link_previews": null,
  "reply_to": {
    "id": 43,
    "content": "Thanks everyone!",
    "type": "text",
    "attachments": [],
    "user": {
      "id": 4,
      "name": "Gleb Orlov",
      "avatar": null
    }
  },
  "user": {
    "id": 1,
    "name": "Anna Smith",
    "avatar": null,
    "is_channel": false,
    "is_bot": false,
    "username": "anna_s"
  },
  "created_at": "2026-10-22T09:11:15.000000Z",
  "edited_at": null,
  "conversation_id": 1,
  "conversation_type": "group",
  "conversation_name": "Design team",
  "conversation_avatar": null,
  "can_delete": false,
  "is_own": false,
  "read_receipt": "delivered",
  "client_id": null,
  "reactions": [],
  "forwarded_from": null,
  "views_count": null,
  "permalink": null,
  "system": null,
  "card": null,
  "group_id": null,
  "mentions": [],
  "silent": false,
  "reply_markup": null,
  "expires_at": null
}
WS MessageUpdated #
private-conversation.{id}private-users.{id} (members)

Message edited, poll/to-do changed or bot keyboard updated.

Example payload
{
  "id": 55,
  "content": "Realtime demo (edited)",
  "edited_at": "2026-10-22T09:11:15.000000Z",
  "created_at": "2026-10-22T09:11:15.000000Z",
  "conversation_id": 1,
  "link_previews": null,
  "attachments": [],
  "type": "text",
  "card": null,
  "group_id": null,
  "reply_markup": null
}
WS MessageDeleted #
private-conversation.{id}private-users.{id} (members)

Deleted for everyone (or, sent only to your users.{id}, deleted for you).

Example payload
{
  "id": 55,
  "created_at": "2026-10-22T09:11:15.000000Z",
  "conversation_id": 1
}
WS MessageReactionUpdated #
private-conversation.{id}private-users.{id} (members)

Reaction counters changed. actor_id — who reacted; emoji_id is null when removed. Set me yourself when actor_id is you.

Example payload
{
  "message_id": 55,
  "conversation_id": 1,
  "reactions": [
    {
      "emoji_id": 2,
      "set_id": 1,
      "set_title": "Min",
      "set_active": true,
      "shortcode": "heart",
      "kind": "unicode",
      "unicode": "❤️",
      "image_url": null,
      "count": 1,
      "user_ids": [
        1
      ]
    }
  ],
  "actor_id": 1,
  "emoji_id": 2
}
WS LinkPreviewsReady #
private-conversation.{id}private-users.{id} (members)

Link previews for a message are ready.

Example payload
{
  "conversation_id": 1,
  "message_id": 55,
  "link_previews": [
    {
      "url": "https://example.com",
      "provider": "generic",
      "title": "example.com",
      "description": null,
      "image": null,
      "site_name": "example.com",
      "embed_url": null,
      "embed_html": null,
      "video_url": null,
      "video_type": null,
      "video_width": null,
      "video_height": null,
      "accessible": true,
      "meta": []
    }
  ]
}
WS ParticipantRead #
private-conversation.{id}private-users.{id} (other members)

A member read the chat up to last_read_at (read receipts).

Example payload
{
  "conversation_id": 1,
  "user_id": 1,
  "last_read_at": "2026-10-22T09:11:15+00:00"
}
WS UserActivity #
private-conversation.{id}private-users.{id} (other members)

Typing / recording audio / cancel. Not sent in channels.

Example payload
{
  "conversation_id": 1,
  "user_id": 1,
  "action": "typing",
  "name": "Anna Smith"
}
WS ConversationCreated #
private-users.{id}

You were added to a chat (or created/joined one). Payload is a conversation list card.

Example payload
{
  "id": 1,
  "name": "Design team",
  "type": "group",
  "avatar": null,
  "description": "Release discussions",
  "username": null,
  "visibility": "public",
  "share_url": null,
  "last_message": null,
  "unread_count": 0
}
WS ConversationUpdated #
private-users.{id}

Chat settings or your role changed. Per-user payload (user_role, is_owner, can_send_messages, can_pin, …).

Example payload
{
  "id": 1,
  "name": "Design team",
  "avatar": null,
  "description": "Release discussions",
  "type": "group",
  "user_role": "admin",
  "is_owner": true,
  "can_send_messages": true,
  "members_can_pin": false,
  "can_pin": true,
  "can_manage_subscribers": false,
  "username": null,
  "visibility": "public",
  "share_url": null,
  "hidden_from_discovery": false,
  "history_ttl": 0
}
WS ConversationDeleted #
private-users.{id}

The chat was deleted or you were removed.

Example payload
{
  "id": 12
}
WS ConversationMuted #
private-users.{id}

Mute changed on another of your devices.

Example payload
{
  "conversation_id": 1,
  "muted_until": "2026-10-22T10:11:15+00:00"
}
WS ConversationPinsUpdated #
private-conversation.{id}private-users.{id} (members)

Pinned messages changed.

Example payload
{
  "conversation_id": 1,
  "pinned_messages": [
    {
      "id": 55,
      "content": "Realtime demo (edited)",
      "type": "text",
      "attachments": [],
      "user": {
        "id": 1,
        "name": "Anna Smith",
        "avatar": null
      },
      "created_at": "2026-10-22T09:11:15.000000Z",
      "pinned_at": "2026-10-22T09:11:15+00:00",
      "pinned_by": 1
    }
  ]
}
WS DraftUpdated #
private-users.{id}

Your draft changed on another device.

Example payload
{
  "conversation_id": 1,
  "draft": {
    "content": "typing a draft…",
    "reply_to_message_id": null,
    "updated_at": "2026-10-22T09:11:15+00:00"
  }
}
WS ScheduledMessagesUpdated #
private-users.{id}

Number of your pending scheduled messages in a chat changed.

Example payload
{
  "conversation_id": 1,
  "pending_count": 5
}
WS MentionsUpdated #
private-users.{id}

Unread mention counter of a chat changed.

Example payload
{
  "conversation_id": 1,
  "unread_mentions_count": 2
}
WS MessageReminderDue #
private-users.{id}

A reminder fired (due:true) — show it in-app.

Example payload
{
  "reminder": {
    "id": 3,
    "message_id": 45,
    "conversation_id": 1,
    "conversation_name": "Design team",
    "sender_name": "Anna Smith",
    "preview": "Hello @Boris Petrov!",
    "remind_at": "2026-11-02T10:00:00+00:00",
    "status": "sent"
  },
  "due": true
}
WS SessionsRevoked #
private-users.{id}

Sessions (token ids) were terminated. If yours is in the list, sign out locally.

Example payload
{
  "session_ids": [
    19,
    23
  ]
}
WS LoginCodeRequested #
private-users.{id}

Someone requested a one-time sign-in code for this account; show it in the signed-in app.

Example payload
{
  "code": "482913",
  "expires_in": 600
}
WS CallStarted #
private-conversation.{id}private-users.{id} (callees)

Incoming call.

Example payload
{
  "call_id": "7c1d…",
  "conversation_id": 3,
  "conversation_type": "private",
  "conversation_name": "Anna Smith",
  "conversation_avatar": null,
  "room": "conv-3",
  "mode": "video",
  "ring_ttl": 45,
  "caller": {
    "id": 1,
    "name": "Anna Smith",
    "avatar": null
  },
  "started_at": "2026-10-22T09:30:00.000Z"
}
WS CallAnswered #
private-users.{id} (callees)

The call was answered on one of your devices — stop ringing on the others.

Example payload
{
  "call_id": "7c1d…",
  "conversation_id": 3
}
WS CallEnded #
private-conversation.{id}private-users.{id} (members)

Call ended. reason: ended, cancelled, declined, timeout, busy, unavailable.

Example payload
{
  "call_id": "7c1d…",
  "conversation_id": 3,
  "reason": "ended",
  "by_user_id": 1
}
WS VideoDownloadUpdated #
private-users.{id}

Server-side video download progressed.

Example payload
{
  "id": 7,
  "url": "https://www.youtube.com/watch?v=…",
  "status": "completed",
  "file_url": "https://minchatapp.com/api/videos/<token>",
  "title": "Demo",
  "duration": 212,
  "error_message": null,
  "code": null
}
WS QrLoginUpdated #
qr-login.{hash} (public)

The phone confirmed or declined the QR request: status is confirmed or declined. On confirmed call /auth/qr/poll to get the token.

Example payload
{
  "status": "confirmed"
}