REST quickstart
Prepare a host and key
Section titled “Prepare a host and key”Run your own instance, sign in, and use Settings, Availability and Event
types to set a profile handle, working hours and an active individual event type. For the
examples below the booking page is /ada/intro. Replace it with your own handle/slug.
Open API keys at /app/api-keys, create a key for the intended organization and copy it
once into your secret store. It acts as its creator in that organization. Keep API keys and
booking manage tokens out of URLs, shared transcripts and source control. Set these shell
variables privately (placeholders below are not working credentials):
export HOURMERE_URL='http://localhost:3000'export HOURMERE_API_KEY='<your API key>'curl --fail-with-body "$HOURMERE_URL/api/v1/me" \ -H "Authorization: Bearer $HOURMERE_API_KEY"Use /api/v1/openapi.json on your instance as the full request/response reference. Strict
request schemas reject unknown fields. Errors use { "error": "stable_code", "message": "…" }.
Find a time
Section titled “Find a time”Choose a future UTC range within the event type’s booking window, at most 62 days. The public slots endpoint returns UTC instants:
curl --fail-with-body --get "$HOURMERE_URL/api/v1/public/ada/intro/slots" \ -H "Authorization: Bearer $HOURMERE_API_KEY" \ --data-urlencode 'start=2026-11-02T00:00:00Z' \ --data-urlencode 'end=2026-11-04T00:00:00Z'Adjust these example dates so they remain in the future. Take the desired returned slot’s
start unchanged. For local date/time-zone queries, the MCP find_available_slots tool
performs that conversion. A selected Google calendar with missing, failed or stale sync yields
calendar_sync_unavailable; fix or deliberately disable that calendar instead of assuming
unknown busy data is free.
Create and manage one booking
Section titled “Create and manage one booking”Bookings send email to the host/invitee when workers are enabled. Additional guests require
the host to enable allowGuests on the event type (off by default, at most ten). Otherwise
nonempty guests return 400 guests_not_allowed. Existing guests keep receiving updates
and cancellations after the host disables new guests. Use
an address you control for a test. Use a new idempotency key per intended booking and keep
the same body/key for retries:
curl --fail-with-body "$HOURMERE_URL/api/v1/public/ada/intro/bookings" \ -H "Authorization: Bearer $HOURMERE_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: <new random UUID>' \ -d '{"start":"<chosen slot start>","invitee":{"name":"Test Invitee","email":"<your test address>","timeZone":"America/Los_Angeles"}}'Save the returned manageToken privately. Only its hash is stored; it is returned once. A
same-key retry returns HTTP 200 (rather than 201) with the original booking and
manageToken: null. Reusing the key with different arguments fails with idempotency_key_reused; use a new key for a genuinely new booking.
The public booking and invitee management endpoints do not require an API key; the examples include it for consistency with the authenticated calls above. A public create request’s idempotency key uses the shared anonymous namespace for that organization, so make it random. For invitee management send the manage token in a header. Choose a new available slot for rescheduling; it returns a replacement booking and a new manage token:
curl --fail-with-body "$HOURMERE_URL/api/v1/bookings/manage/reschedule" \ -H "Authorization: Bearer $HOURMERE_API_KEY" \ -H "X-Manage-Token: $HOURMERE_MANAGE_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"start":"<new slot start>"}'Use the new token for subsequent operations. Cancelling with the current token:
curl --fail-with-body "$HOURMERE_URL/api/v1/bookings/manage/cancel" \ -H "Authorization: Bearer $HOURMERE_API_KEY" \ -H "X-Manage-Token: $HOURMERE_MANAGE_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"reason":"Test cleanup"}'An API response token stays with the cancelled booking after an invitee move and follows
host moves. The token in a booking email always follows the reschedule chain. Treat both as credentials. The public management page carries email tokens
in a fragment (/booking#token=…); API calls use headers, never query parameters. Set HOURMERE_MANAGE_TOKEN privately to the
current returned token before running either management example.
List the key owner’s hosted bookings with GET /api/v1/bookings. A key does not grant access
to arbitrary hosts’ private bookings. Results default to ascending start time and ID; request
order=desc for newest first. Pass nextCursor as cursor and keep the time filters and
order unchanged for every page. Rate limits return 429 and Retry-After; slot races
return slot_taken or slot_unavailable. Recheck availability before retrying with a new key.
To move a booking you host, read GET /api/v1/bookings/{id}/slots?start=…&end=…, then
send POST /api/v1/bookings/{id}/reschedule with JSON { "start": "<chosen slot start>" }.
Both require a session or API key in the booking’s organization. Slots ignore the current
booking, so the new time may overlap it. A host move returns the successor booking with
manageToken: null and preserves existing invitee links. The web booking detail page uses
these same public APIs. Do not retry a move automatically; inspect your booking list if
the answer is lost.