Embedded Portal
The Embedded Portal lets you drop a complete webhook management UI into your application. Your customers can create endpoints, subscribe to events, view delivery logs, and retry failed deliveries — all within your app's interface.
The Embedded Portal is available on Starter plans and above.
Live Preview
Try the portal below — customize the theme, accent color, and border radius to see how it looks in your application.
Overview
The portal is available in two integration modes:
| Mode | Best For | Advantages |
|---|---|---|
| React Component | React/Next.js apps | Native integration, callbacks, full control |
| iFrame | Any web app (non-React) | Zero dependencies, works everywhere |
Both modes use the same portal token for authentication and the same backend API (/v1/waas-portal/).
Portal Token
Before embedding the portal, generate a portal token scoped to a specific tenant. This token authenticates your customer's access and controls which event types they can see.
Via API
curl -X POST https://api.zyphr.dev/v1/waas/applications/{app_id}/portal/token \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tenant_id": "tenant_abc",
"allowed_event_types": ["order.created", "order.updated"],
"expires_in": 3600,
"theme": { "mode": "dark", "accent": "#6366f1" }
}'
Via Dashboard
- Navigate to Webhooks-as-a-Service → Configure in the sidebar
- Click on your application
- Go to the Endpoints tab
- Use the Generate Portal Token action for a specific tenant
The token is a JWT containing:
tenant_id— scopes all operations to this tenantapplication_id— scopes to this WaaS applicationallowed_event_types— optional filter for visible event typestheme— portal appearance settingsexpires_at— token expiration
React Component
Install the portal package:
npm install @zyphr/webhook-portal
# or
yarn add @zyphr/webhook-portal
Basic Usage
import { WebhookPortal } from '@zyphr/webhook-portal';
function CustomerWebhookSettings() {
const [portalToken, setPortalToken] = useState<string | null>(null);
useEffect(() => {
// Fetch portal token from your backend
fetch('/api/webhook-portal-token', {
method: 'POST',
body: JSON.stringify({ tenant_id: currentUser.tenantId }),
})
.then(res => res.json())
.then(data => setPortalToken(data.token));
}, []);
if (!portalToken) return <div>Loading...</div>;
return (
<WebhookPortal
token={portalToken}
theme={{
mode: 'dark',
accent: '#6366f1',
borderRadius: 8,
}}
locale="en"
onEndpointCreated={(endpoint) => {
console.log('Endpoint created:', endpoint);
}}
onEndpointDeleted={(endpoint) => {
console.log('Endpoint deleted:', endpoint);
}}
/>
);
}
Props
| Prop | Type | Required | Description |
|---|---|---|---|
token | string | Yes | Portal token from token generation API |
preview | boolean | No | Render with mock data and no API calls (for demos/previews) |
theme | object | No | { mode: 'light' | 'dark', accent: string, borderRadius: number } |
locale | string | No | Locale code (default: en) |
onEndpointCreated | function | No | Callback when an endpoint is created |
onEndpointDeleted | function | No | Callback when an endpoint is deleted |
onEndpointUpdated | function | No | Callback when an endpoint is updated |
onDeliveryRetried | function | No | Callback when a delivery is retried |
onError | function | No | Callback when an error occurs |
className | string | No | CSS class for the portal container |
iFrame Embed
For non-React applications, embed the portal as an iFrame.
Basic Usage
<iframe
id="zyphr-portal"
src="https://portal.zyphr.dev/?token={portal_token}&theme=dark"
width="100%"
height="600"
style="border: none; border-radius: 8px;"
></iframe>
Query Parameters
| Parameter | Description | Example |
|---|---|---|
token | Portal token (required) | token=eyJhbG... |
theme | Color mode | theme=dark or theme=light |
accent | Accent color (hex) | accent=%236366f1 |
locale | Locale code | locale=en |
baseUrl | Custom API base URL | baseUrl=https://api.zyphr.dev/v1/waas-portal |
postMessage API
The iFrame communicates with the parent page via postMessage.
Events emitted by the portal (listen on your parent page):
window.addEventListener('message', (event) => {
// Verify origin
if (event.origin !== 'https://portal.zyphr.dev') return;
switch (event.data.type) {
case 'zyphr:ready':
console.log('Portal loaded');
break;
case 'zyphr:endpoint:created':
console.log('Endpoint created:', event.data.payload);
break;
case 'zyphr:endpoint:updated':
console.log('Endpoint updated:', event.data.payload);
break;
case 'zyphr:endpoint:deleted':
console.log('Endpoint deleted:', event.data.payload);
break;
case 'zyphr:delivery:retried':
console.log('Delivery retried:', event.data.payload);
break;
case 'zyphr:error':
console.error('Portal error:', event.data.payload);
break;
}
});
Commands you can send to the portal:
const iframe = document.getElementById('zyphr-portal');
// Refresh the portal (reloads all data)
iframe.contentWindow.postMessage({ type: 'zyphr:refresh' }, 'https://portal.zyphr.dev');
// Navigate to a specific section (reserved for future use)
iframe.contentWindow.postMessage(
{ type: 'zyphr:navigate', payload: { section: 'endpoints' } },
'https://portal.zyphr.dev'
);
Portal Features
Both the React component and iFrame provide:
- Event Type Browser — View available event types with descriptions and example payloads
- Endpoint Management — Create, edit, pause, and delete webhook endpoints
- Event Subscriptions — Choose which events each endpoint receives
- Delivery Logs — View delivery history with status, latency, and response details
- Retry Failed Deliveries — One-click retry for failed or exhausted deliveries
- Test Events — Send test events to verify endpoint configuration
- Secret Rotation — Rotate the signing secret with a reveal-once UI
- Health Indicators — Visual indicators for endpoint health and circuit breaker state
Theming
Customize the portal appearance to match your application:
{
"mode": "dark",
"accent": "#6366f1",
"border_radius": 8
}
| Property | Type | Default | Description |
|---|---|---|---|
mode | 'light' | 'dark' | 'light' | Color mode |
accent | string | '#228be6' | Primary accent color (hex) |
border_radius | number | 4 | Border radius in pixels |
Security
- Portal tokens are short-lived JWTs (default: 1 hour, max: 24 hours)
- All portal API requests are scoped to the authenticated tenant
- Tenants cannot see or modify other tenants' endpoints or deliveries
- The portal token does not grant access to the main WaaS management API
Next Steps
- Webhooks-as-a-Service Guide — Full WaaS setup guide
- API Reference — Portal API documentation