Booking and scheduling inside your app.

coss.com adds booking to your product. Hosts set hours and connect calendars, users book in your app, and the database refuses overlapping bookings.

Read the docs

The problem

A booking looks like one form. Behind it are time zones, calendars, races between two people and the emails that tell everyone what happened.

If people book people in your product, such as tutors, advisers or service providers, you need weekly hours that survive a clock change, calendars that stay in sync, and a guarantee that one time can't be sold twice. Then everyone has to hear about it: confirmations, reminders and calendar invitations.

coss.com does this on one API key. Scheduling holds the hosts, the availability and the bookings, email and SMS tell people about them, and the same webhooks and logs cover all three.

How it works

Set up hosts and event types on your server, then let people book in an embedded page or in your own UI.

// Who can be booked, when, and for what.
await ...({
  : "tutor_482",
  : "Ana Reyes",
  : "ana@example.com",
  : "America/New_York",
});

await ...("tutor_482", {
  : [{ : [1, 2, 3, 4, 5], : "09:00", : "17:00" }],
});

const { :  } = await ...({
  : "Trial lesson",
  : 30,
  : 10,
  : [{ : "tutor_482" }],
  : [{ : "google_meet" }],
});

// Emails from your own domain, and an SMS reminder from your approved number.
await ...({
  : ["https://app.example.com"],
  : "Acme Tutors",
  : "bookings@example.com",
  : "+14155550123",
  : { : { : true, : true } },
});

To use coss.com's booking page, your server creates a session for the signed-in user and the browser mounts it. Your API key stays on your server.

const { :  } = await ...({
  : ,
  : { : "customer_77", : "Sam Lee", : "sam@example.com", : "UTC" },
});
// Hand session?.url to the browser.
({
  : ,
  ,
  : () => {
    if (. === "booked") .("Booked", .);
  },
});

To build the page yourself, list the times and book one. A time someone else just took answers slot_unavailable.

const { :  } = await ...(, {
  : "2027-01-04T00:00:00Z",
  : "2027-01-11T00:00:00Z",
});

const {  } = await ...({
  : ,
  : !.[0]!.,
  : {
    : "customer_77",
    : "Sam Lee",
    : "sam@example.com",
    : "+14155550199",
    : "America/Chicago",
  },
});
if (?. === "slot_unavailable") {
  // Someone else got there first: show the times again.
}

Read more in the Scheduling guide, embedding and bookings.

What you get

Availability, calendars, the booking and telling people about it, on the key you use for the rest of coss.com.

No double-booking

A Postgres exclusion constraint refuses two overlapping claims of one host, buffers included. It holds under races, retries and second tabs, and the SDK's retries carry one Idempotency-Key, so a lost response can't book twice.

Calendars

Hosts connect Google, Microsoft or CalDAV calendars. Their busy times block slots and bookings go on the calendar they choose. A calendar that can't be read never counts as free.

Pages to embed, or your own UI

mountBooker and mountHostPortal open coss.com's pages in your app under your brand name. Or build your own on the API: coss.com's pages use the same client API a session's token gives a browser.

Email from your domain

Attendees and hosts get emails with calendar invitations when a booking is confirmed, moved or cancelled, from your verified domain or from coss.com on your behalf. You can turn any of them off.

SMS reminders

Attendees get a reminder a day before, by email and, if you turn it on, by text from your own approved number. A reply of STOP is always honored.

Holds for your payment flow

Hold a slot while you take payment with your own provider, then confirm it. Or set requires_approval, and the time stays blocked until the host approves or declines. See bookings.

Pools, panels and classes

A pool books any available host, collective needs every required host free at once, and group sells seats in one session. Series book up to 52 occurrences at the attendee's local time. See pools and groups.

Webhooks and manage links

Bookings and calendars send webhooks with ids, times and statuses, and attendees reschedule or cancel from a manage link that reaches only their booking.

Specifications

The limits of a booking. The docs list each one in context.

Calendars
Google, Microsoft, CalDAV
Meeting links
Google Meet, Microsoft Teams, or your own link
Event type kinds
one-on-one, pool, collective, group
Duration
5 minutes to 24 hours
Holds
10 minutes by default, 1 minute to 24 hours
Series
up to 52 occurrences, weekly or monthly
Slots per request
up to 62 days
Booker session
30 minutes by default, at most 24 hours
Attendee details kept
90 days after the booking ends
Bookings kept
395 days after the booking ends

Pricing

You pay per confirmed booking. Holds and pending approvals cost nothing until they're confirmed.

The Free plan includes 100 scheduling bookings a month. Booking emails sent from your own domain are billed like any email and SMS reminders like any text message, and live SMS needs a paid plan. Sandbox environments are free. See pricing for the plans.

Questions

How do I add booking to my app?
Add each person who can be booked with coss.scheduling.hosts.create(), give them a schedule, and create an event type. Your users then book in a page you embed with mountBooker from coss/scheduling, or in your own UI with coss.scheduling.slots.list() and coss.scheduling.bookings.create().
Does coss.com give hosts a public booking link?
No. Public booking pages aren't built. Every booking page opens from a short-lived session your server creates, in an iframe in your app or on its own, so you decide who gets to book and when.
How does coss.com prevent double-booking?
Every booking takes a claim on its host's time, buffers included, and a Postgres exclusion constraint refuses two claims of one host that overlap. Two people clicking at once, a second tab or a retry can't both win. The one who loses gets slot_unavailable, and you show them the times again.
Can coss.com take payment for a booking?
Not itself. Built-in payments aren't available. Hold the slot with coss.scheduling.holds.create(), charge the customer with your own payment provider, then call coss.scheduling.holds.confirm(). A hold keeps the time for ten minutes by default, tells nobody and isn't charged.
Which calendars can hosts connect?
Google and Microsoft through their consent screens, and CalDAV servers such as Apple's with an app-specific password. coss.com stores when each calendar is busy and nothing else, and adds bookings to the calendar the host chooses as private events titled "Appointment".
Can attendees get reminders by SMS?
Yes. Attendees get an email reminder a day before by default. Set sms_from to one of your approved numbers and turn on sms_attendee for reminders, and attendees who gave a phone number get a text too. Getting their consent is yours to do, a STOP is always honored, and live SMS needs a paid plan.
Can attendees reschedule or cancel on their own?
Yes. Confirmation emails carry a manage link, and coss.scheduling.sessions.createForBooking() makes one for your app. It reaches only that booking, follows the notice periods you set on the event type, and stops working when the booking is cancelled.
What counts as a billable booking?
One per confirmed booking, per occurrence of a series and per group session, however many people attend. Holds and pending approvals aren't charged, rescheduling is free and a cancelled booking stays charged. Sandbox environments are free. The pricing page has the rate.

The products

One key, one SDK, one log for all of them.

Build it this afternoon.

Hand your coding agent this prompt, then pick the parts you need:

Add coss.com to this project: read https://coss.com/llms.txt, get a development key with `npx coss-cli init --agents`, and build and test with it.

Pricing