Skip to main content

Overview

An API key lets a system you control talk to Bella on your business’s behalf. The things people build most often are:
  • A booking form on your own website - read your services, check availability, then create the client and the appointment.
  • A sync into another system - pull your clients and appointment history into a CRM, a data warehouse or a backup.
Appointments created through the API appear in your scheduler like any other, your clients get the same confirmation messages, and the Booking source report attributes them to Integration so you can tell them apart. To keep another system up to date, read your clients and appointments through the API on a schedule. You create, edit and revoke keys yourself in Settings → Integrations. Nobody at Bella needs to be involved. API access is part of the Professional plan (see Plans compared). On Solo and Starter you can’t create a key, and a request made with an existing key returns 403.
A key belongs to one location. If you run more than one location, switch to that location before creating its key. A key can never be moved to a different location.

Quickstart

Four calls take a visitor from “what do you offer?” to a booked appointment.
You supply the price and duration, and Bella records what you send. They are not re-read from your catalogue at booking time.Always take price and durationInMinutes from the catalogue response in step 1 rather than hard-coding them, or a price change in Bella won’t reach your website. See Pricing your booking correctly.

Authentication

Send the key in the x-api-key header on every request. You never need to say which location - the key already knows.
Keys are stored hashed, so nobody - including us - can read one back after it’s created. If you lose it, revoke it and create another.

Managing keys

1

Open Settings → Integrations

You’ll need permission to manage settings. You can only grant a key permissions you hold yourself. A key with Read appointments sees every appointment, so granting it also needs permission to view all team members’ appointments.
2

Name it after what will use it

“Website booking”, “CRM sync”, “Ops bot” - so the Last used column tells you something useful later.
3

Choose what it can do

Tick only what that integration actually needs. You can change this later without reissuing the key.
4

Copy the key

It’s shown once. Store it as an environment variable on your server. If you lose it, revoke it and create another.
From the ⋯ menu next to any key:
  • Edit - rename it or change its permissions. The key itself never changes, so whoever is using it doesn’t have to do anything.
  • Revoke - stop it working, keep the row so you can still see when it was last used. This cannot be undone.
  • Delete - remove it from the list entirely. If the key was still active this also stops it working.
Edits, revocations and deletions all take effect within a minute rather than instantly - keys are cached briefly to keep requests fast.

Permissions

Everything else returns 403. A key cannot reach sales, reports, payments, team management, settings, or the API keys themselves - no key can ever create another key. There’s no call for sending a text or email either: clients get only your usual automated messages, such as the confirmation for a new appointment.
Give each integration its own key with only the permissions it needs. A website booking form needs the four in the first block; a read-only CRM sync needs only the two view permissions.

API reference

Base URL: https://api.bellabooking.com Requests and responses are JSON. All ids are strings. Dates are YYYY-MM-DD; times of day are HH:MM:SS.

List the catalogue

Returns your categories, each containing its services and bundles, with prices, durations, variants, pricing tiers and add-on groups.
This returns your full catalogue, including services you’ve switched off for online booking. Filter on disabledForOnlineBooking before showing anything to a visitor, or your website will offer services you’ve deliberately taken offline.Check requiresMembership too if you use members-only services - the API will book them for a non-member. The same applies to prerequisiteServiceIds / prerequisiteRequirement / prerequisiteMatchMode - the API does not enforce prerequisite gates.

Check availability

Pass variantId where the service uses variants, and addonDurationInMinutes (the extra minutes of the add-ons the client chose) where it has add-ons, so the slots you get back match the real length of the appointment.
Availability reflects rosters, existing appointments and blocked time. It applies your minimum-notice period as your booking page does, but not your gap-reduction settings - see Booking rules.

Create or match a client

