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

hookshot-sdk

v0.1.4

Published

Official SDK for the Hookshot webhook delivery service

Readme

hookshot-sdk

Official JavaScript/TypeScript SDK for the Hookshot webhook delivery service.

Installation

npm install hookshot-sdk
# or
yarn add hookshot-sdk
# or
pnpm add hookshot-sdk

Requirements

  • Node.js 18+ (uses native fetch)
  • Or any modern browser with fetch support

Quick Start

import { HookshotClient } from 'hookshot-sdk';

const hookshot = new HookshotClient({
  apiKey: 'your-api-key',
});

// Send a webhook event
const result = await hookshot.events.send({
  eventType: 'order.created',
  payload: { orderId: '12345', amount: 99.99 },
});

console.log('Event IDs:', result.eventIds);

API Reference

Configuration

const hookshot = new HookshotClient({
  apiKey: string;      // Required: Your API key
});

Endpoints

Manage webhook endpoints where events will be delivered.

// List all endpoints
const endpoints = await hookshot.endpoints.list();

// Create an endpoint
const endpoint = await hookshot.endpoints.create({
  label: 'Production',
  url: 'https://api.example.com/webhooks',
  maxRetries: 5,        // optional, default: 5
  enabled: true,        // optional, default: true
});

// Get an endpoint
const endpoint = await hookshot.endpoints.get('endpoint-id');

// Update an endpoint
await hookshot.endpoints.update('endpoint-id', {
  label: 'Staging',
  enabled: false,
});

// Delete an endpoint
await hookshot.endpoints.delete('endpoint-id');

Events

Send and manage webhook events.

// Send an event (delivered to all active endpoints)
const result = await hookshot.events.send({
  eventType: 'order.created',
  payload: { orderId: '12345' },
  idempotencyKey: 'order-12345-created',  // optional, prevents duplicates
  endpointId: 'specific-endpoint-id',     // optional, target specific endpoint
  endpointIds: ['id1', 'id2'],            // optional, target multiple endpoints
});

// List events with filtering
const { events, total } = await hookshot.events.list({
  status: 'failed',   // optional: 'pending' | 'delivering' | 'delivered' | 'failed' | 'dlq'
  limit: 20,          // optional, default: 20
  offset: 0,          // optional, for pagination
});

// Get event details
const event = await hookshot.events.get('event-id');

// Get delivery attempts for an event
const attempts = await hookshot.events.getAttempts('event-id');

Dead Letter Queue (DLQ)

Manage events that failed all retry attempts.

// List events in DLQ
const { events, total } = await hookshot.dlq.list({
  limit: 20,
  offset: 0,
});

// Get DLQ statistics
const stats = await hookshot.dlq.stats();
// { count: 5, oldestEventAt: Date, newestEventAt: Date }

// Replay a specific event
await hookshot.dlq.replay('event-id', {
  resetRetryCount: true,  // optional, start with fresh retry count
});

// Replay all events in DLQ
const { replayedCount } = await hookshot.dlq.replayAll();

// Purge a specific event
await hookshot.dlq.purge('event-id');

// Purge all events from DLQ
const { purgedCount } = await hookshot.dlq.purgeAll();

Error Handling

The SDK throws typed errors for different failure scenarios:

import { 
  HookshotClient, 
  HookshotError, 
  HookshotAuthenticationError,
  HookshotRateLimitError,
  HookshotValidationError,
} from 'hookshot-sdk';

try {
  await hookshot.events.send({ ... });
} catch (error) {
  if (error instanceof HookshotAuthenticationError) {
    // Invalid or missing API key (401)
    console.error('Authentication failed');
  } else if (error instanceof HookshotRateLimitError) {
    // Rate limit exceeded (429)
    console.error('Rate limited, retry after:', error.retryAfter, 'seconds');
  } else if (error instanceof HookshotValidationError) {
    // Invalid request data (400)
    console.error('Validation error:', error.details);
  } else if (error instanceof HookshotError) {
    // Other API errors
    console.error('Error:', error.code, error.message, error.status);
  }
}

Error Properties

All errors extend HookshotError with these properties:

| Property | Type | Description | |----------|------|-------------| | message | string | Human-readable error message | | code | string | Error code (e.g., RATE_LIMIT_EXCEEDED) | | status | number | HTTP status code | | details | object | Additional error details (optional) |

TypeScript Support

The SDK is written in TypeScript and exports all types:

import type {
  HookshotConfig,
  EndpointResponse,
  CreateEndpointInput,
  UpdateEndpointInput,
  WebhookEventResponse,
  IngestEventInput,
  IngestResponse,
  DeliveryAttemptResponse,
  DlqStats,
  EventStatus,
  ListEventsParams,
  PaginationParams,
  ReplayOptions,
} from 'hookshot-sdk';

Webhook Payload Format

When Hookshot delivers a webhook to your endpoint, it sends this payload:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "type": "order.created",
  "idempotencyKey": "order-123-created",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "attemptNumber": 1,
  "data": {
    "orderId": "12345",
    "amount": 99.99
  }
}

Headers included with each delivery:

| Header | Description | |--------|-------------| | X-Webhook-Id | Unique event ID | | X-Webhook-Type | Event type | | X-Webhook-Timestamp | Event creation timestamp | | X-Webhook-Attempt | Current attempt number | | X-Webhook-Signature | HMAC-SHA256 signature for verification | | X-Webhook-Idempotency-Key | Idempotency key (if provided) |

Signature Verification

Verify webhook signatures to ensure authenticity:

import { createHmac } from 'crypto';

function verifySignature(
  payload: string,
  signature: string,
  secret: string
): boolean {
  const [version, hash] = signature.split('=');
  if (version !== 'v1') return false;

  const timestamp = req.headers['x-webhook-timestamp'];
  const signedPayload = `${new Date(timestamp).getTime()}.${payload}`;
  
  const expectedHash = createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');

  return hash === expectedHash;
}

License

MIT