Besmi API · v1
Build on Besmi.
A small, clean API for building custom booking experiences on top of your Besmi business: a marketing site, an internal dashboard, a partner integration, anything. Same auth model, same data, just yours to compose.
Quick start
- i.Generate an API key. Sign in to Besmi, open Settings → Dev, click
New key. Copy the key the moment it appears. Besmi only stores a hash, so it can't be shown again. - ii.Make a request. Pass the key as a Bearer token. Every endpoint is scoped to your business. You never specify
businessId. - iii.Build whatever you want. Custom booking page, mobile app, agency dashboard, scheduled sync: all the same calls.
Your first request
curl https://besmi.com/api/v1/business \
-H "Authorization: Bearer bsk_live_your_key_here"Authentication
Every /api/v1/* endpoint accepts either an API key (recommended for server-to-server) or a Firebase ID token (used by the Besmi first-party UI). Both pass through the same auth pipeline. The businessId is derived from the token, never supplied as a parameter.
Authorization: Bearer bsk_live_…bsk_live_ prefix · 24 random bytes (url-safe base64) · ~40 characters totalread for GET endpoints · write for POST / PATCH401 on the next call.Endpoints
Base URL: https://besmi.com
/api/v1/businessRead business profile
Returns name, slug, contact, hours, timezone, theme, landing-page modules, and notification preferences. Stripe / Twilio / partner identifiers are scrubbed.
curl https://besmi.com/api/v1/business \
-H "Authorization: Bearer bsk_live_…"Response · 200
{
"business": {
"id": "biz_xxx",
"name": "Your Esthi Bestie",
"slug": "mlc",
"timezone": "America/Los_Angeles",
"contact": { "email": "...", "phone": "..." },
"schedule": { /* working hours */ },
"theme": { /* colors + fonts */ },
"landingPage": { /* modules */ }
}
}/api/v1/servicesList services & categories
Returns all services and their categories, in display order. Use this to populate a custom service picker.
curl https://besmi.com/api/v1/services \
-H "Authorization: Bearer bsk_live_…"Response · 200
{
"categories": [
{ "id": "cat_xxx", "name": "Lashes", "order": 0, "color": "#C026D3", "services": [] }
],
"services": [
{
"id": "svc_xxx",
"categoryId": "cat_xxx",
"name": "Classic Full Set",
"price": 18000,
"durationMinutes": 120,
"bufferMinutes": 15,
"bookableOnline": true,
"addons": []
}
]
}/api/v1/availabilityGet available slots
Returns bookable time slots for a given date and service duration. Accounts for working hours, blocked windows, buffers, and existing appointments.
Query parameters
datestring | YYYY-MM-DD in the business's timezone |
durationMinutesnumber | Service duration. Default 60. Range 0–480. |
curl "https://besmi.com/api/v1/availability?date=2026-05-15&durationMinutes=120" \
-H "Authorization: Bearer bsk_live_…"Response · 200
{
"slots": [
{ "start": "2026-05-15T17:00:00.000Z", "end": "2026-05-15T19:00:00.000Z" },
{ "start": "2026-05-15T19:30:00.000Z", "end": "2026-05-15T21:30:00.000Z" }
]
}/api/v1/appointmentsList appointments
Lists appointments for the authenticated business, optionally filtered by date range and status. Cursored pagination via from / nextCursor.
Query parameters
fromstring | ISO 8601, inclusive lower bound on startAt |
tostring | ISO 8601, exclusive upper bound on startAt |
statusstring | Comma-separated subset of pending,confirmed,cancelled,noshow |
limitnumber | Default 50, max 200 |
curl "https://besmi.com/api/v1/appointments?from=2026-05-01&to=2026-06-01&status=confirmed,pending" \
-H "Authorization: Bearer bsk_live_…"/api/v1/appointmentsCreate an appointment
Books a new appointment on behalf of the authenticated business. Requires the write scope. Payment isn't handled here. Use Besmi's built-in payment flow or your own Stripe Connect integration.
Request body
{
"serviceId": "svc_xxx",
"startAt": "2026-05-15T17:00:00.000Z",
"endAt": "2026-05-15T19:00:00.000Z",
"client": {
"firstName": "Jordan",
"lastName": "Lee",
"email": "jordan@example.com",
"phone": "+15555550100"
},
"addonIds": ["addon_xxx"],
"status": "confirmed",
"note": "Allergic to acrylic"
}curl -X POST https://besmi.com/api/v1/appointments \
-H "Authorization: Bearer bsk_live_…" \
-H "Content-Type: application/json" \
-d '{
"serviceId": "svc_xxx",
"startAt": "2026-05-15T17:00:00.000Z",
"endAt": "2026-05-15T19:00:00.000Z",
"client": { "firstName": "Jordan", "email": "jordan@example.com", "phone": "+15555550100" }
}'/api/v1/appointments/{id}Read one appointment
Fetches a single appointment by id.
curl https://besmi.com/api/v1/appointments/apt_xxx \
-H "Authorization: Bearer bsk_live_…"/api/v1/appointments/{id}Update an appointment
Patch status, time, addons, owner note, or client contact. Payment fields are intentionally NOT patchable. Use the dedicated Stripe surfaces so Stripe stays the source of truth.
Request body (any subset)
{
"status": "cancelled",
"startAt": "2026-05-16T17:00:00.000Z",
"endAt": "2026-05-16T19:00:00.000Z",
"addonIds": ["addon_xxx"],
"note": "Client called to reschedule",
"client": { "phone": "+15555550101" }
}curl -X PATCH https://besmi.com/api/v1/appointments/apt_xxx \
-H "Authorization: Bearer bsk_live_…" \
-H "Content-Type: application/json" \
-d '{ "status": "cancelled" }'/api/v1/customersList customers
Returns customer records, optionally filtered by a name / email / phone substring.
Query parameters
qstring | Case-insensitive substring filter |
limitnumber | Default 100, max 500 |
curl "https://besmi.com/api/v1/customers?q=jordan&limit=20" \
-H "Authorization: Bearer bsk_live_…"MCP connector
Besmi ships an MCP connector. MCP (Model Context Protocol) is the open standard AI assistants use to call external tools, so an assistant such as Claude or ChatGPT can work directly against a Besmi account: read the schedule, book, reschedule and cancel appointments, look up clients, pull stats, manage discounts, and edit the public page.
This is separate from the REST API above. The REST API is for code you write; the MCP connector is for an AI assistant acting on the owner's behalf. It does not use API keys. Connection is authorized by the business owner through OAuth 2.1, and can be revoked at any time from Settings → Connect.
Endpointhttps://besmi.com/api/mcp
AuthOAuth 2.1 with PKCE. No API key. The owner approves the connection once.
Tools54 tools: schedule, hours and locations, availability, bookings (options, add-ons, stylists, standing appointments), clients, sales and payouts (read only), the receptionist inbox, waitlist, marketing, and an AI page designer (drafts, renders, design review, Looks)
ProtocolStreamable HTTP, protocol 2025-11-25 (and older); MCP Apps page-preview view at ui://besmi/page-preview
Scopesread (look things up), book (schedule, inbox, waitlist), design (the page, as drafts), manage (client records, discounts, marketing). The owner sees them on the consent screen.
Discovery401 responses carry WWW-Authenticate pointing at /.well-known/oauth-protected-resource (RFC 9728), which names the authorization server at /.well-known/oauth-authorization-server (RFC 8414).
ClientsDynamic client registration (RFC 7591) at /api/oauth/register. Public clients only: authorization code + PKCE S256, refresh tokens, revocation at /api/oauth/revoke.
PlansConnecting needs a Pro or Icon plan. A few tools also need a feature from a higher plan; tools/list marks those, and calling one returns an upgrade note.
Any MCP client that supports remote servers with OAuth can connect, not only Claude and ChatGPT. Point it at the endpoint and it discovers the rest. Tools are annotated honestly (readOnlyHint, destructiveHint, idempotentHint), failures come back with isError, and results include structuredContent. Design tools also return a PNG of the page so the model can see its work.
Tools (54)
Studio
get_business_overviewStudio overviewreadlist_servicesService menureadlist_teamTeamreadget_hoursHours and locationsreadSchedule and availability
get_scheduleAppointments by datereadget_upcomingNext appointmentsreadget_pending_requestsRequests waiting for approvalreadcheck_availabilityOpen times on a dayreadfind_next_availabilityNext openingsreadblock_timeBlock personal timebook · writesset_day_offDays offbook · writesset_special_hoursSpecial hours for a datebook · writesBookings
create_appointmentBook an appointmentbook · writesconfirm_appointmentApprove a requestbook · writesreschedule_appointmentMove an appointmentbook · writescancel_appointmentCancel or declinebook · writesmark_no_showMark a no-showbook · writesClients
find_clientFind a clientreadlist_clientsRank clientsreadget_client_historyClient profile and historyreadupdate_clientUpdate a clientmanage · writesget_birthdaysBirthdaysreadget_reviewsReviewsreadrequest_card_on_fileAsk a client to save a cardmanage · writesMoney (read only)
get_salesSales and takingsreadget_payoutsBalance and payoutsreadInbox and waitlist
get_needs_youConversations that need the ownerreadget_conversationRead a text conversationreadreply_to_clientReply to a client by textbook · writesmark_handledClear a "Needs you" flagbook · writesget_waitlistWaitlistreadoffer_openings_to_waitlistOffer openings to the waitlistbook · writesremove_from_waitlistRemove from the waitlistbook · writesMarketing
list_discountsDiscount codesreadcreate_discountCreate a discount codemanage · writesset_discount_activeTurn a code on or offmanage · writespreview_audienceCount an audiencereadlist_audiencesSaved audiencesreadcreate_audienceSave an audiencemanage · writeslist_automationsMarketing automationsreadcreate_automationCreate a campaign (switched off)manage · writesset_automation_enabledPause a campaignmanage · writesdraft_broadcastDraft a one-off blastreadPage designer
get_design_guideDesign guidereadget_page_designPage designreadrender_pageSee the pagereadreview_page_designDesign reviewreadget_page_sectionOne page section in fullreadupdate_page_designChange the page's lookdesign · writesedit_page_sectionsEdit page sectionsdesign · writesapply_lookApply a Lookdesign · writespublish_page_draftPublish the draftdesign · writesdiscard_page_draftDiscard the draftdesign · writesrevert_page_designUndo the last published changedesign · writesOwners add the connector from Settings, then Connect. New tools under the four existing scopes reach existing connections automatically; only a brand-new scope needs a reconnect. The connector never charges or moves money, and never sends marketing on its own.
Errors
Standard HTTP status codes. The response body is always JSON with an error field on failures.
400Bad Request: malformed body, invalid date, missing required field
401Unauthorized: missing, invalid, or revoked key
403Forbidden: key lacks the required scope
404Not Found: resource doesn't exist or belongs to another business
500Internal: something went wrong on our side. Safe to retry.
WebhooksComing soon
Subscribe to appointment.created, appointment.updated, and customer.created events. HMAC-SHA256 signed (Stripe-style). Email developers@besmi.com if you need this on a timeline.
Help
Question, bug report, or integration request? Email developers@besmi.com. Common questions live in the FAQ; this page is the source of truth for endpoint shapes.