If the email or phone already belongs to one of your active clients, the request is refused with 400. A key that can also Read client records gets that client named in detail (“Jane Citizen already has this phone number.”) and their id and name in existingClient; any other key gets “A client with this phone number already exists.” Look a returning client up first with GET /api/Clients/search?filter= and their phone or email, and create one only when nothing comes back. A new client with exactly the same name as an existing one is refused too, unless you send "forceCreateDespiteDuplicateName": true (two people can share a name). notes (a private note only your team sees) and tags (client tags, e.g. ["Booked by phone"]) are optional.

Create an appointment

The appointment is Confirmed straight away, unless it owes a deposit or your client confirmation window applies: then it stays Booked until the client pays or confirms. For deposits, a booking made with a key counts as one the client made themselves (see Deposit applies to).

Pricing your booking correctly

Bella records the price and durationInMinutes you send. It does not re-read them from your catalogue. That means:
  • Always read them from GET /api/servicecategories at booking time. Hard-coded prices go stale the moment you change a price in Bella.
  • Where a service uses variants, take the price and duration from the chosen variant, not the base service.
  • Where a service uses pricing tiers, take them from the tier matching the assigned team member.
  • Add-ons: keep their price out of price, because Bella adds each add-on’s catalogue price to the line itself. Put their minutes in: durationInMinutes is the line’s full length, add-ons included, and is recorded as sent.
  • The one exception is a bundle with a set total (Set total price, % discount or Free): Bella replaces the price on each of its lines with that line’s share of the total, whatever you send.
Getting this wrong doesn’t fail - it books at the price you sent, and that’s what the client is charged at checkout.

Booking rules

Bookings made with an API key are recorded with the same checks your front desk gets, not the stricter ones your public booking page gets. Bella will accept a booking that:
  • double-books a team member
  • is in the past, or inside your minimum-notice period
  • is with a team member who isn’t qualified for that service
  • is a members-only service for someone without a membership
  • has unmet prerequisite services (a treatment that online booking would lock until a consult is booked or completed)
  • would have needed your approval if it came through your own booking page
Check availability first and only offer slots that came back from it. That is what keeps a website booking honest.
Services that need a room or piece of equipment take a resourceId on the line. Your own booking page picks a free resource automatically; the API doesn’t, so a line without one is refused with a message naming the service that needs one. Check availability for that resource first.

Reschedule an appointment

Every service line moves together, keeping the gaps between them and each line’s team member. The client gets your usual reschedule message a minute or two after the move. A reschedule doesn’t check availability: it moves the appointment even when the team member is busy, isn’t rostered or the time is outside your opening hours. Check first with GET /api/Appointments/availability and rescheduleAppointmentId, and move only to a time that came back. A time in the past, or a cancelled or completed appointment, is refused with 400. To change the team member, services or prices as well, use Edit an appointment.

Edit an appointment

The same edit your team makes in the dashboard: change the team member, the services, the prices, the date and time, or the note. Read the appointment with GET /api/Appointments/{id}, change what you need, and send the whole appointment back. What you send replaces what’s there. Each line takes the fields the read returns for it: serviceId, teamMemberId, startTime, durationInMinutes, price, variantId, bundleId, resourceId, addons and discount. Change only what you need. A line’s discount left out is removed, and a line whose service needs a room or piece of equipment is refused without its resourceId. A line’s add-ons, guests and group are kept when left out, and so are the appointment’s products, custom items and tags.
When the date or time changes, the client gets your usual reschedule message, unless you send silentNotification.
  • Check availability first. Like a front-desk edit, it accepts a team member who is already booked. A time outside a team member’s working hours is refused only when Enforce working hours is on in Settings → Scheduling.
  • Read just before you write. There’s no conflict check: if your team changes the appointment between your read and your edit, your edit replaces their change.
  • Prices are recorded as sent, the same as when booking.
  • A cancelled or checked-out appointment can’t be edited (400).

Cancel an appointment

