Bookings & Calendars
Public calendars, calendar events, and bookings (appointments).
- Use it for: Public website · Server integration
- Reads: public token — works in the browser; Bearer for
getBooking,listBookings - Writes: none — read-only today
- CLI:
uidu bookings - Auth: what each token can do and where it may run — Authentication
Calendars and their events are the workspace's public schedule — opening hours, classes, appointments on offer — and bookings are the reservations people made. Render the first on a public site with the public token; read the second from your server.
Mental model
Calendar name, description, color ("#22c55e"), timeZone ("Europe/Rome")
└─→ CalendarEvent name, startTime / endTime, allDay, timeZone, url,
primaryAddress, body (rich text — on getCalendarEvent only)
Booking kind, number, status, currency, itemsCount, itemsTotal (cents),
paidAt / refundedAt / expiredAt / willExpireAt, contact,
fieldValuesByShortname (on getBooking only)- A
CalendarEventis lighter than anEvent: no campaign, no attendance, no CMS body to build — a dated entry on a calendar. Use Events when people RSVP. - Two auth levels. Calendars and calendar events are public reads: the public token works,
including in the browser. Bookings are private data and need a Bearer (
apiKey) client on the server — with a public tokenlistBookingsreturns an empty list andgetBookingreturnsnull, no error. Nothing here writes: the domain is read-only today. - Times (
startTime,endTime) are ISO strings ornull; anallDayevent has no meaningful time of day. Each event and calendar carries itstimeZone— format with it rather than the server's zone. - Money is in cents. A booking's
itemsTotalis an integer in the minor unit of itscurrency: divide by 100 to display it.statusandkindare labels (strings);numberis the human-readable booking number. - Filters.
listCalendarEventsnarrows bycalendarIdsand by namedscopes(e.g.upcoming). List items carry the event'scalendar(id,name,color) and a shortprimaryAddress(formattedAddress,city); the full event, withbodyand the address'snameandcountryCode, comes fromgetCalendarEvent.listCalendarsandlistBookingspage withfirst/afterorlast/before.
Use cases
Public calendar grid
Goal: a statically rendered page with a legend of calendars and the upcoming events grouped by month.
// app/calendar/page.tsx — Server Component
import { listCalendars, listCalendarEvents } from '@uidu/client';
import { uidu } from '@/lib/uidu'; // public token is enough
export default async function CalendarPage() {
const [calendars, events] = await Promise.all([
listCalendars(uidu, { first: 50 }),
listCalendarEvents(uidu, { first: 100, scopes: ['upcoming'] }),
]);
const byMonth = events.reduce<Record<string, typeof events>>((acc, e) => {
if (!e.startTime) return acc;
const month = e.startTime.slice(0, 7); // YYYY-MM
(acc[month] ??= []).push(e);
return acc;
}, {});
return (
<div>
<ul>
{calendars.map((c) => (
<li key={c.id} style={{ color: c.color ?? undefined }}>
{c.name}
</li>
))}
</ul>
{Object.entries(byMonth).map(([month, list]) => (
<section key={month}>
<h2>{month}</h2>
<ul>
{list.map((e) => (
<li key={e.id} style={{ borderColor: e.calendar.color ?? undefined }}>
<a href={`/calendar/${e.id}`}>{e.name}</a>{' '}
{new Date(e.startTime!).toLocaleString(undefined, {
timeZone: e.timeZone ?? undefined,
dateStyle: 'medium',
timeStyle: e.allDay ? undefined : 'short',
})}
{e.primaryAddress?.city && ` · ${e.primaryAddress.city}`}
</li>
))}
</ul>
</section>
))}
</div>
);
}- To show one calendar only, pass
calendarIds: [calendarId];getCalendar(uidu, { id })returns its name, color and time zone for the page header. - One page of events is usually enough for "upcoming"; for a full archive walk every page with
paginateandListCalendarEventsDocument— see Pagination & field values.
Calendar event page
Goal: the detail page each grid item links to, with the event's rich-text description.
// app/calendar/[id]/page.tsx
import { notFound } from 'next/navigation';
import { getCalendarEvent } from '@uidu/client';
import { RichText } from '@uidu/react';
import { uidu } from '@/lib/uidu';
export default async function CalendarEventPage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const event = await getCalendarEvent(uidu, { id });
if (!event) notFound();
return (
<article>
<p>{event.calendar.name}</p>
<h1>{event.name}</h1>
{event.primaryAddress && <p>{event.primaryAddress.formattedAddress}</p>}
{event.body && <RichText doc={event.body} />} {/* Tiptap JSON */}
{event.url && <a href={event.url}>More information</a>}
</article>
);
}Bookings report on the server
Goal: an internal page or export listing recent bookings with their customer and amount.
// app/admin/bookings/data.ts — server-only
import { listBookings, getBooking } from '@uidu/client';
import { uiduAdmin } from '@/lib/uidu-admin'; // createClient({ workspace, apiKey })
const money = (cents: number | null | undefined, currency: string | null | undefined) =>
cents == null
? '—'
: new Intl.NumberFormat(undefined, { style: 'currency', currency: currency ?? 'EUR' }).format(
cents / 100, // itemsTotal is in cents
);
export async function recentBookings() {
const bookings = await listBookings(uiduAdmin, { first: 25 }); // [] with a public token
return bookings.map((b) => ({
number: b.number,
kind: b.kind,
status: b.status,
paid: Boolean(b.paidAt),
items: b.itemsCount,
total: money(b.itemsTotal, b.currency),
customer: b.contact?.name ?? b.contact?.email,
}));
}
export async function bookingDetail(id: string) {
const booking = await getBooking(uiduAdmin, { id }); // null with a public token
return booking && {
...booking,
answers: booking.fieldValuesByShortname, // custom fields, keyed by shortname
};
}getBookingaddspaymentIntentId,refundedAt,updatedAtand the custom-field mapfieldValuesByShortnameto what the list returns.- From a terminal:
uidu bookings list --json,uidu bookings get <id> --json.
API at a glance
Every @uidu/client function in Bookings & calendars, generated from the source — the full reference has the rest of the SDK.
| Function | Kind | Auth | CLI | Description |
|---|---|---|---|---|
getBooking | read | Bearer | bookings get | One booking with its contact, totals in cents and custom fields (fieldValuesByShortname), or null; a public token sees none. |
getCalendar | read | public token | — | One calendar (name, color, time zone), or null. |
getCalendarEvent | read | public token | — | One calendar event with its rich-text body and its calendar, or null. |
listBookings | read | Bearer | bookings list | The workspace's bookings as a flat array; page with first/after (or last/before); a public token gets an empty list. |
listCalendarEvents | read | public token | — | Calendar events as a flat array, optionally narrowed by calendarIds and named scopes (e.g. upcoming); page with first/after. |
listCalendars | read | public token | — | The workspace's calendars as a flat array; page with first/after (or last/before). |
Types: Booking, Calendar, CalendarEvent
CLI:
| Entity | list | get | create | update | delete |
|---|---|---|---|---|---|
bookings | ✓ | ✓ | — | — | — |