API reference
The Tiempo API answers “when can this be booked?” and places bookings safely for every business on your platform. It’s organised around objects with predictable URLs, takes and returns JSON, and uses standard HTTP status codes.
Tiempo owns time and its state. Your platform keeps services, prices, payments, customers and messages. Every change Tiempo makes is recorded as an event and sent to your webhook endpoint.
Authentication
Send your secret key as a bearer token on every request. Keys belong to your platform and are created in the dashboard. Keep them on your servers, never in browsers or mobile apps.
tpt_…- Test key. Works on test data only. Issued when you sign up.
tpk_…- Live key. Real businesses and real bookings. Issued when you activate live mode.
tpw_…- Webhook signing secret, one per endpoint. Verifies deliveries; can’t call the API.
Keys are shown once. Tiempo stores only a hash, so a lost key can’t be recovered: create another and revoke the old one. Each key carries a checksum, so a mistyped key fails fast and secret scanners can recognise leaked ones.
Acting for a business
Each business on your platform is an account. Requests that read or change a business’s resources, schedules or bookings carry its id in the Tiempo-Account header. Accounts, webhook endpoints, events and usage belong to your platform and don’t need it.
Accounts are isolated. An id from one account returns 404 when used under another, so a bug in your code can’t leak one business’s bookings into another’s.
Test and live mode
Test and live are separate worlds, and the key you send decides which one a request touches. Every object carries livemode so you can tell them apart in logs and webhooks.
Real behaviour against test data, including holds, races and webhooks. Counted, never billed.
Real businesses and real bookings. Confirmed bookings beyond the free allowance are billed.
Requests and lists
Timestamps are ISO 8601 instants in UTC. Local times are HH:mm, local dates YYYY-MM-DD, timezones IANA names. Updates are POST with only the fields you’re changing.
Lists return { "object": "list", "data": [...], "has_more": true }, newest first. Page with limit (up to 100) and starting_after or ending_before an id from the list. Filter on your own keys with metadata[key]=value.
Unknown body fields and unknown query parameters are rejected with 400 parameter_unknown, so a typo fails loudly instead of quietly returning the wrong thing.
Send an Idempotency-Key header on any POST to retry it safely: the first response is stored for 24 hours and replayed (with Idempotent-Replayed: true). The same key with a different body is a 400.
Versioning
Breaking changes ship as dated versions (the latest is 2026-10-04). Your platform is pinned to the version that was current when you signed up, so nothing changes under you until you upgrade in the dashboard. You can roll back for 72 hours.
Send Tiempo-Version to try another version on one request; every response says which version it used. Adding fields, endpoints, event types or enum values isn’t breaking, so ignore fields you don’t know and treat enums as open.
Errors
2xx means it worked, 4xx means the request can be fixed, and 5xx means Tiempo had a problem. Errors share one shape: type, a machine-readable code, a message for people, and param naming the field at fault.
200It worked.400The request is malformed, a parameter is unknown, or a value is invalid. error.param names it.401No key, or a revoked one.403The key can’t do this, for example a test key on live data, or the platform is suspended (platform_suspended).404No such object for this business, or it belongs to another.409The time isn’t free, or the object is in the wrong state for this action.413The request body is over 1 MB.429Too many requests: over your platform’s limit for the second (rate_limited). Wait Retry-After seconds and try again.5xxSomething went wrong at Tiempo. Safe to retry with the same Idempotency-Key.
A 409 booking_conflict means the time isn’t free, with a reason per segment. Offer the customer other times; retrying the same slot won’t help.
Every response carries a Request-Id header (req_…). Log it with errors: quoting it to us finds exactly that request.
Each platform can make 100 requests a second in live mode and 25 in test mode; ask us if you need more. Every response says where you are with RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds). Over the limit you get 429 rate_limited with Retry-After: wait that long and retry with the same Idempotency-Key.
Webhooks
Every change is recorded as an event in the same transaction as the change, then POSTed to each of your endpoints that wants it. One endpoint hears from every business on your platform.
- Answer with any 2xx within 10 seconds. Do slow work after you reply.
- Anything else is retried with backoff for about three days. If every delivery to an endpoint fails for three days, Tiempo turns it off; turn it back on and resend what it missed.
- Deliveries can arrive more than once or out of order. Use the event id to skip duplicates.
Check Tiempo-Signature with the endpoint’s tpw_ secret before trusting a delivery. For local development, run java tools/WebhookListener.java from the Tiempo repo; it registers itself and checks every signature.
Reference by topic
- AccountsAn account is one business on your platform: a salon, a padel club. Create one as each business signs up to your product and keep its id next to your own record. Platform-level: no Tiempo-Account header.
- LocationsA place resources work at, with its own timezone. Locations can be closed with blocks.
- ResourcesAnything bookable: a worker, a room, a court. A resource is bookable only inside its schedules: one with none is closed until you give it hours. Capacity above 1 is a pool of identical units.
- SchedulesWorking hours for one resource, versioned by date. Several weeks make a rotation. Times are local wall-clock, so 09:00 stays 09:00 through daylight saving.
- Schedule overridesReplace one resource’s hours for one local date. An empty list means not working that day.
- BlocksTime off, closures, maintenance, lunch. A block targets a resource, a location, or the whole business, for a period or for whole local dates.
- AvailabilityAsk what can be booked before you show times to a customer. The same engine checks every booking, so a time it offers will be accepted unless someone takes it first.
- BookingsTime held on one or more resources. A booking starts pending (a hold that expires after 15 minutes by default) and becomes confirmed when you confirm it. Placing a booking locks its resources first, so when two requests race for the same time exactly one wins.
- AttendeesA booking with seats is a session (a class, a group). Each attendee takes seats with the same hold-then-confirm flow. Never oversold.
- SeriesRecurring bookings from an RRULE, created as real bookings over a rolling horizon. A date that doesn’t fit is skipped and reported, not failed.
- EventsEvery change is an event, written in the same transaction as the change. The same events go to your webhook endpoints; this API lets you catch up if your endpoint was down.
- Webhook endpointsWhere Tiempo sends events. One endpoint hears from every business on your platform. Each endpoint reports its health: when it last worked, and since when it has been failing. One that fails every delivery for 3 days is turned off (disabled_reason "failing") until you turn it back on; then resend what it missed. Platform-level: no Tiempo-Account header.
- UsageBookings counted towards your bill, per month and per business. Platform-level.