Help

The QuantiMeet API

Your own code can work your team's calendar through the QuantiMeet API: make and change event types, find open times, book, move and cancel, list bookings and add webhooks, with your team's own key, on your team's own address.

LivePer-team API keys: each team's keys work on its own address only.

Each example says how it was checked. Most were run on October 17, 2026 on two test teams, one for each way QuantiMeet runs a team, by a script that checks every answer; each shows the call as it was sent and, in the dashed box below it, its answer, shortened, with the team's address, names, ids and secrets replaced. No key appears on this page: $QM_KEY stands for yours.

Start here

  1. Signed in, open your-team.quantimeet.com/settings/developer/api-keys and add a key, named after what will use it, with an expiry.
  2. Copy the key when it is shown: QuantiMeet keeps only a scrambled form of it (a hash), so it cannot show it again. Treat it like a password, and keep it on your server: never put one in a web page or an app.
  3. Put your team's address in a variable, then paste your key at the silent prompt read gives you and press Enter, so it stays out of your shell's history:
export QM="https://your-team.quantimeet.com/api/v2"
read -rs QM_KEY && export QM_KEY
curl -H "Authorization: Bearer $QM_KEY" "$QM/me"
{"status":"success","data":{"id":1,"username":"owner","email":"you@example.com","name":"Your Team",
  "timeZone":"America/Vancouver","defaultScheduleId":1, ...}}
Run on a test team on October 17, 2026. Run the first box, paste your key at its silent prompt and press Enter, then run the call. The answer is shortened.

Replace your-team with your team's address. /me answers with the profile of the person who made the key. Each command below runs as written in a Unix shell (macOS, Linux, or Git Bash or WSL on Windows); the dashed box under a command is its answer, shortened.

Your keys

Your address, and the version each call needs

Event types

List the key owner's own event types, hidden ones too:

curl -H "Authorization: Bearer $QM_KEY" -H "cal-api-version: 2024-06-14" "$QM/event-types"
Run on a test team on October 17, 2026.

Without a key, name a person to get their public event types. Every new team's owner has the username owner:

curl -H "cal-api-version: 2024-06-14" "$QM/event-types?username=owner"
{"status":"success","data":[{"id":1,"slug":"intro-call","title":"Intro Call","lengthInMinutes":30,
  "locations":[{"type":"integration","integration":"jitsi"}],
  "bookingUrl":"https://your-team.quantimeet.com/owner/intro-call", ...}]}
Run on a test team on October 17, 2026. The answer is shortened.

Make one: a title, a slug for its link and its length. It takes your default video location, a QuantiMeet Video room, unless you send locations:

curl -X POST "$QM/event-types" -H "Authorization: Bearer $QM_KEY" \
  -H "cal-api-version: 2024-06-14" -H "Content-Type: application/json" \
  -d '{"title":"Planning session","slug":"planning-session","lengthInMinutes":30}'
{"status":"success","data":{"id":2,"slug":"planning-session","title":"Planning session",
  "lengthInMinutes":30,"hidden":false,"locations":[{"type":"integration","integration":"jitsi"}], ...}}
Run on a test team on October 17, 2026 (201), its title and slug replaced. The answer is shortened.

Read it, change it, and delete it, by its id:

curl -H "Authorization: Bearer $QM_KEY" -H "cal-api-version: 2024-06-14" "$QM/event-types/2"
Run on a test team on October 17, 2026.
curl -X PATCH "$QM/event-types/2" -H "Authorization: Bearer $QM_KEY" \
  -H "cal-api-version: 2024-06-14" -H "Content-Type: application/json" \
  -d '{"title":"Planning call","description":"A first look at your project."}'
Run on a test team on October 17, 2026 (200), with its words replaced. Send only the fields you change.
curl -X DELETE "$QM/event-types/2" -H "Authorization: Bearer $QM_KEY" -H "cal-api-version: 2024-06-14"
Run on a test team on October 17, 2026 (200; it then reads 404).

A key changes and deletes only its own person's event types. Round-robin and collective event types are made in the dashboard; their open times and bookings work through the API by their id, as any other event type's do.

Open times

curl -H "cal-api-version: 2024-09-04" \
  "$QM/slots?eventTypeId=1&start=2027-02-02T07:00:00Z&end=2027-02-03T06:59:59Z&timeZone=America/Vancouver"
{"data":{"2027-02-02":[{"start":"2027-02-02T00:00:00.000-07:00"},
  {"start":"2027-02-02T00:30:00.000-07:00"}, ...]},"status":"success"}
