The Toolkit take
60/min
API requests allowed per TidyCal account, with no webhooks to push new bookings.
19
operations in the OpenAPI spec
Free types only
bookings the API can create
Read-only
MCP server for AI assistants

What the TidyCal API does, and where it stops

TidyCal offers a REST API on paid plans, documented as an OpenAPI 3.0.0 specification with 19 operations [1]. It authenticates with a personal Bearer token or an OAuth client, allows 60 requests a minute and has no webhooks [2]. A read-only MCP server sits beside it for AI assistants. That makes it a good tool for reading and a weak one for acting. It suits pulling bookings into a spreadsheet or CRM and creating free consultations from a custom page. It does not suit taking paid bookings, rescheduling sessions or reacting instantly to new bookings without polling.

Who gets a key, and why every developer's plan matters

API access requires a paid plan: Individual Lifetime, Agency Lifetime or Pro. Free accounts have no API. The detail that trips up teams is how plans apply to people. Personal features such as the API follow each member's own plan, not the team's. A team owner on Pro whose assistant is on Free cannot hand that assistant API access through the team, so every person who will call the API needs at least Individual Lifetime. Check every developer's plan. Then build. The plan details and what each one costs sit in our TidyCal pricing guide.

The documentation, the spec and its quirks

The API reference is published at tidycal.com/developer/docs as a Redoc page generated from the OpenAPI specification. The specification is version 0.1 and covers bookings, booking types, timeslots, contacts, account information, store orders and teams. It names its server as tidycal.com/api, and endpoints sit under that path. No version is placed in the path, so expect changes without a new prefix. Importing the specification into your API client saves a lot of typing, and it is the first thing worth doing.

The specification leaves gaps, though, so read the help center's automations article beside it. The spec documents no rate limits and no webhook endpoints, and the help article supplies the limit and the token steps. A few quirks also deserve a test. Several list filters appear as path parameters, though they behave as query filters. The spec declares no security schemes at all, while the documentation describes Bearer and OAuth. Test each call. Trust behavior over labels.

💡
Toolkit tip
Store the token immediately

Create a personal token under Manage API keys. It is shown only once, so put it in a secret manager and never commit it to code.

Authentication: personal tokens or OAuth

For your own scripts, create a personal token under Manage API keys and send it as a Bearer token on every request. The token is shown only once, so store it immediately in a secret manager and never commit it to code. Treat it like a password. Rotate tokens when staff leave, limit who holds them and keep scripts off shared machines. A good first call is /me, which returns account details and confirms which account a token belongs to. It is the simplest health check, and calling it once at startup costs a single request.

For apps used by other TidyCal users, OAuth clients are available. The flow is OAuth 2.0 with the authorization_code grant, with the authorize URL at tidycal.com/oauth/authorize and the token URL at tidycal.com/oauth/token. Personal tokens are for your own scripts. Use OAuth for anything multi-tenant, so each customer signs in with their own account and you never handle their personal tokens.

💡
Toolkit tip
Use OAuth for shared apps

For apps that other TidyCal users will connect, use the OAuth client flow instead of collecting their personal tokens.

Curious how TidyCal feels in practice?Try TidyCal →

Rate limits and the errors you will meet

The API allows 60 requests per minute per account [2]. Polling once a minute leaves plenty of room, but bulk jobs need pacing, backoff and caching. At 60 requests a minute, a sync that lists one page of bookings and then fetches each new booking separately can process up to 59 new bookings in a single minute. Only a large team would ever approach that in normal daily use. Pagination is simple: list endpoints take a page parameter, store orders return 100 per page, and you loop until a page comes back empty. Do not assume page sizes elsewhere.

The error codes, and the two that mean something

The specification lists 403 and 404 for forbidden or missing resources, 422 for invalid input and 400 on some cancels. Two codes carry more meaning. 402 Payment Required appears when creating a contact because a Lifetime subscription is required, and store orders are a paid-plan feature too, so check the plan before calling. 409 Conflict is duplicate protection: a second booking for the same email, booking type and slot within 5 minutes is refused. A web form that a client double-clicks therefore creates one booking and one 409 rather than two bookings. Treat 409 as already done, log it, and show the existing confirmation instead of reporting an error.

Working with bookings

Listing, filtering and fetching

GET /bookings lists bookings, with parameters for starts_at, ends_at, canceled, page and include_teams. The include_teams flag pulls team bookings into the same list, and the canceled flag includes or excludes canceled ones. Narrowing the window with starts_at and ends_at keeps responses small, so store the last time you polled and move forward from there. GET /bookings/{booking} returns one booking by ID and can return 403, 404 or 422. Use it after listing to fetch full details, but remember that each call counts toward the limit. Fetch only what changed.

Canceling, and the missing reschedule

