npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zyphr-dev/webhook-portal

v0.1.3

Published

Embeddable webhook management portal for Zyphr WaaS

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).

npm version license

Installation

npm install @zyphr-dev/webhook-portal
# or
yarn add @zyphr-dev/webhook-portal

Then 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

  1. Your server requests a portal token from the Zyphr API, scoped to a specific application
  2. Your frontend passes that token to <WebhookPortal />
  3. The portal authenticates directly with the Zyphr API using the token
  4. 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 failed or exhausted deliveries

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