Skip to content

Set up bookings

A bookable page needs where, what, who, the terms and somewhere to book. Every account starts with a location, an unpublished page and a default policy: add services and people, then publish.

  1. Wherea location (already there)
  2. WhatPOST /v1/services
  3. WhoPOST /v1/staff + hours
  4. TermsPOST /v1/booking_policy
  5. Publishbook.tuppence.ai/<address>

Switching? Fresha, Booksy, Square, Vagaro and Treatwell exports import as they are; other spreadsheets are matched column by column. Imports dry-run first and can be undone for 24 hours.

BookingsFree: no monthly, per-booking or new-client fees
PaymentsThe card rate on deposits, fees and payments on the day
Texts (UK business)6p a segment (160 characters, or 70 with an emoji or curly quote)
WhatsApp (UK business)3p a message
EmailFree

Each message’s cost is in the log; monthly totals are on Messages and your statement.

  1. Where. Location: display name; clients come to you, you go to them, or online; timezone; phone, address and opening hours.
  2. What. Services → New service: name, duration and price. Optional: description, buffers, processing time (the person is free meanwhile), options with their own time and price, class size, who the visit is for, online bookability, required resources (a room, a chair) and who performs it.
  3. Who. Staff → New staff member: bio and photo, bookable online (off hides them from the page; you can still book them), services (with their own time or price), and hours: a week or two-week rotation from a date, plus time off, breaks and extra hours.
  4. The terms. Booking policy: deposit, card on file, free-cancellation window, late and no-show fees. What a client reads previews the wording for a £45.00$45.00€45.00 service. Booking policies →
  5. Somewhere to book. Booking page: address (book.tuppence.ai/<address>), look, words, step order, questions, after-booking behaviour and SEO. Preview before going live; Publish puts it live.
  6. Share it. Share: your link, service and staff links, a QR code, the website widget, and places to post your link. Each link carries its channel, so every booking records where its client came from.

The dashboard uses the same calls. Create a service, a person with weekly hours and a deposit, then publish:

