tiempoAPI reference
Start here

Why AI-built booking apps double-book

Ask Claude Code, Cursor or Lovable for a salon booking app and you’ll get something that looks finished in an afternoon: services, staff, a calendar, a checkout. Underneath there’s usually the same scheduler: an appointments table and a check for overlaps before each insert.

It passes every test you’ll think to write, because tests run one request at a time. Customers don’t. This page is about what goes wrong in production, so you can decide whether to build the scheduling yourself or hand it to an API built for it.

Two customers, one slot

The check and the insert are two steps. When two customers pick the same slot within a few milliseconds (a Saturday morning, a popular barber, a class that just opened), both checks see an empty slot and both inserts succeed.

Fixing it properly means serialising bookings per resource: locking the staff member’s row, or an exclusion constraint on time ranges, inside a transaction, in the right order so that two bookings for two resources don’t deadlock. It’s a few lines once you know, and most generated code doesn’t.

The slot has to wait while they pay

Between choosing a time and finishing payment, a customer can take two minutes or twenty. If the slot isn’t held, someone else books it and the first customer pays for a time they don’t have. If it is held, the hold has to expire on its own when they give up, and a late payment must not confirm a slot that has since gone.

That’s a state machine (held, confirmed, expired, cancelled), a timer that releases holds even when no one is looking, and a confirm step that re-checks under the same lock.

Time is harder than it looks

  • Clock changes. “Every Tuesday at 9:00” is a different UTC time in March than in February, and one night a year 01:30 happens twice. Store local times naively and recurring bookings drift by an hour.
  • Several timezones. A chain with shops in London and Madrid, or a customer booking from abroad, needs each shop’s hours in its own zone.
  • Buffers. A 45-minute cut with 10 minutes of cleanup blocks 55 minutes, but the customer still sees 45.
  • More than one thing at once. A massage needs a therapist and a room; a colour needs the stylist for 30 minutes, then not for 30 while it develops, then again. “Anyone available” has to pick someone without two customers getting the same person.
  • Rotas, holidays and one-off changes: alternate Saturdays, a week off, a shop closed for a refit. Each one changes availability, and existing bookings that no longer fit need flagging, not silently keeping.

What Tiempo does instead

Tiempo is only the scheduling part, as an API. Your app keeps its services, prices, customers and payments.

  • Every booking locks the resources it touches, so the race above ends in one booking and one 409 booking_conflict, every time.
  • Holds expire on their own, and confirming a lapsed hold is refused.
  • Schedules are local wall-clock times in each location’s timezone; recurring bookings keep their local time through clock changes.
  • Buffers, multi-resource bookings, “anyone available”, rotas, blocks, overrides, classes with seats and recurring series are built in, and availability search uses the same engine as booking.
  • When hours change under existing bookings, Tiempo flags them and sends a webhook.

Try it in the quickstart, or give your coding agent the rules file so it uses Tiempo from the start.

When building it yourself is fine

Not every app needs this. Your own table is enough when:

  • One person takes bookings for themselves and can sort out the odd clash by phone.
  • There’s no payment step between picking a time and booking it.
  • Everything happens in one timezone, without recurring bookings, buffers or shared rooms.

If you’re building for many businesses (barbers, salons, studios, clubs), each with staff, rooms and customers paying online, that’s what Tiempo is for. If what you need is a personal booking page linked to your calendar, a calendar scheduling tool suits you better.