Besmi·Developers

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

  1. 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.
  2. ii.
    Make a request. Pass the key as a Bearer token. Every endpoint is scoped to your business. You never specify businessId.
  3. 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.

Header
Authorization: Bearer bsk_live_…
Key format
bsk_live_ prefix · 24 random bytes (url-safe base64) · ~40 characters total
Scopes
read for GET endpoints · write for POST / PATCH / DELETE
Storage
Besmi stores only a SHA-256 hash + a 16-character prefix for lookup. Plaintext surfaces exactly once on creation. If you lose a key, generate a new one.
Revocation
Soft-revoke from Settings → Dev. Requests with a revoked key return 401 on the next call.
Treat keys as production credentials. Each key inherits your business's full read & write scope. Don't embed in client-side JavaScript or commit to git. Use environment variables and rotate on team changes.

Endpoints

Base URL: https://besmi.com

GET/api/v1/business

Read 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 */ }
  }
}
GET/api/v1/services

List 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":          []
    }
  ]
}
GET/api/v1/availability

Get 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

date
string
YYYY-MM-DD in the business's timezone
durationMinutes
number
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" }
  ]
}
GET/api/v1/appointments

List appointments

Lists appointments for the authenticated business, optionally filtered by date range and status. Cursored pagination via from / nextCursor.

Query parameters

from
string
ISO 8601, inclusive lower bound on startAt
to
string
ISO 8601, exclusive upper bound on startAt
status
string
Comma-separated subset of pending,confirmed,cancelled,noshow
limit
number
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_…"
POST/api/v1/appointments

Create 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" }
  }'
GET/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_…"
PATCH/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" }'
GET/api/v1/customers

List customers

Returns customer records, optionally filtered by a name / email / phone substring.

Query parameters

q
string
Case-insensitive substring filter
limit
number
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.

Endpoint

https://besmi.com/api/mcp

Auth

OAuth 2.1 with PKCE. No API key. The owner approves the connection once.

Tools

32 tools across schedule, clients, appointments, availability, stats, reviews, discounts, page design, and audiences and campaigns

Scopes

read, book, design, manage

Owners add the connector from Settings, then Connect. If a new tool or scope ships after you connect, reconnect once to pick it up.

Errors

Standard HTTP status codes. The response body is always JSON with an error field on failures.

400

Bad Request: malformed body, invalid date, missing required field

401

Unauthorized: missing, invalid, or revoked key

403

Forbidden: key lacks the required scope

404

Not Found: resource doesn't exist or belongs to another business

500

Internal: 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.