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

# Embeddable UI Components

> Add a messaging inbox, conversation view, and dialpad to your app using Surge's embeddable UI components and JWT auth.

Surge provides ready-to-use UI components you can embed directly into your web application. They connect to Surge's messaging backend and give your users an inbox, conversation view, and unread count — without building any of that yourself.

Components are served from `embed.surge.app`.

## Available components

* **Inbox**: a list of all conversations for the current user, sortable and filterable
* **Conversation**: a single threaded conversation with send capability
* **Unread count**: a badge showing how many unread conversations the user has
* **Phone (dialpad)**: a voice dialer for outbound calls (voice-enabled accounts)

## Authentication

Each component mount requires a signed JWT. The JWT identifies which Surge account and user the component is showing data for.

<Warning>
  **Publishable tokens are deprecated.** If you're currently using a publishable token, migrate to JWT authentication. See [Deprecation Notices](../resources/deprecations).
</Warning>

### Two ways to get a JWT

**Option 1: use the token endpoint (simpler)**

Call the user token endpoint from your server, then pass the resulting token to the component:

<CodeGroup>
  ```python Python theme={null}
  from surge import Surge

  surge = Surge()

  response = surge.users.create_token(user_id="{user_id}")
  token = response.token
  ```

  ```typescript TypeScript theme={null}
  import Surge from "@surgeapi/node";

  const surge = new Surge();

  const response = await surge.users.createToken("{user_id}");
  const token = response.token;
  ```

  ```ruby Ruby theme={null}
  require "surge_api"

  surge = SurgeAPI::Client.new

  response = surge.users.create_token("{user_id}")
  token = response.token
  ```

  ```elixir Elixir theme={null}
  client = Surge.Client.new(System.get_env("SURGE_API_KEY"))

  # create_token/3 requires an empty params map and returns the JWT directly
  {:ok, token} = Surge.Users.create_token(client, "{user_id}", %{})
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.surge.app/users/{user_id}/tokens \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json"
  ```
</CodeGroup>

```json theme={null}
{
  "token": "eyJhbGciOiJFZERTQSIsImtpZCI6InNnbl8wMWouLi4ifQ..."
}
```

<Tip>
  The token is short-lived. Generate a fresh one on each page load or use a refresh mechanism.
</Tip>

**Option 2: create and sign your own JWT**

If you need more control over JWT claims (expiration, scopes), generate a signing key in the dashboard (**Settings → Signing Keys**) and sign your own JWTs. The key is an Ed25519 key pair: your private key stays on your server, and Surge uses the public key to verify tokens.

```python theme={null}
import jwt  # PyJWT
from datetime import datetime, timedelta

payload = {
    "sub": surge_user_id,
    "iat": datetime.utcnow(),
    "exp": datetime.utcnow() + timedelta(hours=1),
}

token = jwt.encode(payload, private_key, algorithm="EdDSA", headers={"kid": key_id})
```

## Mounting a component

Each component is embedded as an iframe served from `embed.surge.app`, with the token passed as a query parameter:

```html theme={null}
<iframe
  src="https://embed.surge.app/conversations?token={USER_JWT}"
></iframe>
```

See the component-specific pages for each component's URL, parameters, and events.

## Next steps

<CardGroup cols={2}>
  <Card title="Working with Users" icon="user" href="./users">
    How Users are provisioned and attributed to messages.
  </Card>

  <Card title="Inbox component" icon="inbox" href="./inbox">
    URL parameters and events for the conversation list.
  </Card>

  <Card title="Conversation component" icon="comment" href="./conversation">
    Mounting a single thread inside your own page.
  </Card>

  <Card title="Unread Count component" icon="bell" href="./unread-count">
    Badge integration for navigation chrome.
  </Card>
</CardGroup>
