Read a booking
const url = 'https://api.keptslot.com/v1/public/bookings/example';const options = {method: 'GET'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url https://api.keptslot.com/v1/public/bookings/exampleThis endpoint gives one booking and the business that holds it. The token in the path is the only credential. There is no login on this surface.
An unknown token, an expired token, and the token of a cancelled booking give the same 404. A cancellation clears the token. Then the booking resolves to no row, the same as a token that never existed.
Use can_cancel and can_reschedule to enable the buttons. Each one
is true exactly when that call succeeds. They are not copies of each other. You can cancel a pending booking inside the notice window. You cannot move it.
Parameters
Section titled “ Parameters ”Path Parameters
Section titled “ Path Parameters ”Responses
Section titled “ Responses ”The booking and its business.
object
object
In the business’s timezone. The appointment happens at the business.
object
The price in the smallest currency unit. It is null when the business does not publish a price.
Plain text written by the business. Render it as text. Do not render it as markup.
Whether this service takes a payment when it is booked, and of what
kind. One of none, full, deposit_fixed or deposit_percent.
Show the requirement before the customer fills in the form. A card
is asked for after the booking is created, which is too late to be
the first the customer hears of it.
What the customer pays at booking time, in the smallest currency unit. It is computed for you: do not work it out from a percentage yourself, because the rounding rule lives on the server and two implementations of it will disagree.
It is null when payment_mode is none, and also when the service
is misconfigured such that no amount can be computed. In that
second case the service cannot be booked at all, so show it as
unavailable rather than asking for a payment that will be refused.
The heading this service groups under, matching an id in the
bootstrap’s categories array. Null means uncategorised: put it
in a final “Other” group, or in no group at all when that is the
only group.
On PUT /v1/services/{id} this field is IGNORED. That endpoint is
a full replace, and honouring it would mean a client that has
never heard of categories strips a business’s grouping every time
it syncs. Categories are set from the dashboard.
A bookable calendar. A calendar is not a person with a login. See the glossary.
object
What this person does, such as “Senior stylist”. Plain text. Render it as text, never as markup. Null when the business has not written one – show the name alone and reserve no space.
A short line about this person. Same rules as title.
object
True when the notice window is the reason
can_cancel is false. For a past booking it is
false, because the status is the reason instead.
How long before the start time cancellation closes. A value of 0 means cancellation stays open until the start time.
What has happened to the money for a booking that has already been paid for. It is absent when the booking took no payment.
This is the customer’s view. It carries no Stripe identifiers and no client secret: the payment is already made, and there is nothing left to confirm.
object
One of initializing, requires_payment, processing,
succeeded, partially_refunded, refunded, refund_pending
or canceled. A disputed payment stays succeeded: the money was
taken, and a dispute is not a status.
A snapshot taken when the booking was made. Changing the service’s price later never changes it.
Zero when nothing has been refunded.
The business’s own refund policy, word for word. We never parse it and we never compute a refund from it. Show it as written.
Present only while status is requires_payment, so the customer
can finish a payment they have not completed. Use it to mount
Stripe’s Payment Element on connected_account_id.
This is what makes a payment resumable. The secret returned when the booking was created works once and is held only in that browser tab, so a refresh, a closed tab or a return from the customer’s bank would otherwise leave the customer unable to pay for a slot their own booking is still holding.
Present under the same condition as client_secret.
True when the payment could be resumed but Stripe could not be reached to resume it. Absent otherwise.
Treat it as “try again shortly”, not as a failed payment and not as
a lost booking. The slot is still held. It exists so this case is
distinguishable from the other reasons no secret is present:
initializing has no payment set up yet, and processing means the
customer has already paid and must not be asked to pay again.
When the slot stops being held, present while the payment is still unsettled. Show the time. Do not compute it from a fixed number of minutes.
object
Null when the workspace has no usable key. A customer can still view and cancel the booking. A reschedule needs the key, so it is not available.
The same note the bootstrap carries. Show it once the booking is confirmed. A booking that takes a deposit redirects here to pay and never sees the booking flow’s confirmation screen, so this is the only place those customers can read it. Plain text – render it as text, never as markup.
Example generated
{ "booking": { "id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "status": "example", "starts_at": "2026-04-15T12:00:00Z", "ends_at": "2026-04-15T12:00:00Z", "service": { "id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "name": "example", "duration_minutes": 1, "price_cents": 1, "description": "example", "payment_mode": "example", "payment_amount_cents": 1, "category_id": "example" }, "staff": { "id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "name": "example", "title": "example", "bio": "example" }, "customer": { "name": "example", "email": "example", "phone": "example" }, "can_cancel": true, "cancel_cutoff_passed": true, "cancel_cutoff_minutes": 1, "can_reschedule": true, "payment": { "status": "example", "amount_cents": 1, "currency": "example", "amount_refunded_cents": 1, "refund_policy": "example", "client_secret": "example", "connected_account_id": "example", "payment_unavailable": true, "hold_expires_at": "2026-04-15T12:00:00Z" } }, "workspace": { "slug": "example", "name": "example", "timezone": "example", "currency": "example", "vertical": "example", "publishable_key": "example", "blurb": "example", "terms_url": "example", "website_url": "example", "instagram_url": "example", "maps_url": "example", "confirmation_note": "example" }}There is no such resource in this workspace.
object
object
A stable machine-readable code. Match on this.
A sentence for a person. Do not match on this.
The field that caused the refusal, if one field did.
The plan limit that refused the request. It is present only on a 402, and only for a secret key or an account key. See the errors guide.
The current count for that dimension. It is present only on a 402, and only for an account key. It is absent when the refusal has no count to report. Absent and zero are different answers.
The cap for that dimension. It is present only on a 402, and only for an account key. A cap of zero is a real value.
Example generated
{ "error": { "type": "example", "message": "example", "param": "example", "dimension": "example", "used": 1, "limit": 1 }}