New:Microsoft Teams Notifications Are Now Available in Socket.Learn more →
Get Started

@webhook-platform/node

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@webhook-platform/node

Official Node.js SDK for Hookflow — reliable webhook infrastructure

Source
npmnpm
Version
2.2.1
Version published
Weekly downloads
7
-84.09%
Maintainers
1
Weekly downloads
 
Created
Source

@webhook-platform/node

Official Node.js SDK for Hookflow.

Installation

npm install @webhook-platform/node

Quick Start

import { Hookflow } from '@webhook-platform/node';

const client = new Hookflow({
  apiKey: 'wh_live_your_api_key',
  baseUrl: 'http://localhost:8080', // optional, defaults to localhost
});

// Send an event
const event = await client.events.send({
  type: 'order.completed',
  data: {
    orderId: 'ord_12345',
    amount: 99.99,
    currency: 'USD',
  },
});

console.log(`Event created: ${event.eventId}`);
console.log(`Deliveries created: ${event.deliveriesCreated}`);

API Reference

Events

// Send event with idempotency key
const event = await client.events.send(
  { type: 'order.completed', data: { orderId: '123' } },
  'unique-idempotency-key'
);

Endpoints

// Create endpoint
const endpoint = await client.endpoints.create(projectId, {
  url: 'https://api.example.com/webhooks',
  description: 'Production webhooks',
  enabled: true,
});

// List endpoints
const endpoints = await client.endpoints.list(projectId);

// Update endpoint
await client.endpoints.update(projectId, endpointId, {
  enabled: false,
});

// Delete endpoint
await client.endpoints.delete(projectId, endpointId);

// Rotate secret
const updated = await client.endpoints.rotateSecret(projectId, endpointId);
console.log(`New secret: ${updated.secret}`);

// Test endpoint connectivity
const result = await client.endpoints.test(projectId, endpointId);
console.log(`Test ${result.success ? 'passed' : 'failed'}: ${result.latencyMs}ms`);

Subscriptions

// Subscribe endpoint to an event type
const subscription = await client.subscriptions.create(projectId, {
  endpointId: endpoint.id,
  eventType: 'order.completed',
  enabled: true,
});

// List subscriptions
const subscriptions = await client.subscriptions.list(projectId);

// Update subscription
await client.subscriptions.update(projectId, subscriptionId, {
  eventType: 'order.shipped',
  enabled: true,
});

// Delete subscription
await client.subscriptions.delete(projectId, subscriptionId);

Deliveries

// List deliveries with filters
const deliveries = await client.deliveries.list(projectId, {
  status: 'FAILED',
  page: 0,
  size: 20,
});

console.log(`Total failed: ${deliveries.totalElements}`);

// Get delivery attempts
const attempts = await client.deliveries.getAttempts(deliveryId);
for (const attempt of attempts) {
  console.log(`Attempt ${attempt.attemptNumber}: ${attempt.httpStatus} (${attempt.latencyMs}ms)`);
}

// Replay failed delivery
await client.deliveries.replay(deliveryId);

Incoming Webhooks

Receive, validate, and forward webhooks from third-party providers (Stripe, GitHub, Twilio, etc.).

Incoming Sources

// Create an incoming source with HMAC verification
const source = await client.incomingSources.create(projectId, {
  name: 'Stripe Webhooks',
  slug: 'stripe',
  providerType: 'STRIPE',
  verificationMode: 'HMAC_GENERIC',
  hmacSecret: 'whsec_...',
  hmacHeaderName: 'Stripe-Signature',
});

console.log(`Ingress URL: ${source.ingressUrl}`);

// List sources
const sources = await client.incomingSources.list(projectId);

// Update source
await client.incomingSources.update(projectId, sourceId, {
  name: 'Stripe Production',
  rateLimitPerSecond: 100,
});

// Delete source
await client.incomingSources.delete(projectId, sourceId);

Incoming Destinations

// Add a forwarding destination
const dest = await client.incomingSources.createDestination(projectId, sourceId, {
  url: 'https://your-api.com/webhooks/stripe',
  enabled: true,
  maxAttempts: 5,
  timeoutSeconds: 30,
});

// List destinations
const dests = await client.incomingSources.listDestinations(projectId, sourceId);

// Update destination
await client.incomingSources.updateDestination(projectId, sourceId, destId, {
  enabled: false,
});

// Delete destination
await client.incomingSources.deleteDestination(projectId, sourceId, destId);

Incoming Events

// List incoming events (with optional source filter)
const events = await client.incomingEvents.list(projectId, {
  sourceId: source.id,
  page: 0,
  size: 20,
});

// Get event details
const event = await client.incomingEvents.get(projectId, eventId);

// Get forward attempts for an event
const attempts = await client.incomingEvents.getAttempts(projectId, eventId);

