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

# Inbox

> The 1Club messaging inbox - one conversation-style list of every outbound and inbound message, with thread roll-ups, draft chips, channel signals, and a detail pane that opens the thread or compose form.

The inbox is one list of every conversation between your gym and your members, outbound and inbound, with drafts alongside. Each row is a conversation - a piece of human-authored, replyable correspondence between your gym and a member - not an individual delivery. Admins and managers work the organization-wide inbox, and instructors see the conversations for members at the clubs they teach.

## When to use it

Open the inbox to see what members have written back, pick up a conversation where it left off, and finish messages you started. Each row rolls up a whole thread, new replies appear without a refresh, and a **Draft** chip marks anything not yet sent.

Typical uses:

* **Catch a member's reply** - a boulderer answers your route-setting update, and its conversation shows a higher thread counter and a fresh timestamp without a refresh, ready to reply inline.
* **Finish a draft** - a message to all jiu-jitsu members about a belt-grading date is still marked **Draft**, and clicking it reopens the compose pane.
* **Follow a group conversation** - a message to four padel members about a doubles ladder shows as one row, with every reply threaded beneath.

See [Worked examples](#worked-examples) for more on each.

## How the list is built

The conversation list is the main view of **Inbox** in the left rail (route `/messages`). The left pane lists conversations; the right pane shows the selected thread or the compose form. On mobile the right pane slides up as a sheet over the list.

The list queries `/v1/messages` filtered to top-level rows (those with no `replyToMessageId`). Each row is therefore a conversation head: outbound sends with their replies, inbound submissions with your responses, and drafts not yet sent.

Rows are sorted by `createdAt` descending and paginated 25 at a time. **Load more** at the bottom extends the page in 25-row steps.

## What a row shows

Each row is built around the counterparty of the conversation:

* A **single contact** shows that contact's avatar and full name.
* A **pair of contacts** shows two stacked avatars and "Firstname, Firstname".
* A **group of 3+** shows the first contact's avatar with a `+N` badge and "Firstname + N others".
* An **inbound message with no stored recipients** falls back to the **sender's** avatar and name - this is how a member-initiated conversation renders.

To the right of the name you may see:

* A **WhatsApp** badge next to a single contact whose WhatsApp number is verified.
* A **Draft** status chip when the message has not been sent yet.
* The relative time of the latest message (`sentAt` if sent, `createdAt` if still a draft).
* A **thread counter** badge (the small number bubble) showing how many messages are in the conversation, including the original.

Below the name is a snippet: the subject if there is one, otherwise up to the first 80 characters of the body with HTML stripped.

## Channels and direction

A message carries a **channel** and a **direction**, both stored on the record.

* **Channel** (`type`) is `email`, `sms`, or `whatsapp`. The same channel-neutral content is projected to whichever channel a message was sent on.
* **Direction** marks transport provenance: `outbound` = sent from the platform, `inbound` = received from outside (for example a member's email into the club's inbox). Direction reflects provenance, not authorship - a member composing in the portal or app produces an **outbound** message addressed to staff, because it originated on the platform.

The underlying `/v1/messages` endpoint accepts filters for `contactId`, `status`, channel `type`, `inboxId`, and `direction`, which is how the same list powers scoped views (see below).

<Note>
  When a message is sent **on behalf of** a specific person - today, a class instructor via the "send from the instructor" option - the inbox shows that person's name and avatar as the sender, matching the email the member received. The record's underlying `senderId` still points at the staff user accountable for the send.
</Note>

## Selecting a row

Clicking a row updates the URL to `/messages/<id>` and renders the right pane:

* If the message is a **draft**, the compose pane opens so you can finish writing.
* Otherwise, the **thread view** renders: the original message at the top, replies underneath in order, and an inline reply box at the bottom.

When you click **Reply** the URL becomes `/messages/<id>/reply` and the compose pane takes over the right side with the original sender pre-selected as the recipient and the subject pre-filled with `Re: <subject>`.

On desktop, opening the inbox with nothing selected auto-opens the first conversation so the detail pane is not blank. On mobile the list stays put until you pick a row.

## Real-time updates

The inbox subscribes to the notification WebSocket. Every time a `message`-category event for the current organization arrives, the list and the open thread refetch, so new inbound replies appear without a manual refresh.

Members' email replies to messages you send arrive in the conversation automatically: each emailed message carries a personal reply address alongside your gym's own address. See [Replies to your messages](/settings/email-sending#replies-to-your-messages).

## Status and engagement signals

The message-level `status` is simple: `draft` or `sent`. The inbox uses it to decide whether selecting a row opens compose or the thread view.

Per-recipient delivery detail is tracked on the record but not surfaced directly in the list. Each recipient has a `deliveryStatus` that can be `queued`, `sent`, `processed`, `delivered`, `deferred`, `bounced`, `dropped`, `failed`, `spam`, `unsubscribed`, or `skipped`, plus an `engagementStatus` of `open`, `click`, `unsubscribe`, or `spamreport`, with timestamps for each transition. Webhook handlers from SendGrid (email) and Twilio (SMS) update these fields as events arrive.

## Audience scope: admin vs instructor view

* **Admins and managers** see the organization-wide inbox: every message attached to the org. The right-pane **Compose** button is enabled, and the audience filter and template picker are available when composing.
* **Instructors** see a club-scoped slice: conversations involving members at the clubs they teach at. Their compose form hides the audience filter and template picker; replying to existing inbound messages still works.

## Permissions

* Reading the inbox requires `messages.read.own` (broader `messages.read.club` / `messages.read.organization` holders see more).
* Composing or replying requires a `messages.create` permission.
* The audience filter and organization-wide templates require manager or admin scope.

## Worked examples

### Spotting a member reply (climbing gym)

A boulderer replied to your route-setting update. Because the inbox refetches on the WebSocket event, the conversation jumps with an incremented thread counter and a fresh timestamp - no refresh needed. Click it to open the thread and reply inline.

### Finishing a draft blast (martial arts)

You started a message to all jiu-jitsu members about a belt-grading date but did not send it. It sits in the list with a **Draft** chip. Clicking the row opens the compose pane instead of a thread, so you can finish and send it.

### Reading a group thread (racket sports)

You messaged four padel members about a doubles ladder. The row shows the first member's avatar with a `+3` badge and "Firstname + 3 others". Opening it shows the single outbound message and any replies threaded beneath.

## Tips & best practices

* **Watch the thread counter.** A rising number bubble means new replies have landed in that conversation.
* **Let the auto-select help on desktop.** The first conversation opens on load, so you can triage without an extra click.
* **Use Reply, not a fresh compose, to keep threads intact.** Replying preserves the conversation and pre-fills the recipient and `Re:` subject.
* **Load more, then scroll.** The list starts at 25 rows; extend it before hunting for an older conversation.
* **Verify WhatsApp before relying on it.** The WhatsApp badge tells you a contact's number is verified and reachable on that channel.

## Troubleshooting

| Symptom | Cause | Fix |
| - | - | - |
| An expected conversation is missing from the list | It is older than the loaded page | Click **Load more** to extend the list, or open it directly by URL |
| Instructor cannot see a member's message | Instructors are scoped to their own clubs' members | Confirm the member belongs to a club the instructor teaches at; an admin sees the full org inbox |
| A new reply did not appear | The WebSocket event was missed or the tab was backgrounded | Reload the inbox; the list refetches on load |
| Compose or reply is unavailable | Missing a `messages.create` permission | Grant the relevant messaging permission via roles and permissions |
| A row shows the sender instead of a recipient | It is an inbound, member-initiated conversation with no stored recipients | Expected - the inbox falls back to the sender's identity for inbound threads |
| Delivery looks stuck at "sent" | Per-recipient delivery detail is not shown in the list | Delivery and engagement status are tracked on the record via SendGrid/Twilio webhooks, not surfaced in the row |

## Related

* [Compose](/inbox/compose) - The send and reply flow the right pane drives.
* [Templates](/settings/templates) - Templates the compose pane reads from.
* [Inbox overview](/inbox/overview) - How the inbox fits with automations and AI replies.
* [Automations](/marketing/automations) - Automated, trigger-based sends that also land in the inbox.


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