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 / Live inbox

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

Live inbox

The inbox is a complete messenger inside the console: every private chat of every connected account — Telegram, Instagram, Facebook — in one list, with whole messages including photos, voice notes and files, live updates, and history from before the account was added. The one rule that surprises people is the read state: reading here does not mark anything read for the customer.

Why nothing is marked read#

Reading a conversation in Oqim never marks it read on Telegram, Instagram or Facebook. The customer does not see a tick or a “seen”. That is deliberate: an owner who scans their messages from the console should not silently tell a hundred customers that their message has been read and answered.

ActionWhat it changesWhat the customer sees
POST /ai/conversations/{id}/readOqim's own unread_count becomes 0. Replying and taking over do the same.Nothing.
POST /ai/conversations/{id}/platform-readA real read receipt is sent once (readHistory on Telegram, mark_seen on Meta) and audited.The message is marked read. A second call answers already_read: true and sends nothing.
  • Oqim contains no call that marks messages read passively — a source-level check fails the build if one is ever added, and the integration tests assert that ingesting, listing, opening and downloading send zero read receipts.
  • The Mark as read control in the thread is the only way to send a receipt on the platform, and it tells you that it does. It needs ai:operate.
  • Receipt calls are best-effort: if the platform refuses, the API answers 409, and if the account is unreachable, 503 with nothing sent.

The chat list#

Every account's private chats are in one list. Each row carries the person's avatar, the channel glyph and name, the last message with its time, the account it belongs to and, where the customer wrote last and nobody answered, since when it has been waiting.

ControlValues
SortRecent (the default), unread first, waiting for a reply (oldest first), oldest.
FilterChannel (all, Telegram, Instagram, Facebook), account, unread, waiting, has files, and personal — the last one only for people who may manage accounts.
SearchMatches the chat title, @username, phone number and the platform's person id. Message text is sealed at rest, so searching inside message bodies is not offered.
  • A file in the last message is shown by its kind, not as a bare attachment id: photo, video, voice, audio, document, sticker, animation, video note, location or contact.
  • Personal chats are listed for owners and admins (accounts:manage) and hidden from other roles. The AI never sees them — see Past conversations and privacy.
  • Group chats and channels are not part of the inbox.

Whole messages#

A message keeps more than its text: its files, the message it replies to, who it was forwarded from, when it was edited or deleted, the reactions on it, and its location or contact card where the platform sent one.

Files: photos, videos, voice and documents#

Every file is stored in Oqim's own storage — local disk or S3 — and served through an authorized API route. A platform URL or file reference is never handed to the browser.

KindExamples
Photo, sticker, animation, video, video noteShown in the thread with a thumbnail where one can be made cheaply.
Voice, audioPlayable in place, with seeking.
DocumentDownloaded by name, with its own type.
Location, contactStructured data, no file.
Share, story, story mentionKept as their kind, with whatever metadata the platform sent.
  • When a file downloads. Telegram: photos, voice notes and stickers up to a few megabytes are fetched as the message arrives, and everything else the first time somebody opens it; the worker holds the sessions, and an expired file reference is refreshed and retried. Instagram and Facebook: Meta's attachment URLs expire, so those files are downloaded immediately while the message is processed.
  • Caps and statuses. 50 MB per file by default (INBOX_MAX_FILE_MB). A file moves through PENDING, STORED, TOO_LARGE, UNAVAILABLE and FAILED; the thread shows the status rather than a broken attachment.
  • Streaming. GET /ai/conversations/{id}/attachments/{attachment_id} streams the file with its content type and supports HTTP Range, so audio and video can seek. While the file is still downloading it answers 202 with {status: "PENDING"} and queues the work; when it finishes, ai.conversation.attachment_ready fires. ?thumb=1 returns the thumbnail.
  • Files from imported history are not downloaded during the import; they download the first time somebody views them.

Sending files#

Replying with a file is two steps: upload it, then send it. POST /ai/conversations/{id}/uploads takes one file and returns an upload_id (unused uploads expire after 24 hours), and POST /ai/conversations/{id}/reply sends either text, or attachments, or both — a reply needs at least one of the two.

ChannelWhat may be sent
TelegramAny file up to the cap. Several files in one message become an album.
InstagramImage, video and audio, within Meta's Send API limits.
FacebookImage, video, audio and file.
  • The reply gate is unchanged by files: the consent rules, the reply window and the platform's own window are checked when the reply is queued and again when it is sent. A file counts as a message.
  • A reply may quote an earlier message where the channel supports it; otherwise it is sent as a plain reply and the thread notes that.
  • Instagram and Facebook text is plain: no Telegram formatting is applied.

History from before the account was added#

ChannelHow far back
TelegramA period you choose, or the whole history: since: "all" with a per-chat limit up to 10,000 messages (500 by default). A full import can take hours, because Telegram's rate limits apply.
Instagram and FacebookThe last 20 messages of each conversation — Meta's Conversations API gives the details of nothing older, so older history cannot be fetched at all. Every new message is stored in full from the moment the account is connected.

Imports are resumable, obey flood control, and never touch a chat's read state. What arrives is inert — it can never make the AI reply. That is covered in Past conversations and privacy.

