@zyphr-dev/webhook-portal
v0.1.3
Published
Embeddable webhook management portal for Zyphr WaaS
Maintainers
Readme
@zyphr-dev/webhook-portal
An embeddable React component that lets your customers manage their own webhook endpoints and inspect delivery logs — powered by Zyphr WaaS (Webhooks-as-a-Service).
Installation
npm install @zyphr-dev/webhook-portal
# or
yarn add @zyphr-dev/webhook-portalThen import the styles in your app's entry point:
import '@zyphr-dev/webhook-portal/styles.css';Requirements: React 17+ and React DOM 17+
Quick Start
Generate a portal token on your server, then render the portal:
import { WebhookPortal } from '@zyphr-dev/webhook-portal';
import '@zyphr-dev/webhook-portal/styles.css';
function WebhooksPage() {
return (
<WebhookPortal
token={portalToken}
theme={{ mode: 'light' }}
onEndpointCreated={(ep) => console.log('Created:', ep.url)}
/>
);
}Your customers can now create endpoints, subscribe to events, view delivery logs, and retry failed deliveries — all from within your app.
How It Works
- Your server requests a portal token from the Zyphr API, scoped to a specific application
- Your frontend passes that token to
<WebhookPortal /> - The portal authenticates directly with the Zyphr API using the token
- Your customers manage their webhook endpoints without ever leaving your app
Portal Props
<WebhookPortal
token="portal_token_xxx" // Required
baseUrl="https://api.zyphr.dev/v1/waas-portal" // Default
theme={{ mode: 'dark', accent: '#6366f1', borderRadius: 8 }}
locale="en"
preview={false}
className="my-portal"
onEndpointCreated={(endpoint) => {}}
onEndpointUpdated={(endpoint) => {}}
onEndpointDeleted={(endpoint) => {}}
onDeliveryRetried={(deliveryId) => {}}
onError={(error) => {}}
/>| Prop | Type | Default | Description |
|------|------|---------|-------------|
| token | string | — | Required. Portal authentication token |
| baseUrl | string | https://api.zyphr.dev/v1/waas-portal | API base URL |
| theme | PortalTheme | { mode: 'light' } | Theme configuration |
| locale | string | — | Locale identifier (future i18n support) |
| preview | boolean | false | Render with mock data, no API calls |
| className | string | — | CSS class for the portal wrapper |
| onEndpointCreated | (endpoint: PortalEndpoint) => void | — | Fires after an endpoint is created |
| onEndpointUpdated | (endpoint: PortalEndpoint) => void | — | Fires after an endpoint is updated |
| onEndpointDeleted | (endpoint: PortalEndpoint) => void | — | Fires after an endpoint is deleted |
| onDeliveryRetried | (deliveryId: string) => void | — | Fires after a delivery retry is queued |
| onError | (error: Error) => void | — | Fires on any API error |
Theming
Customize the portal's appearance with the theme prop:
<WebhookPortal
token={token}
theme={{
mode: 'dark', // 'light' | 'dark'
accent: '#8b5cf6', // Any CSS color value
borderRadius: 12, // Border radius in pixels
}}
/>| Property | Type | Default | Description |
|----------|------|---------|-------------|
| mode | 'light' \| 'dark' | 'light' | Color scheme |
| accent | string | #6366f1 | Primary accent color |
| borderRadius | number | 8 | Border radius in pixels |
CSS Variables
The portal uses CSS custom properties scoped under .zwp-portal, so styles won't leak into your app. You can override variables directly:
.zwp-portal {
--zwp-accent: #8b5cf6;
--zwp-radius: 12px;
--zwp-bg: #0f0f0f;
--zwp-text: #e5e5e5;
}Available variables:
| Variable | Description |
|----------|-------------|
| --zwp-accent | Primary accent color |
| --zwp-radius | Border radius |
| --zwp-bg | Background color |
| --zwp-bg-secondary | Secondary background (cards, inputs) |
| --zwp-border | Border color |
| --zwp-text | Primary text color |
| --zwp-text-secondary | Secondary/muted text |
| --zwp-input-bg | Input field background |
| --zwp-hover | Hover state background |
| --zwp-font | Font family |
| --zwp-mono | Monospace font family |
Features
Endpoint Management
Your customers can:
- Create endpoints with a URL, description, and event subscriptions
- Pause/resume endpoints without deleting them
- Delete endpoints they no longer need
- Copy signing secrets displayed once at creation time
- Rotate signing secrets for security key rotation
Delivery Logs
For each endpoint, customers can:
- Browse delivery history with pagination (20 per page)
- Filter by status — delivered, failed, exhausted, retrying, pending
- Inspect delivery details — event type, attempt count, HTTP response status, latency
- Retry failed deliveries — requeue
failedorexhausteddeliveries
Status Indicators
Deliveries and endpoints use color-coded badges:
| Status | Color | Meaning |
|--------|-------|---------|
| active / delivered | Green | Healthy |
| paused / retrying / pending | Yellow | Attention needed |
| disabled / failed / exhausted | Red | Action required |
Using the API Hook
For advanced use cases, the usePortalApi hook gives you direct access to the portal API:
import { usePortalApi } from '@zyphr-dev/webhook-portal';
function CustomPortal({ token }: { token: string }) {
const api = usePortalApi({ token });
const loadEndpoints = async () => {
const { endpoints, total } = await api.listEndpoints(20, 0);
console.log(`${total} endpoints:`, endpoints);
};
const createEndpoint = async () => {
const endpoint = await api.createEndpoint({
url: 'https://example.com/webhooks',
events: ['order.created', 'order.updated'],
description: 'Production webhook',
});
// endpoint.secret is only available at creation time
console.log('Signing secret:', endpoint.secret);
};
const retryDelivery = async (endpointId: string, deliveryId: string) => {
await api.retryDelivery(endpointId, deliveryId);
};
}API Methods
| Method | Description |
|--------|-------------|
| listEventTypes() | Get available event types |
| listEndpoints(limit?, offset?) | List endpoints with pagination |
| createEndpoint({ url, events, description? }) | Create a new endpoint (returns signing secret) |
| updateEndpoint(id, { url?, events?, status?, description? }) | Update an endpoint |
| deleteEndpoint(id) | Delete an endpoint |
| rotateSecret(id) | Generate a new signing secret |
| listDeliveries(endpointId, { limit?, offset?, status? }) | List deliveries with filtering |
| getDelivery(endpointId, deliveryId) | Get delivery details (includes payload and response) |
| retryDelivery(endpointId, deliveryId) | Retry a failed/exhausted delivery |
All methods throw an Error on HTTP failure with the server's error message.
Types
All types are exported for TypeScript consumers:
import type {
WebhookPortalProps,
PortalTheme,
PortalEventType,
PortalEndpoint,
PortalEndpointWithSecret,
PortalDelivery,
PortalDeliveryDetail,
} from '@zyphr-dev/webhook-portal';Key Types
interface PortalEndpoint {
id: string;
url: string;
description?: string;
events: string[];
status: 'active' | 'paused' | 'disabled';
retry_policy?: { max_attempts?: number; intervals?: number[] };
consecutive_failures?: number;
last_failure_at?: string;
disabled_at?: string;
disabled_reason?: string;
created_at: string;
updated_at: string;
}
interface PortalEndpointWithSecret extends PortalEndpoint {
secret: string; // Only returned at creation time
}
interface PortalDelivery {
id: string;
event_id: string;
event_type: string;
status: 'pending' | 'delivering' | 'delivered' | 'failed' | 'retrying' | 'exhausted';
attempts: number;
max_attempts: number;
last_response_status?: number;
latency_ms?: number;
last_error?: string;
first_attempted_at?: string;
last_attempted_at?: string;
completed_at?: string;
created_at: string;
}
interface PortalDeliveryDetail extends PortalDelivery {
payload?: Record<string, unknown>;
last_response_body?: string;
}
interface PortalEventType {
event_type: string;
name: string;
description?: string;
category?: string;
example_payload?: Record<string, unknown>;
}Preview Mode
Pass preview={true} to render the portal with mock data and no API calls. Useful for prototyping, testing themes, or building documentation:
<WebhookPortal token="preview" preview={true} theme={{ mode: 'dark' }} />Bundle
Dual-format build — works with both ESM and CommonJS bundlers:
- ESM:
dist/index.js - CommonJS:
dist/index.cjs - Types:
dist/index.d.ts - Styles:
dist/styles.css
Zero runtime dependencies beyond React.
License
MIT
