# Send RCS Message

> Embed an interactive RCS message composer into your application

The RCS message embed enables customers to preview and send RCS messages directly from your website. Perfect for sending demos.

![Send RCS Message](/media/send-rcs-message.png)

## Step 1: Backend

Create an endpoint that requests a signed token from Pinnacle. Configure the display message and send permissions.

  ### server.ts
    ```typescript
    import 'dotenv/config';
    import express from 'express';

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

    app.get('/api/get-send-rcs-message-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({
          // required
          agentId: process.env.AGENT_ID!,
          scopes: ['MESSAGES.SEND'],
          configuredMessage: {
            // required
            agentName: "Your Brand",
            agentIconUrl: "https://example.com/icon.png",
            title: "Message Title",
            subtitle: "Message Subtitle",
            basicText: "Your message content",
            consentText: "Message and data rates may apply.",
            termsUrl: "https://example.com/terms",
            privacyUrl: "https://example.com/privacy",

            // optional
            imageUrl: "https://example.com/image.jpg",
            videoUrl: "https://example.com/video.mp4",
            pdfUrl: "https://example.com/document.pdf",
            pdfSize: 10,
            quickReplies: [
              { type: 'trigger', title: 'Shop Now', payload: 'shop_action' },
              { type: 'openUrl', title: 'Learn More', payload: 'https://example.com' },
              { type: 'call', title: 'Call Support', payload: '+14155551234' },
              {
                type: 'sendLocation',
                title: 'Get Directions',
                latLong: { lat: 37.7749, lng: -122.4194 },
                name: 'Store Location'
              },
              { type: 'requestUserLocation', title: 'Find Nearby' },
              {
                type: 'scheduleEvent',
                title: 'Add to Calendar',
                eventStartTime: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
                eventEndTime: new Date(Date.now() + 25 * 60 * 60 * 1000).toISOString(),
                eventTitle: 'Product Demo',
              }
            ]
          }
        })
      });

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

    app.listen(8080, () => {
      console.log('Server running at http://localhost:8080');
    });
    ```
  
  ### package.json
    ```json
    {
      "name": "rcs-embed-demo",
      "version": "1.0.0",
      "type": "module",
      "scripts": {
        "dev": "tsx watch server.ts",
        "start": "tsx server.ts"
      },
      "dependencies": {
        "dotenv": "^16.4.7",
        "express": "^5.2.1"
      },
      "devDependencies": {
        "@types/express": "^5.0.6",
        "@types/node": "^20",
        "tsx": "^4.19.3",
        "typescript": "^5"
      }
    }
    ```
  
  ### .env.example
    ```bash
    # https://app.pinnacle.sh/dashboard/development/api-keys
    PINNACLE_API_KEY=pnclk_your_api_key_here

    # https://app.pinnacle.sh/dashboard/agents
    AGENT_ID=agent_XXXXXXXXXXXX
    ```
  

### Schema

| Field | Type | Required | Description |
|---|---|---|---|
| `agentId` | `string` | Yes | Your RCS agent ID |
| `configuredMessage` | `object` | Yes | Message content and layout configuration |
| `scopes` | `string[]` | Yes | Permissions granted to the token |

