Quickstart

Next.js

Add booking to a Next.js App Router project using Server Actions and the Seshn SDK.

Prerequisites

  • Node.js 18+
  • A Seshn account with an API key (sign up)
  • A Next.js 14+ project with App Router

1. Install the SDK

terminal
1npm install @seshn/sdk

2. Add your API key

Store the key in an environment variable. Never expose it to the browser.

.env.local
1SESHN_API_KEY=sk_test_...

3. Create a Seshn client

Initialize the client once and reuse it across server code.

lib/seshn.ts
1import { Seshn } from '@seshn/sdk';
2
3export const seshn = new Seshn(process.env.SESHN_API_KEY!, {
4 baseUrl: 'https://api.seshn.net',
5});

4. Create Server Actions

Server Actions run on the server and can be called directly from React components. These three actions cover the core booking flow: check availability, create a booking, and confirm it.

app/actions.ts
1'use server';
2
3import { seshn } from '@/lib/seshn';
4
5export async function getAvailability(serviceId: string, from: string, to: string) {
6 const result = await seshn.availability.query({ serviceId, from, to });
7 return result.data;
8}
9
10export async function createBooking(slotId: string, contactId: string, seats: number) {
11 const { booking } = await seshn.bookings.create({
12 slotId,
13 contactId,
14 seats,
15 hold: true, // hold the slot while the user confirms
16 });
17 return booking;
18}
19
20export async function confirmBooking(bookingId: string) {
21 const { booking } = await seshn.bookings.confirm(bookingId);
22 return booking;
23}

5. Build a booking component

This client component calls the Server Actions you defined above. It fetches slots, lets the user pick one, and confirms the booking.

app/book/page.tsx
1'use client';
2
3import { useState, useEffect } from 'react';
4import { getAvailability, createBooking, confirmBooking } from '../actions';
5
6export default function BookingPage() {
7 const [slots, setSlots] = useState<any[]>([]);
8 const [booking, setBooking] = useState<any>(null);
9 const [confirmed, setConfirmed] = useState(false);
10
11 useEffect(() => {
12 getAvailability('svc_yoga_class', '2026-03-20', '2026-03-27')
13 .then(setSlots);
14 }, []);
15
16 async function handleBook(slotId: string) {
17 const b = await createBooking(slotId, 'ct_jane_doe', 1);
18 setBooking(b);
19 }
20
21 async function handleConfirm() {
22 if (!booking) return;
23 await confirmBooking(booking.id);
24 setConfirmed(true);
25 }
26
27 if (confirmed) {
28 return <p>Booking {booking.id} confirmed.</p>;
29 }
30
31 if (booking) {
32 return (
33 <div>
34 <p>Booking {booking.id} is held. Confirm?</p>
35 <button onClick={handleConfirm}>Confirm</button>
36 </div>
37 );
38 }
39
40 return (
41 <div>
42 <h1>Available Slots</h1>
43 {slots.map((slot) => (
44 <div key={slot.id}>
45 <span>{slot.startTime} - {slot.endTime}</span>
46 <button onClick={() => handleBook(slot.id)}>Book</button>
47 </div>
48 ))}
49 </div>
50 );
51}

6. Alternative: API Route

If you prefer Route Handlers over Server Actions, expose the same logic as an API endpoint.

app/api/book/route.ts
1import { NextRequest, NextResponse } from 'next/server';
2import { seshn } from '@/lib/seshn';
3
4export async function POST(req: NextRequest) {
5 const { slotId, contactId, seats } = await req.json();
6
7 // Create the booking
8 const { booking } = await seshn.bookings.create({
9 slotId,
10 contactId,
11 seats,
12 });
13
14 // Confirm immediately (or let the client confirm later)
15 const { booking: confirmed } = await seshn.bookings.confirm(booking.id);
16
17 return NextResponse.json(confirmed);
18}

What's next