PATCH /bookings/{booking}/cancel cancels a booking by ID, with an optional reason, and can return 400, 403 or 404. Canceling a paid booking does not refund it, so the refund has to happen in Stripe or PayPal as a separate step. There is no reschedule operation in the specification. The obvious workaround is to cancel and create a new booking, but paid bookings cannot be recreated through the API. For anything paid, send clients their reschedule link instead. That keeps payment intact.

Creating bookings: free types only

POST /booking-types/{bookingType}/bookings creates a booking. Name, email and timezone are required, plus starts_at for a single booking, and it returns 201, or 403, 409 or 422. It works only for free booking types [2]. Paid types refuse, because payment must happen on TidyCal's own checkout. A clinic building its own intake page can collect name, email and time zone, check timeslots and create a free consultation in two calls, but the paid follow-up session must still be booked on TidyCal's checkout page.

For package booking types, send a bookings array instead of a single starts_at, with one date per entry and the package size limiting the count. Validate against timeslots first, then submit once. The create call also accepts booking_questions with answers. Match them to the questions defined on the booking type, answer every required one and keep keys consistent, since the answers appear later in exports.

⚠️
Watch out
Paid bookings need TidyCal's checkout

The API cannot create bookings for paid booking types, and there is no reschedule endpoint. Send clients their booking or reschedule link for anything paid.

Booking types, timeslots, contacts and store orders

Booking types you can create but not edit

GET /booking-types lists booking types with a page parameter. Use the list to map IDs to names and cache it, because booking types change rarely. POST /booking-types creates one, with title, description, duration_minutes and url_slug required and optional fields for padding, availability, privacy, limits, guests, redirects, approval, price and currency. It returns 201 on success. The catch is that the specification lists no update or delete. Edits happen in the app, where deleting a type stops new bookings and keeps existing ones. A script that sets up a new consultant's standard services can create every type in one run, but any mistake has to be fixed by hand afterwards.

A few fields deserve attention before you run that script. Up to 10 guest invites per booker can be set. The availability interval runs from 15 to 1,440 minutes. Minimum notice, booking_threshold, defaults to 120 minutes and can be 0 to 15,000, so leaving the default means clients cannot book a slot less than two hours away. That suits prepared sessions, but services that want same-hour bookings should lower it toward zero. On pricing, payment_platform accepts stripe, paypal or tidycal, and currency uses ISO 4217 codes and defaults to the account currency. Payments still run through the connected processor. Test with a small price.

Timeslots and time zones

GET /booking-types/{bookingType}/timeslots lists open slots between starts_at and ends_at, respecting availability, buffers and calendar conflicts. Call it before creating a booking. Times come back as timestamps, and booking creation requires a timezone, while TidyCal converts availability for clients inside the app. Your own system has no such help. Store UTC and convert only for display, in the client's zone.

Contacts and store orders

GET /contacts lists contacts with a page parameter. Contacts come from bookings, the Calendly import or the API, and deleting a contact also deletes its bookings. Read freely. Delete with care. POST /contacts creates a contact with name and email required and timezone optional, and it can return 402 when a lifetime plan is required. Because the app has no CSV contact import, the API is the bulk route, as long as you pace the calls.

GET /me/store/orders lists storefront sales and booking add-ons, newest completed first, with pending and failed orders last and 100 per page on paid plans. The app's Sales page is read-only, so this is the route for sales reports. A nightly report gets the latest sales from the first pages quickly, but it must keep paging to find the failed checkouts worth following up.

Teams through the API

GET /teams lists the teams an account can access, and GET /teams/{team} returns one. That matters for agencies and multi-brand businesses: Agency Lifetime users can create unlimited teams, and Pro users run several brands as teams. Map team IDs once. GET /teams/{team}/bookings filters by start_date, end_date, email, host_id and canceled. Filtering by host_id month by month shows how unevenly round robin has spread sessions, since TidyCal assigns by priority with random tie-breaks and keeps no workload count. That report gives a manager the data to rebalance priorities by hand.

Membership is manageable too. GET /teams/{team}/users lists members, a POST adds a user by sending an invitation email, with email required and an optional role, and DELETE removes a user. Pending invitations count toward Agency seats, so watch the cap. Team booking types can be listed and created through their own endpoints, with the same create fields as personal types. They follow the owner's plan, and round robin and collective types need Agency Lifetime or Pro. As with personal types, edits still happen in the app.

Ready to put TidyCal to the test?Try TidyCal →

No webhooks, so you poll

TidyCal does not offer configurable webhooks [2]. To catch new bookings, you poll GET /bookings on a schedule. A sensible pattern is one list call per minute with starts_at set to the last run, a detail call only for IDs not seen before, and a nightly full sweep with the canceled flag. Store the IDs you have seen, log every 409 and 422, and back off when nearing 60 requests a minute. That pattern keeps a single account well under the limit. It is more work than a webhook, and it is never instant.