Run on test teams on October 17, 2026, whose hours were the whole day: 48 open times of 30 minutes, shortened. A team with working hours gets times inside them only.

Book

curl -X POST "$QM/bookings" -H "Authorization: Bearer $QM_KEY" \
  -H "cal-api-version: 2024-08-13" -H "Content-Type: application/json" \
  -d '{"start":"2027-02-02T16:00:00Z","eventTypeId":1,
       "attendee":{"name":"Sam Lee","email":"sam@example.com","timeZone":"America/Vancouver"}}'
{"status":"success","data":{"id":12,"uid":"BOOKING_UID","status":"accepted",
  "start":"2027-02-02T16:00:00.000Z","end":"2027-02-02T16:30:00.000Z","duration":30,
  "location":"https://meet.quantimeet.com/...","attendees":[ ... ],"hosts":[ ... ], ...}}
Run on test teams on October 17, 2026 (201), the attendee's name and address replaced. The answer is shortened.

Read, move and cancel

curl -H "Authorization: Bearer $QM_KEY" -H "cal-api-version: 2024-08-13" "$QM/bookings/BOOKING_UID"
Run on test teams on October 17, 2026.
curl -X POST "$QM/bookings/BOOKING_UID/reschedule" -H "Authorization: Bearer $QM_KEY" \
  -H "cal-api-version: 2024-08-13" -H "Content-Type: application/json" \
  -d '{"start":"2027-02-02T16:30:00Z","reschedulingReason":"The client asked to move it"}'
{"status":"success","data":{"uid":"NEW_BOOKING_UID","rescheduledFromUid":"BOOKING_UID",
  "status":"accepted","start":"2027-02-02T16:30:00.000Z", ...}}
Run on test teams on October 17, 2026 (201). The answer is shortened.
curl -X POST "$QM/bookings/NEW_BOOKING_UID/cancel" -H "Authorization: Bearer $QM_KEY" \
  -H "cal-api-version: 2024-08-13" -H "Content-Type: application/json" \
  -d '{"cancellationReason":"The client cannot come"}'
{"status":"success","data":{"uid":"NEW_BOOKING_UID","status":"cancelled", ...}}
Run on test teams on October 17, 2026 (200). The answer is shortened.

List bookings

curl -H "Authorization: Bearer $QM_KEY" -H "cal-api-version: 2024-08-13" \
  "$QM/bookings?status=upcoming&sortStart=asc&take=50&skip=0"
{"status":"success","data":[ ... ],"pagination":{"totalItems":1,"remainingItems":0,"returnedItems":1,
  "itemsPerPage":50,"currentPage":1,"totalPages":1,"hasNextPage":false,"hasPreviousPage":false}}
Run on test teams on October 17, 2026. The answer is shortened.

Filters: status (upcoming, recurring, past, cancelled, unconfirmed; several with commas), attendeeEmail, eventTypeId, and afterStart and beforeEnd (times with their offset). Pages: take and skip. Without a key, the list answers 403.

Webhooks

LiveA webhook receives a signed message for each booking and each cancellation of its event type.

Add one on an event type, switched off, with its secret; switch it on ("active":true) once your receiver is ready. Its address must be HTTPS on a public host: private and internal addresses are refused (400). You can also add one on the event type's Webhooks tab in your dashboard.

curl -X POST "$QM/event-types/1/webhooks" -H "Authorization: Bearer $QM_KEY" \
  -H "Content-Type: application/json" \
  -d '{"active":false,"subscriberUrl":"https://example.com/hooks/quantimeet",
       "triggers":["BOOKING_CREATED","BOOKING_CANCELLED"],"secret":"YOUR_WEBHOOK_SECRET"}'
{"status":"success","data":{"id":"WEBHOOK_ID","eventTypeId":1,"active":false,
  "subscriberUrl":"https://example.com/hooks/quantimeet","triggers":[ ... ],"secret":"YOUR_WEBHOOK_SECRET", ...}}
Run on test teams on October 17, 2026 (201), its address and secret replaced. The answer is shortened.
curl -X PATCH "$QM/event-types/1/webhooks/WEBHOOK_ID" -H "Authorization: Bearer $QM_KEY" \
  -H "Content-Type: application/json" -d '{"triggers":["BOOKING_CREATED"]}'
