Payments & Stripe
The Booking Kit provides payment logic through the PaymentAdapter interface and pure computation functions for cancellation policies and fees.
Payment adapter
Section titled “Payment adapter”The PaymentAdapter interface abstracts payment processing:
interface PaymentAdapter { createPaymentIntent(options: CreatePaymentIntentOptions): Promise<CreatePaymentIntentResult>; createSetupIntent(options: CreateSetupIntentOptions): Promise<CreateSetupIntentResult>; capturePayment(paymentIntentId: string): Promise<CaptureResult>; refundPayment(paymentIntentId: string, amountCents?: number): Promise<RefundResult>;}Cancellation policies
Section titled “Cancellation policies”Define tiered fee schedules based on how far in advance a booking is cancelled:
import { evaluateCancellationFee, validateCancellationPolicy } from "@thebookingkit/core";import type { CancellationPolicy, CancellationFeeResult } from "@thebookingkit/core";
// Free cancellation if 48+ hours notice, escalating fees for closer cancellationsconst policy: CancellationPolicy = [ { hoursBefore: 48, feePercentage: 0 }, // Free cancellation 48h+ { hoursBefore: 24, feePercentage: 25 }, // 25% fee 24-48h before { hoursBefore: 0, feePercentage: 50 }, // 50% fee same day];
// Validate the policy structuretry { validateCancellationPolicy(policy); console.log("Policy is valid");} catch (error) { console.error("Invalid policy:", error.message);}
// Compute the fee for a specific cancellationconst fee: CancellationFeeResult = evaluateCancellationFee( policy, 5000, // booking price in cents ($50.00) new Date("2026-03-10T14:00:00.000Z"), // appointment start time (UTC) new Date("2026-03-09T10:00:00.000Z") // cancellation time (28 hours before));
console.log(fee);// Output: {// feeCents: 1250, // 25% of $50 = $12.50// feePercentage: 25,// refundCents: 3750, // Customer gets $37.50 back// matchedTier: { hoursBefore: 24, feePercentage: 25 }// }Tiered cancellation scenarios:
import { evaluateCancellationFee } from "@thebookingkit/core";import type { CancellationPolicy } from "@thebookingkit/core";
const policy: CancellationPolicy = [ { hoursBefore: 48, feePercentage: 0 }, { hoursBefore: 24, feePercentage: 25 }, { hoursBefore: 0, feePercentage: 50 },];
const appointmentStart = new Date("2026-03-10T14:00:00.000Z");const priceCents = 10000; // $100
// Scenario 1: Cancel 72 hours before (free)const fee1 = evaluateCancellationFee( policy, priceCents, appointmentStart, new Date("2026-03-07T14:00:00.000Z") // 72 hours before);console.log(`Fee: $${fee1.feeCents / 100} (${fee1.feePercentage}%)`); // Fee: $0 (0%)
// Scenario 2: Cancel 36 hours before (25% fee)const fee2 = evaluateCancellationFee( policy, priceCents, appointmentStart, new Date("2026-03-09T02:00:00.000Z") // 36 hours before);console.log(`Fee: $${fee2.feeCents / 100} (${fee2.feePercentage}%)`); // Fee: $25 (25%)
// Scenario 3: Cancel 6 hours before (50% fee)const fee3 = evaluateCancellationFee( policy, priceCents, appointmentStart, new Date("2026-03-10T08:00:00.000Z") // 6 hours before);console.log(`Fee: $${fee3.feeCents / 100} (${fee3.feePercentage}%)`); // Fee: $50 (50%)Payment utilities
Section titled “Payment utilities”import { requiresPayment, hasNoShowFee, validatePaymentAmount, validateCurrency, formatPaymentAmount, computePaymentSummary,} from "@thebookingkit/core";import type { PaymentRecord, CancellationPolicy } from "@thebookingkit/core";
// Check if an event type requires paymentrequiresPayment({ priceCents: 5000 }); // truerequiresPayment({ priceCents: 0 }); // falserequiresPayment({ priceCents: null }); // false
// Check if policy has no-show feesconst policy: CancellationPolicy = [ { hoursBefore: 24, feePercentage: 25 }, { hoursBefore: 0, feePercentage: 100 }, // Full fee for no-shows];hasNoShowFee(policy); // true
// Validate payment amountsvalidatePaymentAmount(5000); // truevalidatePaymentAmount(0); // truevalidatePaymentAmount(-100); // throws PaymentValidationError
// Validate currency codesvalidateCurrency("usd"); // truevalidateCurrency("gbp"); // truevalidateCurrency("xyz"); // throws PaymentValidationError
// Format amounts for displayformatPaymentAmount(5000, "usd"); // "$50.00"formatPaymentAmount(1250, "gbp"); // "£12.50"formatPaymentAmount(100, "jpy"); // "¥100" (no decimal places)
// Compute payment summary for a provider's dashboardconst paymentRecords: PaymentRecord[] = [ { id: "pay-1", bookingId: "booking-1", stripePaymentIntentId: "pi_123abc", amountCents: 5000, currency: "usd", status: "succeeded", paymentType: "prepayment", refundAmountCents: 0, createdAt: new Date("2026-03-01"), }, { id: "pay-2", bookingId: "booking-2", stripePaymentIntentId: "pi_456def", amountCents: 8000, currency: "usd", status: "refunded", paymentType: "prepayment", refundAmountCents: 8000, createdAt: new Date("2026-03-05"), },];
const summary = computePaymentSummary(paymentRecords);console.log(summary);// {// totalRevenueCents: 5000,// totalRefundedCents: 8000,// netRevenueCents: -3000,// countByStatus: { succeeded: 1, refunded: 1 },// totalPayments: 2// }UI components
Section titled “UI components”import { PaymentGate } from "./components/payment-gate";import { PaymentHistory } from "./components/payment-history";
// Wrap the booking confirmation in a payment step<PaymentGate amountCents={5000} currency="usd" onPaymentComplete={handlePaymentComplete}/>
// Show payment history to provider<PaymentHistory payments={bookingPayments} />