Skip to main content
npayload is launching soon.
npayloadDocs
Framework Quickstarts

Hono quickstart

Build an edge-ready API with Hono that publishes and receives npayload messages

Build an edge-ready API with Hono that publishes messages to npayload and receives webhooks. Hono runs on edge runtimes, Bun, Deno, and Node.js.

Prerequisites

  • Node.js 18+ or Bun
  • An npayload account with machine credentials (get them here)

Set up the project

mkdir npayload-hono && cd npayload-hono
npm init -y
npm install @npayload/node hono
npm install -D typescript tsx @types/node
mkdir npayload-hono && cd npayload-hono
bun init
bun add @npayload/node hono

Create a .env file:

NPAYLOAD_CLIENT_ID=oac_your_client_id
NPAYLOAD_HMAC_SECRET=your_hmac_secret
WEBHOOK_SECRET=your_webhook_secret
PORT=3000

Create the npayload client

// src/npayload.ts
import { NPayloadAuth, NPayloadClient } from '@npayload/node';

const auth = new NPayloadAuth({
  clientId: process.env.NPAYLOAD_CLIENT_ID!,
  hmacSecret: process.env.NPAYLOAD_HMAC_SECRET!,
});

export const npayload = new NPayloadClient({
  auth,
  environment: 'development',
});

Set up channels

// src/setup.ts
import { npayload } from './npayload';

export async function setup() {
  await npayload.channels.create({
    name: 'events',
    description: 'Application events',
    privacy: 'standard',
  });

  await npayload.subscriptions.create({
    channel: 'events',
    name: 'event-handler',
    type: 'webhook',
    endpoint: {
      url: `${process.env.BASE_URL ?? 'http://localhost:3000'}/webhooks/events`,
      method: 'POST',
    },
  });

  console.log('Channel and subscription created.');
}

Build the Hono app

// src/index.ts
import { Hono } from 'hono';
import { serve } from '@hono/node-server';
import { npayload } from './npayload';
import { setup } from './setup';

const app = new Hono();

// Publish endpoint
app.post('/publish', async (c) => {
  const body = await c.req.json();

  const message = await npayload.messages.publish({
    channel: 'events',
    payload: body,
  });

  return c.json({ messageId: message.gid }, 201);
});

// Webhook receiver
app.post('/webhooks/events', async (c) => {
  const body = await c.req.json();
  const signature = c.req.header('x-npayload-signature') ?? '';

  const isValid = npayload.webhooks.verify(
    body,
    signature,
    process.env.WEBHOOK_SECRET!
  );

  if (!isValid) {
    return c.json({ error: 'Invalid signature' }, 401);
  }

  console.log('Received:', body.payload);
  return c.json({ received: true });
});

// Health check
app.get('/health', (c) => c.json({ status: 'ok' }));

const port = Number(process.env.PORT) || 3000;

setup().then(() => {
  serve({ fetch: app.fetch, port }, () => {
    console.log(`Hono server running on port ${port}`);
  });
});

Run it

npx tsx src/index.ts
bun run src/index.ts

Test publishing:

curl -X POST http://localhost:3000/publish \
  -H "Content-Type: application/json" \
  -d '{"event": "item.purchased", "itemId": "itm_456", "quantity": 2}'

Next steps

Was this page helpful?

On this page