> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twenty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Inbox

> Post messages from your app in members' inbox, from a logic function or a front component.

## Overview

Your app can start and continue conversations in the inbox of workspace members, where they also talk with Twenty's assistant. A message can end on a question, a form or a change to approve, which the member answers from the chat before the conversation continues with the assistant.

The inbox helpers are exported from both `twenty-sdk/logic-function` and `twenty-sdk/front-component`, so a scheduled run and a button in your app post the same way.

## Sending a message

`sendInboxMessage()` posts a message from your app in the chats of one or more workspace members and returns the conversation's `threadId`.

```ts src/logic-functions/notify-first-recording.ts theme={null}
import { sendInboxMessage } from 'twenty-sdk/logic-function';

const { threadId } = await sendInboxMessage({
  workspaceMemberIds: [workspaceMemberId],
  threadKey: 'first-call-recording',
  idempotencyKey: 'first-call-recording',
  title: 'Your first call recording is ready',
  text: 'Your first call was recorded: **Weekly sync**.',
  toolCall: {
    toolName: 'ask_question',
    input: {
      header: 'Share',
      question: 'Do you want to share it with the other attendees?',
      options: [{ label: 'Draft a recap email' }, { label: 'Not now' }],
    },
  },
});
```

Key points:

* `workspaceMemberIds` lists the members who receive the conversation, at least one. The first member of a new conversation owns it, and the others follow it as participants. A later send under the same key that lists new members adds them; members it leaves out keep the conversation.
* `threadKey` picks the conversation for this app, shared by every member it is sent to. A new key starts a conversation titled `title`; a key you used before adds the message to that conversation.
* `idempotencyKey` identifies the message within the conversation. Sending again with the same keys writes nothing new, so retries and concurrent runs never duplicate a message.
* `text` is markdown, and can carry [mentions and record references](#mentions-and-record-references).
* `toolCall` (optional) ends the message on one of:
  * a call the member answers, which pauses the conversation: `ask_question` (one multiple-choice question), `request_form` (fields to fill in) or `propose_tool_call` (a call to approve). Its `input` takes the `toolName`, the `arguments` you would call the tool with and a one-sentence `summary`. The tool must be one your app's default role could run itself, such as `create_one_person` or `update_one_opportunity` (with the record `id`); an email (`send_email` or `draft_email`, with `recipients`, `subject` and a `body` in HTML) needs no permission of your app. The member reviews the call in the same card as a call the assistant proposes, edits it if they want, and the approved call runs with their own access;
  * one of your app's own tools, by `logicFunctionUniversalIdentifier`, rendered by its front component with the `input` and `output` you pass. It does not pause the conversation.
* Only one call the member answers can wait in a conversation at a time: sending another before they answer fails with `THREAD_AWAITING_ANSWER`. Plain messages and app tool calls are still accepted.
* Only the member who owns a conversation can delete it, and a deleted conversation is gone for every member: it is not recreated, and nothing is added to it. The other members can unsubscribe to take it out of their own inbox.
* Every member must have the `AI` permission, and the call fails without writing the message when one of them cannot have the conversation. Your app's [default role](https://docs.twenty.com/developers/extend/apps/config/roles.md) must grant `SystemPermissionFlag.AI`.

### Who sends the message

A message is always written by your app, whatever triggered the call. The call itself runs like the default [API clients](https://docs.twenty.com/developers/extend/apps/logic/logic-functions.md#whose-access-a-call-uses):

* In a logic function, it acts as the person who triggered the run, or as your application when nobody did, such as on a cron schedule.
* In a front component, it acts as the member looking at the page. When the token has expired, the call refreshes it once through Twenty and retries.

The person behind the call needs the `AI` permission as well, like every recipient.

To post from a front component, import the same helpers from `twenty-sdk/front-component`. [Posting to the inbox](https://docs.twenty.com/developers/extend/apps/layout/front-components.md#posting-to-the-inbox) shows how to open the conversation afterwards.

## Mentions and record references

The inbox renders reference tokens in `text` as chips. Write them with these helpers rather than by hand:

```ts src/logic-functions/flag-idle-deal.ts theme={null}
import {
  inboxMention,
  inboxReferenceRecord,
  sendInboxMessage,
} from 'twenty-sdk/logic-function';

const ownerMention = await inboxMention({ workspaceMemberId: owner.id });

const dealReference = await inboxReferenceRecord({
  objectNameSingular: 'opportunity',
  recordId: opportunity.id,
});

await sendInboxMessage({
  workspaceMemberIds: [owner.id],
  threadKey: `idle-deal-${opportunity.id}`,
  idempotencyKey: `idle-deal-${opportunity.id}-${weekNumber}`,
  title: `${opportunity.name} is idle`,
  text: `${ownerMention}, ${dealReference} has had no activity for two weeks.`,
});
```

* `inboxMention({ workspaceMemberId })` writes a mention of a workspace member, and `inboxReferenceRecord({ objectNameSingular, recordId })` a chip that links to any record.
* Both read the label the chip shows, as the composer does: the member's full name, or their email when the name is empty, and the record's label identifier, such as a company name. Brackets become parentheses and line breaks become spaces, so the chip always renders.
* They read with the same access as the rest of the call, so that access needs to reach the member or record. A record reference makes two requests, one for the object's label field and one for the record.
* A mention only renders. It does not add the member to the conversation or notify them, so list everyone who should receive the message in `workspaceMemberIds`.
* `INBOX_ASSISTANT_MENTION` is the text the composer writes when a member mentions the assistant (`@Ada`), so your messages name it the same way.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.