@unthread-io/portal-embed-sdk
v0.0.2
Published
SDK for embedding the Unthread customer portal in your application
Readme
@unthread-io/portal-embed-sdk
SDK for embedding the Unthread customer portal in your application. Supports vanilla JavaScript, React, and any framework.
Installation
npm install @unthread-io/portal-embed-sdkQuick Start
React
import { UnthreadPortal } from '@unthread-io/portal-embed-sdk/react';
function SupportPage() {
const getToken = async () => {
const res = await fetch('/api/portal-token');
const { jwt } = await res.json();
return jwt;
};
return (
<UnthreadPortal
baseUrl="https://help.acme.unthread.io"
getToken={getToken}
onAuthenticated={() => console.log('Portal ready')}
style={{ height: 600 }}
/>
);
}Using the hook for programmatic control
import { UnthreadPortal, useUnthreadPortal } from '@unthread-io/portal-embed-sdk/react';
function SupportPage() {
const portal = useUnthreadPortal();
return (
<div>
<nav>
<button onClick={() => portal.showConversations()}>My Tickets</button>
<button onClick={() => portal.showNewTicket()}>Submit Ticket</button>
<button onClick={() => portal.showArticle('getting-started')}>Help</button>
</nav>
<UnthreadPortal baseUrl="https://help.acme.unthread.io" getToken={getToken} style={{ height: 600 }} />
</div>
);
}Vanilla JavaScript
<div id="portal" style="width: 100%; height: 600px;"></div>
<script>
// Queue calls before the script loads
window.UnthreadPortal =
window.UnthreadPortal ||
function () {
(window.UnthreadPortal.q = window.UnthreadPortal.q || []).push(arguments);
};
UnthreadPortal('boot', {
baseUrl: 'https://help.acme.unthread.io',
getToken: function () {
return fetch('/api/portal-token')
.then(function (res) {
return res.json();
})
.then(function (data) {
return data.jwt;
});
},
container: '#portal',
});
</script>
<script src="https://help.acme.unthread.io/embed.js" async></script>ES Module imports
import { boot, showConversations, onAuthenticated } from '@unthread-io/portal-embed-sdk';
await boot({
baseUrl: 'https://help.acme.unthread.io',
getToken: async () => {
const res = await fetch('/api/portal-token');
const { jwt } = await res.json();
return jwt;
},
container: '#portal',
});
onAuthenticated(() => {
console.log('User is authenticated in the portal');
});
showConversations();API Reference
Lifecycle
| Method | Description |
| ------------------ | -------------------------------------------------------------------------- |
| boot(options) | Initialize and render the portal |
| shutdown() | Remove the portal and clean up all state |
| authenticate() | Re-invoke getToken and send the result to the portal (for token refresh) |
| update(userData) | Update user metadata (name, email, etc.) |
| logout() | Clear the portal session |
Navigation
| Method | Description |
| ------------------------------ | -------------------------------- |
| navigate(path) | Navigate to any portal path |
| showHome() | Navigate to the portal home page |
| showConversations() | Show the ticket list |
| showConversation(id) | Open a specific conversation |
| showArticle(slugOrId) | Open a knowledge base article |
| showNewTicket(ticketTypeId?) | Open the ticket submission form |
Events
| Method | Description |
| --------------------------- | ------------------------------------------------------- |
| on(event, callback) | Subscribe to an event. Returns an unsubscribe function. |
| onReady(callback) | Shorthand for on('ready', callback) |
| onAuthenticated(callback) | Shorthand for on('authenticated', callback) |
| onError(callback) | Shorthand for on('error', callback) |
React
| Export | Description |
| --------------------- | ----------------------------------------------------------------- |
| <UnthreadPortal /> | Component that renders the embedded portal |
| useUnthreadPortal() | Hook returning stable references to all navigation/action methods |
Boot Options
| Option | Type | Required | Description |
| ----------- | --------------------------------- | -------- | --------------------------------------------- |
| baseUrl | string | Yes | Portal URL |
| container | string \| HTMLElement | Yes | Where to render (CSS selector or DOM element) |
| getToken | () => string \| Promise<string> | Yes | Callback that returns a signed JWT |
JWT Format
Your backend signs a JWT using the embed secret key (generated in portal admin settings):
{
"email": "[email protected]",
"name": "Jane Doe",
"external_id": "usr_123",
"iat": 1709312400,
"exp": 1709312700
}| Field | Required | Description |
| ------------- | -------- | ------------------------------------------------------------------------------------------------- |
| email | Yes | User's email address. Used to identify the portal account. |
| name | No | Display name shown in the portal. |
| external_id | No | Your internal user ID. Reserved for future use — validated but not currently stored or processed. |
| iat | Yes | Issued-at timestamp (Unix seconds). |
| exp | Yes | Expiration timestamp. Max 5 minutes from iat. |
- Algorithm: HS256
- Max TTL: 5 minutes