curl -H "Authorization: Bearer $QM_KEY" "$QM/event-types/1/webhooks"
curl -X DELETE "$QM/event-types/1/webhooks/WEBHOOK_ID" -H "Authorization: Bearer $QM_KEY"
Change, list and delete: run on test teams on October 17, 2026 (200 each). Switching a test webhook on was not run here: it would have sent a message.

Each message is a POST with Content-Type: application/json, X-Cal-Webhook-Version: 2021-10-20 and X-Cal-Signature-256: the HMAC-SHA256 of the exact body, under your secret, in hex.

{"triggerEvent":"BOOKING_CREATED","createdAt":"2026-10-14T10:28:04.715Z",
 "payload":{"uid":"BOOKING_UID","bookingId":1,"eventTypeId":1,"status":"ACCEPTED",
   "title":"Intro Call between owner and Sam Lee",
   "startTime":"2026-10-15T16:00:00Z","endTime":"2026-10-15T16:30:00Z",
   "organizer":{ ... },"attendees":[ ... ],
   "metadata":{"videoCallUrl":"https://meet.quantimeet.com/ROOM"},
   "bookerUrl":"https://your-team.quantimeet.com", ...}}
As a test team received it on October 14, 2026, shortened, with its names and links replaced.

Check the signature

import hashlib, hmac

def from_quantimeet(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected.encode(), (signature or "").encode())
Python. Tested against a body signed the way QuantiMeet signs it, and against the same body with one byte changed.
const crypto = require("node:crypto");

function fromQuantiMeet(rawBody, signature, secret) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected), b = Buffer.from(String(signature || ""));
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Node, tested the same way.

Limits

curl -si -H "Authorization: Bearer $QM_KEY" "$QM/me" | grep -i '^x-ratelimit'
x-ratelimit-limit-default: 120
x-ratelimit-remaining-default: 119
x-ratelimit-reset-default: 60
Run on test teams on October 17, 2026: a key's first call.
{"status":"error","timestamp":"2026-10-18T01:48:23.170Z","path":"/v2/me",
 "error":{"code":"ThrottlerException","message":"CustomThrottlerGuard - Too many requests. Please try again later.", ...}}
The 429, measured on October 17, 2026 in Vancouver (October 18 in UTC, as its timestamp says) on a test key given a limit of 3 calls a minute: its fourth call. The answer is shortened.

Errors

An error answers with its HTTP status and a body like this one, for a call with no key:

curl "$QM/me"
{"status":"error","timestamp":"2026-10-18T01:42:48.709Z","path":"/v2/me",
 "error":{"code":"UnauthorizedException","message":"ApiAuthStrategy - No authentication method provided. ...", ...}}
Run on test teams on October 17, 2026 in Vancouver (October 18 in UTC, as its timestamp says). The answer is shortened.

Times and time zones

Check the time zone data your own code uses. Each line must show -07:00; -08:00 means data older than BC's new rule. On Windows, type python for python3; Python there may need the tzdata package (pip install tzdata).

python3 -c "from datetime import datetime; from zoneinfo import ZoneInfo; print(datetime(2027,2,2,9,tzinfo=ZoneInfo('America/Vancouver')).isoformat())"
node -e "console.log(new Intl.DateTimeFormat('en-US',{timeZone:'America/Vancouver',timeZoneName:'longOffset'}).format(new Date('2027-02-02T16:00:00Z')))"
Run on our own computer on October 17, 2026: 2027-02-02T09:00:00-07:00, and 2/2/2027, GMT-07:00.

More in Time zones.

What your address answers

These parts of the API: your profile (/me), event types, bookings, open times (/slots), schedules, your connected calendars and their busy times (/calendars), conferencing apps, destination and selected calendars, webhooks, and the time zone list. You connect a calendar and a video app in your dashboard, not through the API.

Anything else answers 404, "This endpoint is not available on a team host." That includes organizations, managed users, OAuth clients and platform tokens (a business on QuantiMeet is one team, with its own keys), making or refreshing a key (/api-keys), teams (/teams), and Stripe and verified-resource endpoints.

Still stuck? Email info@quantimeet.com. We answer support requests by email within one business day, and usually within hours.

Is something not working for everyone? The status page shows what our own checks see, every 5 minutes.