Terminal window
api() { # GET a path, or POST it with a body, using your key and a fresh Idempotency-Key
if [ $# -eq 1 ]; then
curl -sS "https://api.tuppence.ai$1" -H "Authorization: Bearer $TUPPENCE_SECRET_KEY"
else
curl -sS "https://api.tuppence.ai$1" -H "Authorization: Bearer $TUPPENCE_SECRET_KEY" \
-H "Idempotency-Key: $(uuidgen)" -H "Content-Type: application/json" -d "$2"
fi
}
# Where: every account has a location from the first look.
location=$(api /v1/locations | jq -r '.data[0].id')
# What, and who: Monday to Friday, nine till half past five.
api /v1/services '{"name": "Intro call", "duration_minutes": 30, "amount": 4500}' > /dev/null
staff=$(api /v1/staff "{\"name\": \"Bella\", \"locations\": [\"$location\"]}" | jq -r .id)
day='[["09:00", "17:30"]]'
api "/v1/staff/$staff/schedules" "{\"location\": \"$location\", \"effective_from\": \"$(date +%F)\",
\"pattern\": [{\"1\": $day, \"2\": $day, \"3\": $day, \"4\": $day, \"5\": $day}]}" > /dev/null
# The terms: a £10 deposit, refunded if they cancel in time.
api /v1/booking_policy '{"deposit": {"type": "fixed", "value": 1000, "refundable": true}}' > /dev/null
# Somewhere to book: a line about you, then live.
api /v1/booking_page '{"content": {"about": "Product strategy calls for early-stage startups."}}' > /dev/null
api /v1/booking_page/publish '{}' | jq -r '"\(.published) \(.url)"' # true https://book.tuppence.ai/test/…
Terminal window
api() { # GET a path, or POST it with a body, using your key and a fresh Idempotency-Key
if [ $# -eq 1 ]; then
curl -sS "https://api.tuppence.ai$1" -H "Authorization: Bearer $TUPPENCE_SECRET_KEY"
else
curl -sS "https://api.tuppence.ai$1" -H "Authorization: Bearer $TUPPENCE_SECRET_KEY" \
-H "Idempotency-Key: $(uuidgen)" -H "Content-Type: application/json" -d "$2"
fi
}
# Where: every account has a location from the first look.
location=$(api /v1/locations | jq -r '.data[0].id')
# What, and who: Monday to Friday, nine till half past five.
api /v1/services '{"name": "Intro call", "duration_minutes": 30, "amount": 4500}' > /dev/null
staff=$(api /v1/staff "{\"name\": \"Bella\", \"locations\": [\"$location\"]}" | jq -r .id)
day='[["09:00", "17:30"]]'
api "/v1/staff/$staff/schedules" "{\"location\": \"$location\", \"effective_from\": \"$(date +%F)\",
\"pattern\": [{\"1\": $day, \"2\": $day, \"3\": $day, \"4\": $day, \"5\": $day}]}" > /dev/null
# The terms: a $10 deposit, refunded if they cancel in time.
api /v1/booking_policy '{"deposit": {"type": "fixed", "value": 1000, "refundable": true}}' > /dev/null
# Somewhere to book: a line about you, then live.
api /v1/booking_page '{"content": {"about": "Product strategy calls for early-stage startups."}}' > /dev/null
api /v1/booking_page/publish '{}' | jq -r '"\(.published) \(.url)"' # true https://book.tuppence.ai/test/…
Terminal window
api() { # GET a path, or POST it with a body, using your key and a fresh Idempotency-Key
if [ $# -eq 1 ]; then
curl -sS "https://api.tuppence.ai$1" -H "Authorization: Bearer $TUPPENCE_SECRET_KEY"
else
curl -sS "https://api.tuppence.ai$1" -H "Authorization: Bearer $TUPPENCE_SECRET_KEY" \
-H "Idempotency-Key: $(uuidgen)" -H "Content-Type: application/json" -d "$2"
fi
}
# Where: every account has a location from the first look.
location=$(api /v1/locations | jq -r '.data[0].id')
# What, and who: Monday to Friday, nine till half past five.
api /v1/services '{"name": "Intro call", "duration_minutes": 30, "amount": 4500}' > /dev/null
staff=$(api /v1/staff "{\"name\": \"Bella\", \"locations\": [\"$location\"]}" | jq -r .id)
day='[["09:00", "17:30"]]'
api "/v1/staff/$staff/schedules" "{\"location\": \"$location\", \"effective_from\": \"$(date +%F)\",
\"pattern\": [{\"1\": $day, \"2\": $day, \"3\": $day, \"4\": $day, \"5\": $day}]}" > /dev/null
# The terms: a €10 deposit, refunded if they cancel in time.
api /v1/booking_policy '{"deposit": {"type": "fixed", "value": 1000, "refundable": true}}' > /dev/null
# Somewhere to book: a line about you, then live.
api /v1/booking_page '{"content": {"about": "Product strategy calls for early-stage startups."}}' > /dev/null
api /v1/booking_page/publish '{}' | jq -r '"\(.published) \(.url)"' # true https://book.tuppence.ai/test/…
CallTakes
POST /v1/servicesname, duration_minutes, amount (minor units); optionally variants, addons, resources, staff, buffers, max_group_size. Without staff, every active person performs it.
POST /v1/staffA person and the locations they work at.
POST /v1/staff/{id}/schedulesA weekly pattern (ISO weekdays, "1" is Monday), or two patterns for a rotation, from effective_from.
POST /v1/booking_policyAny of the policy’s fields; the rest carry over.
POST /v1/booking_page, …/publishPatches to slug (the address), theme, content, flow, seo; then publish.

In Bookings › Set up bookings › Where and when, Connect Google Business Profile and choose the place, or paste its Google Maps link (Share → copy). Address, phone and opening hours fill in for you to check before saving. If you tick the box, the listing’s photos become your page’s cover and gallery. Disconnect revokes access. The option only appears where it’s available.

API: GET /v1/booking_setup/google_business and …/locations, then POST …/listing and …/photos.

Home shows a checklist once the page exists (GET /v1/booking_setup/checklist). Three days after going live, the account owner gets one email naming the next item.

ItemDone when
Take real paymentsThe account is live
Your first bookingA real one (not example or imported)
Reminders onOn by default unless switched off in Messages
Invite your teamSomeone else joins
Connect a calendarGoogle, Outlook or iCloud is syncing
A second channelBookings from two places, e.g. your link and Instagram

No money moves. Your page is at book.tuppence.ai/test/<address>; book yourself with a test card. POST /v1/test_helpers/bookings/seed_week fills a week with example bookings from your services, staff and hours. Reseeding the same week adds nothing.

Docs assistant

Open as a page
Loading the assistant…