Live updates#

  • The console subscribes to GET /api/v1/events/stream. A new message (ai.conversation.message) appends to the open thread and re-sorts the list in place; edits, deletions, reactions and Oqim-side read changes arrive as ai.conversation.message_updated; a finished download arrives as ai.conversation.attachment_ready.
  • Those payloads carry identifiers and states only — never the message text. Anything sensitive stays in the console's own fetch, so a webhook endpoint never receives it.
  • Polling is the fallback when the stream is unavailable: a few seconds for the open thread, about fifteen for the list.

Endpoints#

All under /api/v1. Everything on a conversation needs ai:read or ai:operate; in a personal chat the attachment route additionally needs accounts:manage. See the API reference for bodies and responses.

EndpointPermissionWhat it does
GET/ai/conversationsai:readThe organization's inbox on every channel, each with its channel (TELEGRAM, INSTAGRAM or FACEBOOK), its account (account: id, channel, name, username, avatar_url; connected_account_id for Instagram and Facebook), the linked recipient's consent, last_message (author, kind, the first 80 characters of the text decrypted, at) and waiting_since (the customer's last message time when they wrote last and nobody replied; null otherwise).
GET/ai/conversations/{id}ai:readOne conversation with its newest messages (oldest first; limit up to 200, default 50), the linked recipient, the open handoff, and reply: whether a person can reply now and on what basis (REPLY_WINDOW, CONSENT on Telegram, or HUMAN_AGENT on Instagram and Facebook, with window_ends_at and, where the platform's Meta app has the Human Agent permission, human_window_ends_at), or why not (code, reason), and max_length with max_length_unit: the channel's text limit (Telegram 4096 utf16, Instagram 1000 bytes, Facebook 2000 characters).
POST/ai/conversations/{id}/replyai:operateReply as a person.
POST/ai/conversations/{id}/takeoverai:operateTake the conversation over: the AI pauses (ai_state PAUSED_HANDOFF), its unsent messages are cancelled, and a MANUAL handoff assigned to you is opened (or the open handoff, if unassigned, becomes yours).
POST/ai/conversations/{id}/resumeai:operateHand the conversation back to the AI: ai_state ACTIVE and the open handoff resolved.
POST/ai/conversations/{id}/readai:operateMark the conversation read in Oqim only (unread_count 0).
POST/ai/conversations/{id}/platform-readai:operateSend a read receipt on the platform itself (Telegram readHistory, Meta mark_seen) — the ONLY way a message is ever marked read there, and only when a person asks.
GET/ai/conversations/{id}/attachments/{attachment_id}ai:readStream a message's file from Oqim's storage with its content type and HTTP Range (audio and video seek).
POST/ai/conversations/{id}/uploadsai:operateUpload one file (multipart field file) to send in the conversation, before replying.
PUT/ai/conversations/{id}/personalai:operateMark the chat personal (personal: true) or a business chat (false).
GET/ai/conversations/{id}/insightsai:readLatest Conversation Intelligence analysis and summary for a conversation, with live: the case analysis's current reading (JEV between summaries: scores, flags and classification; see AI Seller: case analysis and insights).
POST/ai/conversations/{id}/analyzeai:operateQueue a Conversation Intelligence summary and insights for this conversation immediately (outside the normal 60-second debounce window and the every-10-messages cadence).
POST/ai/conversations/simulateai:operateSimulator only (TELEGRAM_DRIVER=simulator; otherwise 404 simulator_only): a customer writes to one of your accounts.
POST/ai/playground/runai:operateDry-run the AI Seller pipeline against a business with a synthetic conversation (mode PLAYGROUND, or EVAL for automated evaluations).
GET/ai/handoffsai:readConversations handed to people, newest first: by the AI (trigger HUMAN_REQUESTED, LOW_CONFIDENCE, COMPLAINT, PRICING_EXCEPTION, …) or taken over (MANUAL).
PATCH/ai/handoffs/{id}ai:operateAssign an open handoff to a member (assigned_user_id; null unassigns) and/or resolve it (resolved: true, with an optional resolution_note).
POST/ai/conversations/{id}/drafts/{draft}/approveai:operateSend a draft the AI Seller prepared (autonomy 2, or 3 outside the approved scenarios).
POST/ai/conversations/{id}/drafts/{draft}/discardai:operateSet a pending draft or recommendation aside (status DISCARDED).
GET/ai/leadsai:readThe AI Seller's leads, the most recently updated first: one per conversation, opened when the customer shows interest, with the funnel stage (and its name), quality (cold, warm, hot), interest, status (OPEN; WON at the funnel's last stage; LOST when the customer opted out) and a value estimate from the prices of the offers the customer is interested in.
GET/ai/sales-pipelineai:readFunnel snapshot: for each business's default funnel, counts of open/won/lost leads per stage with estimated total value (sum of value_estimate for open leads) and oldest open lead age in days.
GET/ai/analyticsai:readConversation and sales metrics over a time range (from/to: YYYY-MM-DD or RFC3339, default last 30 days).
GET/ai/performanceai:readPer-agent/business/model performance over a time range (from/to: YYYY-MM-DD or RFC3339, default last 30 days).

Read receipts are a person's decision

Never wire /platform-read into a bulk action or a view. Sending a receipt tells the customer their message was read; Oqim only does that when somebody presses the button.
PreviousChannelsNext Past conversations and privacy