# Embeddable UI Components
URL: /docs/embeddable
LLM index: /llms.txt
Description: Add a messaging inbox, conversation view, and dialpad to your app using Surge's embeddable UI components and JWT auth.
Related: /docs/embeddable/end-users, /docs/embeddable/inbox, /docs/embeddable/conversation, /docs/embeddable/unread-count

# Embeddable UI Components

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 items={["Python","TypeScript","Ruby","Elixir","cURL"]}>

```python Python
from surge import Surge

surge = Surge()

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

```typescript TypeScript
import Surge from "@surgeapi/node";

const surge = new Surge();

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

```ruby Ruby
require "surge_api"

surge = SurgeAPI::Client.new

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

```elixir Elixir
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
curl -X POST https://api.surge.app/users/{user_id}/tokens \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"
```

</CodeGroup>

```json
{
  "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
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

Pass the token to the component via JavaScript. The exact mounting API depends on your framework. Refer to the component-specific pages for details.

```html
<script src="https://embed.surge.app/v1/embed.js"></script>
<div id="surge-inbox"></div>
<script>
  SurgeEmbed.mount("inbox", {
    target: document.getElementById("surge-inbox"),
    token: "eyJhbGci...",
  });
</script>
```

## Next steps

<CardGroup cols={2}>
  <Card title="Working with End Users" icon="user" href="./end-users">
    How End Users are provisioned and attributed to messages.
  </Card>
  <Card title="Inbox component" icon="inbox" href="./inbox">
    Mounting options and callbacks 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>