Always send a JSON body, even if it’s just {}.
refundAmount is null when the appointment held no paid deposit, and 0 when it held one and nothing was sent back (the policy kept it, or it was paid in person and you hand it back yourself). Each cancel adds one to the client’s cancellation count, or to their no-show count with reasonId 6. Packages, memberships, gift-card balances, loyalty points and promo codes the appointment used are restored automatically.
Cancelling through the API never charges a client’s card on file. A deposit paid online by card is refunded automatically, less what your late cancellation or no-show fee takes on a late cancellation (all of it when your deposit rule keeps the whole deposit). To charge the rest of a fee to a card on file, cancel from the dashboard, or use Charge fee on the cancelled appointment.

Check a client in

Neither takes a body. Both return where the appointment now sits:
checkInState is NotArrived, Waiting or InProgress. Times are UTC. Check-in is separate from the appointment’s status. A checked-in appointment is still Booked or Confirmed; only checkout completes it. So these two calls cannot confirm, complete or cancel anything, and an appointment nobody checked in still checks out normally - “not arrived” is not a no-show. You can call start without calling checkin first, for a front desk that only marks the service starting. Bella backfills the arrival to the same instant, so the wait time reads zero. Both calls are safe to repeat: a second one changes nothing. Checking in notifies the assigned team member in the dashboard, the same as a front-desk check-in. The client is never messaged - they are standing in front of you.
Check-in clears if the appointment later moves to a different day. A same-day time change keeps it. Both calls return 400 on a cancelled or completed appointment. Undoing a check-in is dashboard-only for now.
These count against the write limit, which is sized for a booking form at 10 a minute. A front desk marking a morning’s arrivals is burstier than that, so if you’re building a kiosk or check-in screen, ask us to raise it before you go live rather than spacing the calls out.

Read clients

search accepts filter (name, email or phone), limit, skip and a range of filters including createdAfter, createdBefore, lastAppointmentAfter and tags.

Read appointments

search requires startDate and endDate, and accepts teamMemberIds, serviceIds, statusIds (1 Booked, 2 Confirmed, 3 Completed, 4 Cancelled), clientFilter (a client’s name, email or phone, in any format, or an appointment tag), limit (up to 200), skip, orderBy and orderByDirection. Times come back in your business’s local time. The search lines carry no variantId; GET /api/Appointments/{id} has it.
Read endpoints return the full internal record - including private notes, client timeline notes and their attachments, card-on-file details and payment links.Never pass these responses straight through to a browser. Read them on your server, keep only the fields you need, and treat anything you store as you would the records in your dashboard.
There’s no incremental cursor yet. A sync re-reads the date or page range it asks for. Deleted records leave no tombstone, so a full reconciliation is more reliable than a running total.

Errors

Errors are returned as JSON with an HTTP status and a detail explaining what went wrong.

Rate limits

Limits are applied per key, per minute. Exceeding a limit returns 429 with a Retry-After header. Wait that many seconds and retry - don’t retry immediately in a loop.
The write limit is sized for a real booking form rather than a bulk import - so if you’re migrating data or running a busier site, ask us to raise it rather than working around it. These limits protect your business’s own performance and may change; they aren’t a service guarantee.

Keeping your key safe

Never put an API key in code a visitor’s browser can read. Anyone who can see it can act as your business. Keep it on your own server and call Bella from there.
  • Store it as an environment variable or in a secrets manager, never in your source code.
  • Give each integration its own key, so you can revoke one without breaking the others.
  • Revoke a key the moment it’s no longer needed, or the moment you suspect it’s been exposed.
  • Narrow a key’s permissions when an integration stops needing something - editing is safer than leaving a key more capable than it has to be.
  • Your key can read and change real client data. Treat it like the password to your dashboard.

Finding this API

Agents and crawlers discover the website-booking API from the Bella marketing site - not from an OpenAPI file on this docs host: This page is the human reference for the thirteen routes a key can call. Tell us what you’re building - it genuinely shapes what we build next.