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

@vennio/sdk

v0.3.0

Published

Scheduling API for JS/TS apps and AI agents — bookings, shareable Venn Links, and bidirectional availability. Full TypeScript types.

Readme

@vennio/sdk

Scheduling API primitives for JavaScript and TypeScript apps. List bookings, create shareable Venn Links, accept availability from your customers — without building calendar OAuth, availability logic, or timezone handling yourself.

Works in Node.js and the browser; designed to plug into AI agents that schedule on behalf of users.

Installation

npm install @vennio/sdk

Node 18+. ES modules and CommonJS both supported.

Quick Start

import { Vennio, VennioApiError } from '@vennio/sdk';

const vennio = new Vennio(process.env.VENNIO_API_KEY!);

// List the authenticated business's recent bookings
const { bookings } = await vennio.bookings.list({ limit: 10 });
console.log(bookings.map((b) => `${b.customer_email} — ${b.start_time}`));

// Create a Venn Link — a shareable URL recipients use to book time with you
const link = await vennio.vennLinks.create({
  title: '30-min intro call',
  duration_minutes: 30,
  expiresIn: '7d',
});
console.log(`Share this URL: ${link.url}`);

API Keys

Get keys from https://vennio.app/api-keys. Four shapes — the prefix tells you both scope (publishable / secret) and environment (live / test):

  • vennio_pk_live_… — publishable, live. Read-only-ish; safe to ship in a browser bundle. Use for client-side widgets and embeds.
  • vennio_sk_live_… — secret, live. Full access: booking creation, cancel, admin operations. Server-side only. Never ship in a client bundle.
  • vennio_pk_test_… / vennio_sk_test_… — same scopes, but every request runs in test mode (see below).

Test mode

Requests authenticated with a _test_ key are real API calls that hit the real database — bookings, Venn Links, and proposals all persist and are queryable — but side effects are suppressed server-side:

  • No email is sent to customers or principals.
  • No calendar event is created in Google / Microsoft / iCal feeds.
  • No webhooks fire to your registered endpoints.
  • No CRM sync (HubSpot, Salesforce) runs.

This is the safe way to iterate against your own account from a script without spamming yourself or real customers. Test data is fully isolated from live data — listing bookings with a test key returns only test-mode bookings.

const vennio = new Vennio(process.env.VENNIO_API_KEY!); // sk_test_… while iterating
const created = await vennio.bookings.create({ /* … */ });
// → persisted in DB, no email, no calendar event, no webhook

For one-off dry runs against a live key (e.g. an integration test in CI that uses production credentials), pass demo_mode: true on the request:

await vennio.bookings.create({ /* … */, demo_mode: true });
// → same side-effect suppression, but on a per-request basis

When you're ready to ship, swap the key prefix from _test_ to _live_. No other code changes.

Error handling

Every method on vennio.bookings, vennio.vennLinks, and the other resource namespaces throws a VennioApiError on API errors (4xx/5xx). Network errors and request-construction errors throw the underlying TypeError / AbortError etc.

import { Vennio, VennioApiError } from '@vennio/sdk';

const vennio = new Vennio(process.env.VENNIO_API_KEY!);

try {
  const booking = await vennio.bookings.create({
    business_id: 'your-business-uuid',
    customer_email: '[email protected]',
    customer_name: 'Jane Doe',
    start_time: '2026-06-01T14:00:00Z',
    end_time: '2026-06-01T14:30:00Z',
  });
  console.log('created', booking);
} catch (err) {
  if (err instanceof VennioApiError) {
    // err.code:    short string — 'unauthorized', 'validation_error',
    //              'not_found', 'rate_limit_exceeded', etc.
    // err.status:  HTTP status (e.g. 401, 400, 404, 429).
    // err.details: raw API response body for debugging / form-level errors.
    console.error(`vennio: ${err.code} (${err.status}) — ${err.message}`);
  } else {
    throw err;
  }
}

Resource namespaces

The Vennio class exposes a curated surface for the most common scheduling primitives. Endpoints outside the curated surface remain reachable through vennio.raw — the underlying generated client.

Curated

  • vennio.bookingscreate, list, get, update, cancel, stats
  • vennio.vennLinkscreate, list, get, update, delete, bookings
  • vennio.webhooksverify for inbound payloads (see Consuming webhooks below). Webhook management methods (create, list, get, update, delete, regenerateSecret) land in a subsequent release; until then use vennio.raw.webhooks.*.
  • vennio.proposals, vennio.calendars, vennio.availability — scaffolded; fuller method coverage lands in subsequent releases.

Available via vennio.raw

