Embedding

Coss.com's pages in your app, or your own UI, without your API key in a browser.

Your API key stays on your server. For a browser, your server creates a session: short-lived, for one thing, with its token in the URL's fragment, which never reaches a server.

// On your server:
const { :  } = await ...({
  : ,
  // Someone you've signed in: the browser can't book as anyone else.
  : { : "patient_77", : "Sam Lee", : "sam@example.com", : "UTC" },
});
// Pass session?.url to the browser.

Open the url on its own, or embed it with coss/scheduling:

import { mountBooker, mountHostPortal } from "coss/scheduling";

mountBooker({
  url: session.url,
  container: document.getElementById("booking"),
  onEvent: (event) => {
    if (event.type === "booked") showThanks(event.booking_id);
  },
});

mountHostPortal({
  url: hostSession.url,
  container: document.getElementById("availability"),
});

The page's origin must be in your settings' allowed_origins:

await ...({
  : ["https://app.example.com"],
  : "Acme Health",
});

Events carry ids and statuses only. The pages tell your app ready, booked, rescheduled, cancelled, availability_saved, calendar_connected and error.

Your own UI

A session's token also works directly from a browser, against the client API at /scheduling/client/*, with Authorization: Bearer <token>. It's how coss.com's own pages work, so nothing they do is out of your reach. Calls are only accepted from your allowed_origins, and a session reaches only its own scope: an attendee sees times, never who else could take them.

Booker sessions have GET /session, GET /slots and POST /bookings. Manage sessions have GET /booking, GET /booking/slots, POST /booking/reschedule and POST /booking/cancel. Host sessions have /host/schedules, /host/calendar_connections, /host/calendars/{id} and /host/bookings.