Zapier offers another route on paid plans, with three triggers: booking created, updated and canceled. Zapier hides the polling from you, which suits non-developers, though booking answers arrive in one field. For a CRM sync, either route works: poll every few minutes or use the Booking Created trigger, and handle cancellations with the canceled flag. TidyCal has no native CRM. Expect some glue code, or start from the no-code routes in our TidyCal integrations guide.

The read-only MCP server for AI assistants

TidyCal runs an MCP server at tidycal.com/mcp. It speaks MCP over HTTP, with nothing to install and no API key, and AI assistants can read your scheduling data through it [3]. It cannot create, change or cancel anything. It cannot edit availability or send messages either, so every action still happens in the app. It is a window, not a hand. Use it for questions only.

What it reads, and what it shares

The ten tools all read data: get-current-user, list-teams, get-team, list-booking-types, get-booking-type, list-booking-type-available-times, list-bookings, get-booking, list-busy-times and list-locations. Busy times cover Google, Microsoft and Apple calendars enabled for conflict checking, and bookings include booker name, email, phone, answers and payment status. Asked what next Tuesday looks like, a connected assistant can combine bookings, busy times and open slots into a useful morning briefing. Times come back in UTC, ISO 8601, unless noted, so ask the assistant to convert them.

That reach has a privacy cost. A practice that connects an assistant shares every client's name, email, phone number and intake answers with that AI provider whenever it asks about bookings. TidyCal says it does not sell assistant request data or use it to train models, but your AI provider's policy still applies. Decide who may connect, and put it in your own privacy notice first.

Connecting, and the plan question

Authentication is OAuth 2.1 with PKCE (S256) and dynamic client registration, with the authorization_code and refresh_token grants and a single scope, mcp:scheduling:read [4]. A compatible assistant registers itself, so the owner only approves the sign-in on TidyCal. In Claude, add tidycal.com/mcp as a custom connector. The MCP docs say ChatGPT custom connectors work on plans that support them, while the help article says other web-based assistants cannot sign in. Test your client.

The plan requirement is also contested. The MCP docs say Pro is required and that every call on a free plan returns a Pro-required error, and the privacy policy also ties assistant connections to Pro. The help article says any paid plan works. Assume Pro until tested. A lifetime owner should try connecting before relying on it, because on an ineligible plan the connection signs in but every call returns an error.

How it compares with Calendly's API

Calendly's API allows 500 requests per user per minute on paid plans and 50 on Free, offers custom webhooks on paid plans, and runs an MCP server with read and write scopes. TidyCal offers 60 a minute per account, no webhooks and read-only MCP. The difference is roughly eightfold on rate limits and categorical on actions. Calendly pushes events and lets an assistant write. TidyCal pushes nothing and lets an assistant only read. For a product built on scheduling, that decides the choice. If you stay with TidyCal and get stuck, email support@tidycal.com with request IDs and payloads; replies take about 8 hours on every plan, as our TidyCal customer service guide explains.

Frequently asked questions

Does TidyCal have an API?+

Yes, a REST API on paid plans (Individual Lifetime, Agency Lifetime or Pro), with Bearer tokens or OAuth 2.0 and 60 requests a minute.

Does TidyCal have webhooks?+

No. TidyCal does not offer configurable webhooks, so you poll the bookings endpoint on a schedule or use Zapier's booking created, updated and canceled triggers on a paid plan.

Can the TidyCal API create paid bookings?+

No. It can create bookings only for free booking types; paid sessions must go through TidyCal's own checkout page.

Can I reschedule or edit through the API?+

No. The specification has no reschedule operation and no update or delete for booking types, so those changes happen in the app.

Can AI assistants use TidyCal?+

Yes, through a read-only MCP server at tidycal.com/mcp with OAuth sign-in; it cannot book or cancel. The MCP docs say it needs Pro, while the help article says any paid plan works.

Does a team plan give every member API access?+

No. Personal features such as the API follow each member's own plan, so every person who calls the API needs at least Individual Lifetime.

The bottom line

The TidyCal API covers reading bookings, creating free bookings, setting up booking types and managing teams, and it fills gaps the app leaves, such as sales reports beyond the app's 30 days of income data. It lacks webhooks, rescheduling and paid booking creation, and MCP adds AI reading, not acting. That is fine for small automations and thin for serious integrations. A freelancer who wants bookings in a spreadsheet or a simple CRM will find the API and Zapier sufficient. A software team building a product on top of scheduling will run into the missing pieces quickly.

Sources
  1. [1] TidyCal API, OpenAPI specification (2026-10) https://tidycal.com/developer/docs/
  2. [2] TidyCal Help: tidycal automations (2026-10) https://help.tidycal.com/article/147-tidycal-automations
  3. [3] TidyCal Help: connect ai assistants to tidycal with mcp (2026-10) https://help.tidycal.com/article/1060-connect-ai-assistants-to-tidycal-with-mcp
  4. [4] TidyCal MCP server docs (2026-10) https://tidycal.com/mcp-docs