Skip to content
Keptslot
Start free

Read a booking page

GET
/v1/public/workspaces/{slug}
curl --request GET \
--url https://api.keptslot.com/v1/public/workspaces/example

This endpoint gives one slug’s workspace, its bookable services and calendars, and the questions its booking form asks.

It carries no API key. The response includes the workspace publishable key, and every later call carries that key.

require_verification warns the customer that a 6-digit code follows. Do not use it to decide the next screen. Use the status on the create response instead. A business can change this setting at any time.

slug
required
string

The workspace and its bookable content.

Media type application/json
object
workspace
required
object
slug
required
string
name
required
string
timezone
required

An IANA zone name, such as Europe/London.

string
currency
required
string
publishable_key
required

The pk_ key for later calls. It is public by design. It is not a secret.

string
require_verification
required
boolean
sms_enabled
required

True when the business sends text messages as well as email. The phone field is optional for every business, whatever this value is.

boolean
vertical
required

Selects the customer-facing words, such as appointment or meeting. It changes copy only. It never changes booking mechanics.

string
booking_policy
string | null
contact_email
string | null
contact_phone
string | null
blurb

A short line about the business, shown under its name. Plain text. Render it as text, never as markup. Null when the business has not written one, which is the usual case.

string | null
terms_url

The BUSINESS’s own terms, not the platform’s. Show it alongside ours and label it so a customer can tell whose is whose. Always http or https.

string | null
website_url
string | null
instagram_url
string | null
maps_url
string | null
confirmation_note

Shown on the confirmation screen after the booking succeeds. What to bring, where to park, the door code. Plain text – render it as text, never as markup. Null is the usual case and renders nothing at all.

string | null
social_title

For the link card only, when someone pastes the booking link into a message. Crawlers do not run JavaScript, so nothing rendered in a browser can use this. Fall back to the business name when it is null.

string | null
social_description
string | null
allow_staff_choice

False when the business does not let customers pick who they see. Omit the staff step and send no staff_id. The create endpoint already treats staff_id as optional, so nothing else changes.

boolean
refund_policy

The business’s refund terms, for disclosure BEFORE a customer picks a service that takes a deposit. Plain text, passed through verbatim. We never parse it and never compute a refund from it.

string | null
services
required
Array<object>
object
id
required
string format: uuid
name
required
string
duration_minutes
required
integer
price_cents

The price in the smallest currency unit. It is null when the business does not publish a price.

integer | null
description

Plain text written by the business. Render it as text. Do not render it as markup.

string | null
payment_mode

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.

string
payment_amount_cents

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.

integer | null
category_id

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.

string | null
staff
required
Array<object>

A bookable calendar. A calendar is not a person with a login. See the glossary.

object
id
required
string format: uuid
name
required
string
title

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.

string | null
bio

A short line about this person. Same rules as title.

string | null
categories

The headings services group under, in the order the business set. Always an array, never null. Empty when the business has created none, which renders as no grouping at all. Do not re-sort it: the order is the business’s and is decided on the server.

A service whose category_id is null, or names no category here, belongs in a final “Other” group – or in no group at all when that is the only group.

Array<object>
object
id
required
string format: uuid
name
required
string
position
required
integer
questions
required
Array<object>
object
id
required
string format: uuid
label
required

Plain text written by the business. Render it as text.

string
help_text
string | null
type
required
string
options
required
Array<string>
required
required
boolean
applies_to
required

The scope of the question. If the value is selected_services, then service_ids lists the services it applies to.

string
service_ids
required
Array<string>
position
required
integer
Example generated
{
"workspace": {
"slug": "example",
"name": "example",
"timezone": "example",
"currency": "example",
"publishable_key": "example",
"require_verification": true,
"sms_enabled": true,
"vertical": "example",
"booking_policy": "example",
"contact_email": "example",
"contact_phone": "example",
"blurb": "example",
"terms_url": "example",
"website_url": "example",
"instagram_url": "example",
"maps_url": "example",
"confirmation_note": "example",
"social_title": "example",
"social_description": "example",
"allow_staff_choice": true,
"refund_policy": "example"
},
"services": [
{
"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"
}
],
"categories": [
{
"id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"name": "example",
"position": 1
}
],
"questions": [
{
"id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"label": "example",
"help_text": "example",
"type": "example",
"options": [
"example"
],
"required": true,
"applies_to": "example",
"service_ids": [
"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0"
],
"position": 1
}
]
}

There is no such resource in this workspace.

Media type application/json
object
error
required
object
type
required

A stable machine-readable code. Match on this.

string
message
required

A sentence for a person. Do not match on this.

string
param

The field that caused the refusal, if one field did.

string
dimension

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.

string
used

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.

integer format: int64
limit

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.

integer format: int64
Example generated
{
"error": {
"type": "example",
"message": "example",
"param": "example",
"dimension": "example",
"used": 1,
"limit": 1
}
}