<br />

  ### configuredMessage
    | Field | Type | Required | Description |
    |---|---|---|---|
    | `agentName` | `string` | Yes | Display name for your RCS agent |
    | `agentIconUrl` | `string` | Yes | URL to your agent's icon image |
    | `title` | `string` | Yes | Card title for rich messages |
    | `subtitle` | `string` | Yes | Supporting text under the title |
    | `basicText` | `string` | Yes | Plain text content for simple messages |
    | `consentText` | `string` | Yes | Legal consent disclosure text |
    | `termsUrl` | `string` | Yes | Link to your terms of service |
    | `privacyUrl` | `string` | Yes | Link to your privacy policy |
    | `imageUrl` | `string` | No | Image URL for rich media messages |
    | `videoUrl` | `string` | No | Video URL for rich media messages |
    | `pdfUrl` | `string` | No | PDF URL for rich media messages |
    | `pdfSize` | `number` | No | PDF file size in KB |
    | `quickReplies` | `RichButton[]` | No | Array of [RichButton](/api-reference/messages/send-rcs#request-body.applicationjson.body.quickReplies) objects (max 10) |

    **Info:**
      Maximum 10 quick replies per message. See the [RCS API reference](/api-reference/messages/send-rcs#request-body.applicationjson.body.quickReplies) for all available quick reply types.
    
  
  ### scopes
    | Scopes | Description |
    |---|---|
    | `MESSAGES.SEND` | Permission to send RCS messages |
  

## Step 2: Frontend

Add the iframe to your page. Subscribe to the `message` event to listen for `RCS_WIDGET_READY`, then send `INIT_SEND_DEMO` with your signed token to initialize the embed.

```html
<!-- Other page content -->

<iframe
  id="send_rcs"
  src="https://embed.pinnacle.sh/embed/v2/send-rcs-message"
  style="width: 100vw; height: 100vh; border: none;">
</iframe>

<!-- Other page content -->

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

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

    if (event.data.type === 'RCS_WIDGET_READY') {
      // Fetch token from your backend
      const res = await fetch('/api/get-send-rcs-message-token');
      const { signedToken } = await res.json();

      // Initialize the widget
      iframe.contentWindow.postMessage({
        type: 'INIT_SEND_DEMO',             // required
        signedToken: signedToken,           // required
        primaryColor: '#16a34a'
      }, 'https://embed.pinnacle.sh');
    }
  });
</script>

<!-- Other page content -->
```

### Events

| Field | Type | Description |
|---|---|---|
| `INIT_SEND_DEMO` | `postMessage` | Send signed token and configuration to initialize the widget |
| `RCS_WIDGET_READY` | `event` | Iframe has loaded and is ready to receive configuration |

<br />

  ### INIT_SEND_DEMO
    | Field | Type | Required | Description |
    |---|---|---|---|
    | `type` | `"INIT_SEND_DEMO"` | Yes | Message type identifier |
    | `signedToken` | `string` | Yes | JWT token from your backend |
    | `primaryColor` | `string` | No | Primary color for the widget (defaults to `#16a34a`) |
  
  ### RCS_WIDGET_READY
    Emitted by the iframe when it has loaded and is ready to receive configuration. Listen for this event before sending `INIT_SEND_DEMO`.
  

## Complete Integration

  ### index.html
    ```html
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>RCS Message Demo</title>
    </head>
    <body>
      <iframe
        id="send_rcs"
        src="https://embed.pinnacle.sh/embed/v2/send-rcs-message"
        style="width: 100vw; height: 100vh; border: none;">
      </iframe>

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

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

          if (event.data.type === 'RCS_WIDGET_READY') {
            // Fetch token from your backend
            const res = await fetch('/api/get-send-rcs-message-token');
            const { signedToken } = await res.json();

            // Initialize the widget
            iframe.contentWindow.postMessage({
              type: 'INIT_SEND_DEMO',             // required
              signedToken: signedToken,           // required
              primaryColor: '#16a34a'
            }, 'https://embed.pinnacle.sh');
          }
        });
      </script>
    </body>
    </html>
    ```
  
  ### server.ts
    ```typescript
    import 'dotenv/config';
    import express from 'express';
    import path from 'path';
    import { fileURLToPath } from 'url';

    const __filename = fileURLToPath(import.meta.url);
    const __dirname = path.dirname(__filename);

    const app = express();
    app.use(express.json());
    app.use(express.static('public'));

    app.get('/', (req, res) => {
      res.sendFile(path.join(__dirname, 'index.html'));
    });

    app.get('/api/get-send-rcs-message-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({
          // required
          agentId: process.env.AGENT_ID!,
          scopes: ['MESSAGES.SEND'],
          configuredMessage: {
            // required
            agentName: "Your Brand",
            agentIconUrl: "https://example.com/icon.png",
            title: "Message Title",
            subtitle: "Message Subtitle",
            basicText: "Your message content",
            consentText: "Message and data rates may apply.",
            termsUrl: "https://example.com/terms",
            privacyUrl: "https://example.com/privacy",

            // optional
            imageUrl: "https://example.com/image.jpg",
            videoUrl: "https://example.com/video.mp4",
            pdfUrl: "https://example.com/document.pdf",
            pdfSize: 10,
            quickReplies: [
              { type: 'trigger', title: 'Shop Now', payload: 'shop_action' },
              { type: 'openUrl', title: 'Learn More', payload: 'https://example.com' },
              { type: 'call', title: 'Call Support', payload: '+14155551234' },
              {
                type: 'sendLocation',
                title: 'Get Directions',
                latLong: { lat: 37.7749, lng: -122.4194 },
                name: 'Store Location'
              },
              { type: 'requestUserLocation', title: 'Find Nearby' },
              {
                type: 'scheduleEvent',
                title: 'Add to Calendar',
                eventStartTime: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
                eventEndTime: new Date(Date.now() + 25 * 60 * 60 * 1000).toISOString(),
                eventTitle: 'Product Demo',
              }
            ]
          }
        })
      });

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

    app.listen(8080, () => {
      console.log('Server running at http://localhost:8080');
    });
    ```
  
  ### package.json
    ```json
    {
      "name": "rcs-embed-demo",
      "version": "1.0.0",
      "type": "module",
      "scripts": {
        "dev": "tsx watch server.ts",
        "start": "tsx server.ts"
      },
      "dependencies": {
        "dotenv": "^16.4.7",
        "express": "^5.2.1"
      },
      "devDependencies": {
        "@types/express": "^5.0.6",
        "@types/node": "^20",
        "tsx": "^4.19.3",
        "typescript": "^5"
      }
    }
    ```
  
  ### .env.example
    ```bash
    # https://app.pinnacle.sh/dashboard/development/api-keys
    PINNACLE_API_KEY=pnclk_your_api_key_here

    # https://app.pinnacle.sh/dashboard/agents
    AGENT_ID=agent_XXXXXXXXXXXX
    ```