// Replay event to all destinations
const result = await client.incomingEvents.replay(projectId, eventId);
console.log(`Replayed to ${result.destinationsCount} destinations`);

Webhook Signature Verification

Verify incoming webhooks in your endpoint:

import { verifySignature, constructEvent } from '@webhook-platform/node';

app.post('/webhooks', (req, res) => {
  const payload = req.body; // raw body string
  const signature = req.headers['x-signature'];
  const secret = process.env.WEBHOOK_SECRET;

  try {
    // Option 1: Just verify
    verifySignature(payload, signature, secret);

    // Option 2: Verify and parse
    const event = constructEvent(payload, req.headers, secret);
    
    console.log(`Received ${event.type}:`, event.data);
    
    // Handle the event
    switch (event.type) {
      case 'order.completed':
        handleOrderCompleted(event.data);
        break;
    }

    res.status(200).send('OK');
  } catch (err) {
    console.error('Webhook verification failed:', err.message);
    res.status(400).send('Invalid signature');
  }
});

Express.js Example

import express from 'express';
import { constructEvent } from '@webhook-platform/node';

const app = express();

// Important: Use raw body for signature verification
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  const event = constructEvent(
    req.body.toString(),
    req.headers,
    process.env.WEBHOOK_SECRET
  );

  // Process event...
  res.sendStatus(200);
});

Error Handling

import { 
  HookflowError, 
  RateLimitError, 
  AuthenticationError,
  ValidationError 
} from '@webhook-platform/node';

try {
  await client.events.send({ type: 'test', data: {} });
} catch (err) {
  if (err instanceof RateLimitError) {
    // Wait and retry
    console.log(`Rate limited. Retry after ${err.retryAfter}ms`);
    await sleep(err.retryAfter);
  } else if (err instanceof AuthenticationError) {
    console.error('Invalid API key');
  } else if (err instanceof ValidationError) {
    console.error('Validation failed:', err.fieldErrors);
  } else if (err instanceof HookflowError) {
    console.error(`Error ${err.status}: ${err.message}`);
  }
}

Error Response Format

All API errors return a consistent JSON body:

{
  "error": "error_code",
  "message": "Human-readable description",
  "status": 400,
  "fieldErrors": { "field": "reason" }
}
  • error — machine-readable error code (snake_case), always present
  • message — human-readable description, always present
  • status — HTTP status code (integer), always present
  • fieldErrors — field-level validation details (only present for validation_error)

Error Codes Reference

HTTP Statuserror CodeSDK ExceptionDescription
400validation_errorValidationErrorInvalid request parameters; see fieldErrors
400invalid_requestHookflowErrorMalformed or semantically invalid request
401unauthorizedAuthenticationErrorMissing or invalid API key / expired token
403forbiddenHookflowErrorInsufficient permissions for the action
404not_foundNotFoundErrorRequested resource does not exist
413payload_too_largeHookflowErrorRequest body exceeds maximum allowed size
422unprocessable_entityHookflowErrorValid syntax but violates business rules
429rate_limit_exceededRateLimitErrorToo many requests; check X-RateLimit-* headers
500internal_errorHookflowErrorUnexpected server error

Generic Requests

As the API expands, you can call any endpoint directly without waiting for SDK updates:

// GET
const schemas = await client.get<any[]>('/api/v1/projects/proj_123/schemas');

// POST with body and idempotency key
const result = await client.post('/api/v1/some/new/endpoint', { key: 'value' }, 'idempotency-key');

// PUT
await client.put('/api/v1/projects/proj_123/settings', { timezone: 'UTC' });

// PATCH
await client.patch('/api/v1/projects/proj_123/settings', { timezone: 'UTC' });

// DELETE
await client.delete('/api/v1/projects/proj_123/tags/old-tag');

// Fully custom request (any HTTP method)
const data = await client.request<any>('OPTIONS', '/api/v1/some/path');

All generic methods use the same authentication, error handling, and rate-limit logic as the built-in methods.

Configuration

const client = new Hookflow({
  apiKey: 'wh_live_xxx',      // Required: Your API key
  baseUrl: 'https://api.example.com', // Optional: API base URL
  timeout: 30000,              // Optional: Request timeout in ms (default: 30000)
});

TypeScript Support

This SDK is written in TypeScript and includes full type definitions:

import type { 
  Event, 
  EventResponse, 
  Endpoint, 
  Delivery,
  DeliveryStatus 
} from '@webhook-platform/node';

Development

Running Tests

Local (requires Node.js 16+):

npm install
npm test

Docker:

docker run --rm -v $(pwd):/app -w /app node:20-alpine sh -c "npm install && npm test"

Building

npm run build

License

MIT

Keywords

webhook

FAQs

Package last updated on 18 Mar 2026

Related posts