Anything not on the curated surface is reachable through vennio.raw.<namespace>.

Always on .raw — these admin, meta, and network-graph endpoints aren't part of the curated surface:

  • vennio.raw.network — network-graph queries
  • vennio.raw.eventTypes — event-type management
  • vennio.raw.consents — consent records
  • vennio.raw.apiKeys — API key management

Available on .raw only — curation may follow if usage warrants it:

  • vennio.raw.invitations
  • vennio.raw.accessRequests
  • vennio.raw.hubspot
  • vennio.raw.schedules

.raw methods return a hey-api RequestResult — a discriminated union shaped as { data, error, request, response } — instead of throwing. Narrow on result.error (or result.data) before reading the payload:

const result = await vennio.raw.eventTypes.list();
if (result.error) {
  console.error('eventTypes.list failed', result.error);
} else {
  console.log(result.data);
}

Note the error-model difference from the curated namespaces: methods on vennio.bookings, vennio.vennLinks, etc. throw VennioApiError on 4xx/5xx (see Error handling above); .raw methods do not throw — they place the error in result.error for you to handle.

Consuming webhooks

Every Vennio webhook delivery is signed with the webhook's secret. The signature arrives in the X-Vennio-Signature header as sha256=<hex_digest>, where the digest is HMAC-SHA256 of the raw request body keyed by the webhook secret. Verify every payload before trusting it — vennio.webhooks.verify handles the HMAC, the sha256= prefix, and the timing-safe comparison.

Pass the raw bytes the server received, not a re-stringified copy. Re-serialising changes key ordering and whitespace and invalidates the signature.

// Express
import express from 'express';
import { Vennio } from '@vennio/sdk';

const vennio = new Vennio(process.env.VENNIO_API_KEY!);
const app = express();

app.post(
  '/webhooks/vennio',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const ok = vennio.webhooks.verify(
      req.body, // Buffer — the raw bytes
      req.header('X-Vennio-Signature') ?? '',
      process.env.VENNIO_WEBHOOK_SECRET!,
    );
    if (!ok) return res.status(401).end();

    const event = JSON.parse(req.body.toString('utf8'));
    // Idempotency: dedupe on event.id. Retries reuse the same id.
    // Respond 2xx fast; do slow work after the response (queue, defer, …).
    res.status(200).end();

    handle(event).catch(console.error);
  },
);
// Next.js App Router route handler
import { Vennio } from '@vennio/sdk';

const vennio = new Vennio(process.env.VENNIO_API_KEY!);

export async function POST(request: Request) {
  const raw = await request.text(); // read BEFORE .json()
  const ok = vennio.webhooks.verify(
    raw,
    request.headers.get('x-vennio-signature') ?? '',
    process.env.VENNIO_WEBHOOK_SECRET!,
  );
  if (!ok) return new Response('invalid signature', { status: 401 });

  const event = JSON.parse(raw);
  // ...dedupe on event.id, fan out by event.type...
  return new Response(null, { status: 200 });
}

Operational notes. Vennio retries failed deliveries on an exponential backoff (1 min → 5 min → 30 min). Retries carry the same event.id and a fresh signature — dedupe on the id, not on the signature. The webhook secret is returned once when you create the webhook; reveal it later from the dashboard or rotate via vennio.raw.webhooks.regenerateSecret.

TypeScript

Full types included — no @types package needed:

import {
  Vennio,
  VennioApiError,
  type Booking,
  type VennLink,
  type CreateBookingResult,
} from '@vennio/sdk';

Every request shape, response shape, and error shape is generated from the canonical OpenAPI spec at https://api.vennio.app and re-exported.

AI Agent usage

The SDK works well with agents that schedule on behalf of users. Surface the methods as tools; let the model pick:

// Tool: list_bookings
async function list_bookings(args: { limit?: number }) {
  const { bookings } = await vennio.bookings.list(args);
  return bookings.map((b) => ({
    id: b.id,
    when: `${b.start_time} → ${b.end_time}`,
    with: b.customer_email,
    status: b.status,
  }));
}

For schedule-on-behalf-of-user flows that need consent gates, mutual availability, or proposal back-and-forth, drop down to vennio.raw.* until those namespaces are curated.

Migrating from 0.1.x

The Vennio class is the modern, namespaced API. The 0.1.x flat surface (vennio.getSlots, vennio.book) is still exported as LegacyVennio for incremental migration:

import { LegacyVennio } from '@vennio/sdk';
// ...behaves exactly like the old default export

LegacyVennio is deprecated and will be removed in 1.0.0.

Documentation

Full API reference: https://docs.vennio.app

License

MIT