Skip to content

SDK reference

@mrcharles/sdk is zero-dependency TypeScript, shipped as ESM (import), as an IIFE for <script> (window.MrCharles) and with full types. About 11 kB gzipped. The usage guide is JavaScript SDK; this page is the surface.

OptionTypeDefaultNotes
env'production''production'The only public environment; kept for forward compatibility.
apiBase, appBase, sitesBasestringproduction hostsEndpoint overrides for tests and proxies.
fetchtypeof fetchglobalThis.fetchServer runtimes, tests, custom agents.
localestringsite defaultAny BCP-47 tag. Drives lang on links/embeds, the hold locale (mapped to es/ca/en), Accept-Language, t() and format.
publishableKeystring—Your pk_live_…/pk_test_… key, sent as X-MC-Key. It only works from the website origins you listed for it, gives no access to your account, and records bookings as made on your website. Secret (sk_) and restricted (rk_) keys are refused here.
headersRecord<string,string>—Extra headers on every request. Forwarding headers (X-Forwarded-For and the like) are ignored by the API.
MethodReturnsEndpoint
get(slug)PublicSiteGET /public/sites/{slug}
resolve(host)PublicSiteGET /public/sites/resolve?host=
availability(slug, roomId, { from, to })RoomAvailabilityGET /public/sites/{slug}/rooms/{roomId}/availability
quote(slug, roomId, { date, startTime, durationMinutes, groupSizeId?, partySize?, locale? })QuotePOST /public/sites/{slug}/rooms/{roomId}/quote
MethodReturnsEndpoint
create(slug, HoldRequest)HoldPOST /public/sites/{slug}/holds
verify(holdId, code)HoldPOST /public/holds/{id}/verify
resend(holdId)HoldPOST /public/holds/{id}/resend
confirm(holdId, { paymentMode, notes?, email? })ConfirmationPOST /public/holds/{id}/confirm
MethodReturnsEndpoint
get(manageToken)BookingGET /public/bookings/manage/{token}
cancel(manageToken, reason?)BookingPOST /public/bookings/manage/{token}/cancel
MethodReturns
profile(instructorUserId)TeacherProfile
offers(instructorUserId)LessonOffer[] (published only)
offer(offerId)LessonOffer
windows(instructorUserId, { from, to })TeacherWindows
policy(instructorUserId)LessonPolicy
slots({ instructorUserId, offerId, date, days? })LessonSlots
MethodBuilds
site(slug)https://{slug}.sites.mrcharles.app/
bookRoom({ slug, roomId, date?, start?, durationMinutes?, lang?, embed? })the hosted booking screen, prefilled
manage(slug, manageToken)the guest’s manage page
bookLesson({ instructorId, offerId?, attribution? })the app’s lesson booking screen; attribution from client.attribution.handoff()
teacherProfile(instructorUserId)the teacher’s profile in the app
MethodReturns
handoff(){ attribution, expiresAt }: a signed token valid 30 minutes. Needs a teacher’s publishableKey and a page on one of its origins.

client.mountRoomBooking(target, options) → EmbedHandle

Section titled “client.mountRoomBooking(target, options) → EmbedHandle”

target is a selector or element. Options are RoomLinkOptions plus onBooked({ reference, manageUrl }). The iframe resizes itself and only accepts messages from the hosted site’s origin. handle.destroy() removes it.

MemberWhat
locale / setLocale(tag)the client’s language (undefined = each site’s default)
hostedLocalewhat the hosted screen and messages will use: es, ca or en
t(key, params?)a UI string: mc.t('hint.resendsLeft', { n: 2 })
errorMessage(err)a guest-facing sentence for any error
formatprice, date, time, timeRange, duration, weekday, countdown
pick(localized, default?)one language out of { es, ca, en }

SDK strings exist for es, ca, en, fr, pt, it, de (LOCALES); the hosted screen for es, ca, en (HOSTED_LOCALES). Standalone: t, messageFor, translator, normalizeLocale, toHostedLocale, intlTag, createFormatter, MESSAGES.

client.roomBooking(options) → RoomBooking

Section titled “client.roomBooking(options) → RoomBooking”

The headless flow. options: slug, roomId, onChange(state), locale?. The state carries locale and errorMessage (the last error, translated); flow.t() and flow.setLocale() match the client’s.

MethodEffect on state.step
loadSite()→ pick (room, policy, captcha and Stripe keys on state.site)
loadAvailability({ from?, days? })fills state.days
startTimesFor(date, durationMinutes) / durationsFor(date, start)pure helpers on the loaded availability
rateAt(date, start, groupSizeId?)hourly rate hint at a start time, from the loaded availability
quote({ date, startTime, durationMinutes, groupSizeId?, partySize? })none; resolves the itemised price (labels in the flow’s language)
hold(details) — details.groupSizeId?, details.partySize?→ verify (state.hold, state.hold.devCode in sandbox)
verify(code) / resend()→ confirm
confirm({ paymentMode, notes?, email? })→ done (state.confirmation: reference, manageUrl, clientSecret for card)
reset()→ pick

MrCharlesError has code (the API’s error.code), status, requestId and three predicates:

  • slotIsGone — SLOT_TAKEN, OUTSIDE_HOURS, ROOM_NOT_BOOKABLE: offer another time.
  • holdIsDead — HOLD_EXPIRED, HOLD_NOT_FOUND, TOO_MANY_ATTEMPTS: start over.
  • isTransient — RATE_LIMITED, network, 5xx: wait, then retry once.

Publishable-key errors: KEY_INVALID, KEY_REVOKED, KEY_EXPIRED, KEY_ENV_MISMATCH, ORIGIN_NOT_ALLOWED (the page’s origin is not one of the key’s), TEACHER_KEY_REQUIRED (handoff() with a studio key).

isMrCharlesError(e) narrows unknown errors.

startTimes, durationOptions, toMinutes, toHHMM, addMinutes, formatPrice, dateKey, addDays, uuid, isTrustedOrigin, parseEmbedEvent, resolveEndpoints, ENVIRONMENTS, VERSION. Embed handles have setLang(tag).

Everything is exported from the package root: PublicSite, PublicRoom, RoomAvailability, Hold, HoldRequest, Confirmation, Booking, TeacherProfile, LessonOffer, LessonSlots, RoomBookingState, RoomStep, EmbedOptions, ErrorCode, Locale…

Semver. Minor versions add; majors may rename. The CDN path /sdk/v0/ tracks the latest 0.x; pin the npm version in production builds.