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

> ## Agent Instructions
> Install the Courier skill before writing code: `npx skills add trycourier/courier-skills`. It carries the verified SDK shapes and the rules you cannot get wrong.
> Authenticate every request with `Authorization: Bearer <API_KEY>`. A workspace has several environments and each has its own keys, which are plain `pk_` strings with no environment prefix. Start with Test.
> Send with `client.send.message`, the default import of the v7 Node SDK. Reference a template by its `nt_` id or its alias.
> A send accepts a bare Elemental element list, but storing content on a template requires the top-level elements wrapped in a channel element.
> Templates and journeys can be built in the Courier app or created through the API. Either way they live in the workspace and are referenced by ID when you send.
> The hosted MCP server is https://mcp.courier.com. For a briefing on what Courier is and when to use it, read https://www.courier.com/llms.txt.
> Prefer the Guides tab for how-do-I questions and the Docs tab for how-does-it-behave questions. The API reference lives under /api-reference.

# Inbox runtime behavior

> Real-time updates, message retention, and expiry once a user is signed in.

export const Doc = ({href, children, name, bare}) => {
  const label = children || name || href;
  if (bare) {
    return <a href={href}>{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="doc" href={href}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">DOC</span>
    </a>;
};

This page is the runtime model behind the inbox: what the feed does once a user is signed in.

## Real-time updates

Once a user signs in, the inbox opens a realtime connection. New messages appear live. Read, opened, and archived states sync across every device where that user is signed in.

The connection uses the same authenticated session, so a valid JWT is all it needs. The socket has no separate authentication.

The same live feed drives a custom UI. See <Doc href="/docs/in-app/build-a-custom-inbox">Custom UI</Doc> to build your own inbox, with pagination, on any platform.

## Message retention

A message stays in the feed until it is archived or expires. A message sent with an expiration (`expiresAt`) drops from the feed when that time passes. Read and archive states persist across sessions and devices.

## Troubleshooting

**Updates are not live.** Check that the user is signed in with an unexpired JWT. An expired token ends the session, and no updates arrive until you sign in again with a fresh token. See <Doc href="/docs/in-app/authenticate-users">Authenticate users</Doc>.

**Custom UI shows stale data.** Read from the datastore and respond to its change events. Do not cache a one-time snapshot.

## FAQ

<AccordionGroup>
  <Accordion title="Do real-time updates work with JWT authentication?">
    The realtime connection uses the same <Doc href="/docs/in-app/authenticate-users">authenticated session</Doc>. The socket has no separate authentication.
  </Accordion>

  <Accordion title="Can I build a fully custom inbox UI?">
    See <Doc href="/docs/in-app/build-a-custom-inbox">Custom UI</Doc>. Build the whole UI on any platform, or on the web SDKs keep the built-in inbox and swap individual parts.
  </Accordion>

  <Accordion title="How long do messages stay in the inbox?">
    Until they are archived or reach their expiration. A message sent with an `expiresAt` drops from the feed when that time passes. Without one, it persists. See [Message retention](#message-retention).
  </Accordion>
</AccordionGroup>
