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

beds24-booking-sdk

v0.2.0

Published

All-in-one booking SDK integrating Beds24 (PMS), Stripe (payments), and Resend (email). Handles availability, pricing, checkout, booking creation, and notifications.

Readme

beds24-booking-sdk

All-in-one booking SDK integrating Beds24 (PMS), Stripe (payments), and Resend (email).

Handles availability checks, pricing, Stripe Checkout, Beds24 booking creation, and email notifications in a single workflow.

日本語ドキュメント

Installation

npm install beds24-booking-sdk stripe resend

stripe and resend are peer dependencies. resend is optional if you don't need email notifications.

Setup

import { BookingSDK } from "beds24-booking-sdk";

const sdk = new BookingSDK({
  beds24: {
    refreshToken: process.env.BEDS24_REFRESH_TOKEN!,
    accessToken: process.env.BEDS24_ACCESS_TOKEN, // optional (auto-refreshes)
    propertyId: 123456,
    roomId: 654321,
  },
  stripe: {
    secretKey: process.env.STRIPE_SECRET_KEY!,
    webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
  },
  email: {
    resendApiKey: process.env.RESEND_API_KEY!,
    from: "My Property <[email protected]>",
    owner: "[email protected]",
    replyTo: "[email protected]", // optional
  },
  property: {
    name: "My Property",
    nameEn: "My Property", // optional — used in email header subtitle
    maxGuests: 10,
    checkInTime: "15:00",
    checkOutTime: "10:00",
    address: "123 Main St, Tokyo, Japan",
    phone: "03-1234-5678",
    basePrice: 15000,       // per night (weekday)
    weekendPrice: 20000,    // per night (weekend)
    extraGuestThreshold: 2, // surcharge applies above this number
    extraGuestSurcharge: 3000, // per extra guest per night
    validCheckInTimes: ["15:00", "16:00", "17:00", "18:00", "19:00", "20:00"],
    maxStayNights: 30,
  },
  baseUrl: "https://example.com",
});

Usage

Calendar & Availability

// Fetch calendar with pricing (also populates server-side price cache)
const calendar = await sdk.getCalendar("2026-04-01", "2027-03-31");

// Check availability for specific dates
const available = await sdk.checkAvailability("2026-05-01", "2026-05-03", 4);

Pricing

// Client-side: calculate from availability data
const price = sdk.calculatePrice("2026-05-01", "2026-05-03", availabilityData, 4);

// Server-side: verify against cache (prevents price tampering)
const verified = sdk.verifyPriceFromCache("2026-05-01", "2026-05-03", 4);

Stripe Checkout

import { isCheckoutError } from "beds24-booking-sdk";

const result = await sdk.createCheckout({
  checkIn: "2026-05-01",
  checkOut: "2026-05-03",
  guestName: "John Doe",
  guestNameKana: "",
  guestEmail: "[email protected]",
  guestPhone: "090-1234-5678",
  guests: 4,
  totalPrice: 46000,
  checkInTime: "16:00",
  notes: "Late arrival",
});

if (isCheckoutError(result)) {
  console.error(result.error); // validation error or price mismatch
} else {
  redirect(result.url); // Stripe Checkout URL
}

Webhook Handler

Handles Stripe checkout.session.completed events — creates a Beds24 booking and sends confirmation emails in one call.

// Next.js API Route example
export async function POST(request: Request) {
  const body = await request.text();
  const signature = request.headers.get("stripe-signature")!;

  const result = await sdk.handlePaymentWebhook(body, signature);

  if (result.error) {
    return Response.json({ error: result.error }, { status: 500 });
  }
  return Response.json(result);
}

Idempotency in production ⚠️

Stripe retries webhook deliveries on non-2xx responses. The default InMemoryIdempotencyStore is process-local — on serverless or multi-instance deployments, restarts and concurrent invocations across instances will not share dedup state and you may end up creating duplicate Beds24 bookings.

For production, supply a shared, persistent store via idempotencyStore:

import type { IdempotencyStore } from "beds24-booking-sdk";

const redisStore: IdempotencyStore = {
  async has(id) {
    return (await redis.exists(`stripe:evt:${id}`)) === 1;
  },
  async add(id) {
    await redis.set(`stripe:evt:${id}`, "1", "EX", 60 * 60 * 24 * 7); // 7 days
  },
};

const sdk = new BookingSDK({
  // ...
  idempotencyStore: redisStore,
});

Email Templates

The SDK ships with built-in Japanese-localized confirmation email templates. They are used by handlePaymentWebhook by default. You can also call them directly:

import {
  generateBookingConfirmationEmail,
  generateOwnerNotificationEmail,
} from "beds24-booking-sdk/email";

const guestEmail = generateBookingConfirmationEmail(bookingData, propertyConfig);
const ownerEmail = generateOwnerNotificationEmail(bookingData, propertyConfig);

For non-Japanese audiences, supply your own templates via BookingSDKConfig.templates — the webhook handler will use them instead of the Japanese defaults:

import type { BookingEmailTemplates } from "beds24-booking-sdk";

const englishTemplates: BookingEmailTemplates = {
  guest: (data, property) => ({
    subject: `[${property.name}] Reservation confirmed (${data.checkIn} → ${data.checkOut})`,
    html: `<p>Dear ${data.guestName}, your booking ${data.bookingId} is confirmed…</p>`,
    text: `Dear ${data.guestName}, your booking ${data.bookingId} is confirmed…`,
  }),
  owner: (data) => ({
    subject: `[New booking] ${data.guestName} ${data.checkIn}→${data.checkOut}`,
    html: `<pre>${data.bookingId} / ${data.guestEmail}</pre>`,
    text: `${data.bookingId} / ${data.guestEmail}`,
  }),
};

const sdk = new BookingSDK({ /* ... */, templates: englishTemplates });

Error handling & localization

validateCheckoutRequest and createCheckout return errors with stable, locale-independent codes (ValidationErrorCode, CheckoutErrorCode) plus a default English message. Switch on code in your UI rather than parsing the message:

import { isCheckoutError } from "beds24-booking-sdk";

const result = await sdk.createCheckout(req);
if (isCheckoutError(result)) {
  // result.code is one of:
  //   "VALIDATION_FAILED" | "INVALID_PRICE" | "PRICE_CACHE_EXPIRED" | "PRICE_MISMATCH"
  showLocalizedError(result.code);
}

Submodule Imports

Import only what you need:

import { Beds24Client } from "beds24-booking-sdk/beds24";
import { PriceCache, calculateTotalPrice } from "beds24-booking-sdk/pricing";
import { EmailSender } from "beds24-booking-sdk/email";
import { validateCheckoutRequest } from "beds24-booking-sdk/payment";

Requirements

  • Node.js >= 18
  • Beds24 API V2 account (refresh token)
  • Stripe account (secret key + webhook secret)
  • Resend account (API key) — only if using email features

License

MIT