Pinnacle

Inbox

Embed a full-featured messaging inbox into your application

The inbox embed gives your users a complete RCS and SMS messaging experience — conversations, message history, rich media, and real-time updates.

Send RCS Demo

Step 1: Backend

Create an endpoint that requests a signed JWT from Pinnacle. Control which conversations and UI appear in the inbox.

TypeScript
import 'dotenv/config';
import express from 'express';

const app = express();
app.use(express.json());

app.post('/api/get-inbox-token', async (req, res) => {
  const response = await fetch('https://api.pinnacle.sh/embed/get-token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'pinnacle-api-key': process.env.PINNACLE_API_KEY!
    },
    body: JSON.stringify({
      inboxFilter: {},  // optional — pass brandIds or senders to filter, or {} for a team-level inbox
      scopes: [
        'CONVERSATIONS.LIST',       // required
        'CONVERSATIONS.MESSAGES',    // required
        'CONVERSATIONS.SEND',
        'CONVERSATIONS.CREATE',
        'UPLOAD_FILE',
        'REALTIME.CONNECTION'
      ]
    })
  });

  const { signedToken } = await response.json();
  res.json({ signedToken });
});

app.listen(8080, () => {
  console.log('Server running at http://localhost:8080');
});

Schema

FieldTypeRequiredDescription
inboxFilterobjectYesFilter conversations by brandIds or senders, or pass {} for a team-level inbox
scopesstring[]YesPermissions granted to the token

Set inboxFilter to control which conversations appear in the inbox.

FieldTypeDescription
brandIdsstring[]Show conversations for the specified brand IDs.
sendersstring[]Show conversations for specific RCS agent IDs or phone numbers in E.164 format (e.g. +14155550123).

Choose one filter

Use brandIds or senders, not both. For all team conversations, use inboxFilter: {}.

Step 2: Frontend

Add the iframe to your page. Subscribe to the message event to listen for INBOX_READY, then send INIT_INBOX with your signed token to initialize the inbox.

HTML
<!-- Other page content -->

<iframe
  id="inbox"
  src="https://embed.pinnacle.sh/embed/v2/inbox"
  style="width: 100%; height: 100vh; border: none;">
</iframe>

<!-- Other page content -->

<script>
  const iframe = document.getElementById('inbox');

  window.addEventListener('message', async (event) => {
    if (event.origin !== 'https://embed.pinnacle.sh') return;

    if (event.data.type === 'INBOX_READY') {
      // Fetch token from your backend
      const res = await fetch('/api/get-inbox-token', { method: 'POST' });
      const { signedToken } = await res.json();

      // Initialize the inbox
      iframe.contentWindow.postMessage({
        type: 'INIT_INBOX',             // required
        signedToken: signedToken,       // required
        primaryColor: '#16a34a'
      }, 'https://embed.pinnacle.sh');
    }

    if (event.data.type === 'INBOX_ERROR') {
      // handle iframe init failure here
    }
  });
</script>

<!-- Other page content -->

Events

FieldTypeDescription
INIT_INBOXpostMessageSend signed token and configuration to initialize the inbox
INBOX_READYeventIframe has loaded and is ready to receive configuration
INBOX_ERROReventValidation or initialization error occurred

FieldTypeRequiredDescription
type"INIT_INBOX"YesMessage type identifier
signedTokenstringYesJWT token from your backend
primaryColorstringNoPrimary color for the inbox (defaults to #16a34a)

Complete Integration

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Inbox</title>
</head>
<body>
  <iframe
    id="inbox"
    src="https://embed.pinnacle.sh/embed/v2/inbox"
    style="width: 100%; height: 100vh; border: none;">
  </iframe>

  <script>
    const iframe = document.getElementById('inbox');

    window.addEventListener('message', async (event) => {
      if (event.origin !== 'https://embed.pinnacle.sh') return;

      if (event.data.type === 'INBOX_READY') {
        // Fetch token from your backend
        const res = await fetch('/api/get-inbox-token', { method: 'POST' });
        const { signedToken } = await res.json();

        // Initialize the inbox
        iframe.contentWindow.postMessage({
          type: 'INIT_INBOX',             // required
          signedToken: signedToken,       // required
          primaryColor: '#16a34a'
        }, 'https://embed.pinnacle.sh');
      }

      if (event.data.type === 'INBOX_ERROR') {
        // handle iframe init failure here
      }
    });
  </script>
</body>
</html>
Pinnacle referenceAsk Pinnacle

Get a sourced answer from the published documentation.

ViewingPinnacle documentation

Conversations are saved for analysis.

Try asking