Bjuti API Documentation
Welcome to the official Bjuti Developer Portal. This documentation covers the REST API and Model Context Protocol (MCP) daemon interfaces. Software developers and autonomous AI agents can search salons and beauty professionals, query pricelists and real-time appointment availability, initiate temporary reservations (15-min On Hold), and confirm bookings via email verification codes.
https://api.bjuti.ee. The main consumer portal is accessible at bjuti.ee. Machine-readable specification is available at /v1/openapi.json.
AI Agent Booking Workflow Order & Parameter Chaining
To finalize an appointment booking reliably, autonomous AI agents and integrations MUST invoke endpoints in the following strictly chained sequence (Steps 1 to 7). Each subsequent step's input parameters are directly sourced from preceding API responses:
7-Step Booking Lifecycle:
- Step 1: Authenticate Agent (
POST /v1/agent/auth/tokenor MCPbjuti_agent_auth)
Input:client_id,client_secret
➔ Sourced Output:access_token(Bearer token valid for strictly 15 minutes / 900 seconds) ➔ Pass in all subsequent requests:Authorization: Bearer <access_token>. - Step 2 (Optional): Discover Service Categories (
GET /v1/agent/booking/service-groupsor MCPbjuti_get_service_categories)
➔ Sourced Output:category_id,name(Hair, Nails, Brows/Lashes, Skin, Massage, etc.). - Step 3: Search Salons & Specialists (
GET /v1/agent/booking/nearby-salonsor/search-salonsor MCPbjuti_find_salons)
Input: GPS coordinates (lat,lng,radius_km) OR text query (q,salon_name,specialist_name)
➔ Sourced Outputs:salons[].location_id➔ Mandatory input for Steps 4, 5, and 6!salons[].professionals[].professional_id➔ Mandatory input for Steps 5 and 6!
- Step 4: Fetch Salon Pricelist & Services (
GET /v1/agent/booking/pricelistor MCPbjuti_get_salon_pricelist)
Input:location_id(Sourced from Step 3:salons[].location_id)
➔ Sourced Outputs:pricelist[].service_id➔ Mandatory input (array or comma-separated) for Steps 5 and 6!pricelist[].specialists[].professional_id➔ Specialist confirmation.
- Step 5: Query Open Availability Slots (4-Day Window) (
GET /v1/agent/booking/availability-slotsor MCPbjuti_get_available_slots)
Inputs:location_id➔ Sourced from Step 3professional_id➔ Sourced from Step 3 or 4service_ids➔ Sourced from Step 4 (comma-separated UUIDs)date➔ Desired starting date inYYYY-MM-DD
slots[date][]array, select client's chosenstart_time(e.g."14:30") ➔ Pass to Step 6! (If booked, checkfirst_available_dateandwaitlist_available). - Step 6: Temporary Hold (15-Minute Reservation) (
POST /v1/agent/booking/holdor MCPbjuti_hold_booking)
Inputs:location_id(Sourced from Step 3)professional_id(Sourced from Step 3 or 4)service_ids(Sourced from Step 4)date(Sourced from Step 5)start_time(Sourced from Step 5:slots[date][])- Client details:
contact_firstname,contact_lastname,contact_phone,contact_email,message_text
booking_id(UUID) ➔ Pass to Step 7! Client receives a 6-digit confirmation code via email. - Step 7: Confirm Booking with Email Code (
POST /v1/agent/booking/confirmor MCPbjuti_confirm_booking)
Inputs:booking_id➔ Sourced from Step 6:booking_idverification_code➔ 6-digit code provided by client from email
status: "confirmed") and permanently written to salon calendar!
- Early Hold Release:
POST /v1/agent/booking/release-holdrequiresbooking_id(from Step 6) if the client cancels before code entry. - Join Waitlist:
POST /v1/agent/booking/waitlistif Step 5 has no open slots andwaitlist_available: true. - Active Appointments Check:
GET /v1/agent/booking/my-activechecks client's existing bookings before Step 6 (to prevent 1-booking-per-category conflicts).
Authentication and Token Lifetimes (15-Minute Rule)
All authenticated API endpoints require a Bearer token in the HTTP Authorization header:
Authorization: Bearer <access_token>
access_token tokens are valid for exactly 15 minutes (900 seconds). AI agents or clients must persist the issued refresh_token and request a new access token via /v1/agent/auth/refresh prior to expiration. Authentication endpoints are rate-limited to 10 requests per minute.
Booking & Hold Business Rules
- Pricelist-based selection: When booking, the agent must submit service IDs (
service_ids) derived directly from the salon pricelist (/pricelist). - 15-Minute On Hold reservation: Initiating a booking (
/hold) locks the selected slot with statusOn Hold. The slot is blocked for other clients and agents for 15 minutes. - Email verification code: Creating a hold triggers a 6-digit confirmation code dispatched to the client's email address. To finalize the booking, submit the code via
/confirm(up to 5 attempts before the reservation is cancelled). - 1 active booking per category per client: An AI agent cannot place more than one active booking in the same service category (e.g. Hair) for the same client. If the client already holds a confirmed or held appointment, the system returns error code
ACTIVE_BOOKING_EXISTS.
1. Obtain Access Token
Authenticates an AI agent or integration client using credentials and returns a 15-minute Bearer access token along with a refresh token.
Parameters (JSON body)
| Field | Type | Description |
|---|---|---|
client_id required | string | Public agent Client ID (e.g. ag_live_9b4c81...) |
client_secret required | string | Secret key for the agent |
curl -X POST https://api.bjuti.ee/v1/agent/auth/token \
-H "Content-Type: application/json" \
-d '{
"client_id": "ag_live_9b4c81a2f0e84",
"client_secret": "sec_f20a91e847c1..."
}'
{
"status": "success",
"data": {
"access_token": "agt_4f89b1c20e4a779d...",
"token_type": "Bearer",
"expires_in": 900,
"expires_at": "2026-11-08T21:15:00+02:00",
"refresh_token": "refr_d8a1c902b4e7..."
}
}
{
"status": "error",
"code": "INVALID_CREDENTIALS",
"message": "Invalid client_id or client_secret"
}
2. Refresh Access Token
Exchanges a valid refresh token for a fresh 15-minute access token. The old refresh token is invalidated immediately (refresh token rotation).
Parameters (JSON body)
| Field | Type | Description |
|---|---|---|
refresh_token required | string | Refresh token received from a prior token request |
curl -X POST https://api.bjuti.ee/v1/agent/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "refr_d8a1c902b4e7..."
}'
{
"status": "success",
"data": {
"access_token": "agt_99c301fa882b...",
"token_type": "Bearer",
"expires_in": 900,
"expires_at": "2026-11-08T21:30:00+02:00",
"refresh_token": "refr_66ea01449bc1..."
}
}
3. Verify Agent Profile
Returns the identity, permissions, and active token expiration timestamp for the authenticated agent.
Parameters
No query parameters required. Header Authorization: Bearer <token> is required.
curl -X GET https://api.bjuti.ee/v1/agent/auth/me \
-H "Authorization: Bearer agt_4f89b1c20e4a779d..."
{
"status": "success",
"data": {
"agent_id": "9a148c3b-5521-4d30-bfae-1280ea9010ab",
"name": "Concierge Booking Bot",
"email": "bot@example.com",
"token_expires_at": "2026-11-08T21:15:00+02:00",
"seconds_remaining": 842
}
}
4. Service Categories
Returns the main categories of beauty treatments (e.g. Hair, Nails, Brows & Lashes, Massage, Facial).
Query Parameters
| Parameter | Type | Description |
|---|---|---|
country optional | string | Country code (defaults to EE) |
curl -X GET "https://api.bjuti.ee/v1/agent/booking/service-groups?country=EE" \
-H "Authorization: Bearer <access_token>"
{
"status": "success",
"data": [
{ "id": "hair", "code": "hair", "name": "Hairdressing", "icon": "scissors" },
{ "id": "nails", "code": "nails", "name": "Nail Services", "icon": "hand-sparkles" },
{ "id": "face", "code": "face", "name": "Facial Care", "icon": "spa" },
{ "id": "brows", "code": "brows", "name": "Brows & Lashes", "icon": "eye" }
]
}
5. Search Nearby Salons (GPS)
Finds active salon locations based on client geographic coordinates (latitude and longitude) and a search radius using the Haversine formula.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
lat required | float | Client latitude (e.g. 59.43696) |
lng required | float | Client longitude (e.g. 24.75353) |
radius_km optional | float | Search radius in km (defaults to 25) |
category optional | string | Service category code filter |
curl -X GET "https://api.bjuti.ee/v1/agent/booking/nearby-salons?lat=59.4369&lng=24.7535&radius_km=10" \
-H "Authorization: Bearer <access_token>"
{
"status": "success",
"data": [
{
"location_id": "96fb29cf-a031-4ce8-b541-ef12998a1234",
"company_name": "Studio Elegance OÜ",
"location_name": "Studio Elegance Downtown",
"address": "Rotermanni 8, Tallinn",
"distance_km": 0.42,
"rating": 4.9,
"coordinates": { "lat": 59.4385, "lng": 24.7561 }
}
]
}
6. Search Salons by Name or Specialist
Searches by salon name, professional first/last name, phone number, or email address.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
query required | string | Search term (min 2 characters, e.g. "Kadri Tamm", "55123456", "Elegance") |
city optional | string | Filter by city (e.g. "Tartu", "Tallinn") |
curl -X GET "https://api.bjuti.ee/v1/agent/booking/search-salons?query=Kadri" \
-H "Authorization: Bearer <access_token>"
{
"status": "success",
"data": [
{
"location_id": "96fb29cf-a031-4ce8-b541-ef12998a1234",
"location_name": "Studio Elegance Downtown",
"address": "Rotermanni 8, Tallinn",
"matching_professionals": [
{
"professional_id": "8a1e47b2-3c10-482a-99cd-482b991a0021",
"name": "Kadri Kallas",
"title": "Senior Stylist",
"avatar_url": "https://ik.imagekit.io/bjuti/Professionals/kadri.webp"
}
]
}
]
}
7. Salon Pricelist & Service Add-ons
Returns base treatments available at the given location, prices (VAT incl.), duration in minutes, and available add-ons (addons) associated with each service. Agents can submit both base and add-on service IDs in a single booking request.
Query Parameters
| Parameter | Type | Source & Description |
|---|---|---|
location_id required | uuid | Sourced from Step 3 /nearby-salons or /search-salons response field salons[].location_id. |
professional_id optional | uuid | Sourced from Step 3 salons[].professionals[].professional_id to filter treatments by master. |
curl -X GET "https://api.bjuti.ee/v1/agent/booking/pricelist?location_id=96fb29cf-a031-4ce8-b541-ef12998a1234" \
-H "Authorization: Bearer <access_token>"
{
"status": "success",
"data": {
"location_id": "96fb29cf-a031-4ce8-b541-ef12998a1234",
"salon_name": "Studio Elegance Downtown",
"services": [
{
"service_id": "c14d9b2e-7412-4aa3-8fa9-994b2a8901aa",
"category": "hair",
"name": "Women's Haircut & Blow-dry",
"description": "Includes washing, scalp massage, haircut, and styling.",
"duration_minutes": 60,
"price": 45.00,
"addons": [
{
"service_id": "8b14da21-998b-4b11-9a40-ef81203491ba",
"category": "hair",
"name": "Intensive Moisture Hair Mask",
"description": "Deep restructuring treatment powered by K18 or Olaplex.",
"duration_minutes": 20,
"price": 15.00
},
{
"service_id": "fe1023ba-1200-4781-a891-cb9041289190",
"category": "hair",
"name": "Relaxing Scalp Massage with Essential Oils",
"duration_minutes": 15,
"price": 10.00
}
]
}
]
}
}
8. Availability Slots (4-Day Window & First Available Date)
Calculates open booking slots across the professional's working schedule for the total duration of all selected services and add-ons:
- 4-Day Window: Returns open slots from the requested date up to 3 days ahead (
datetodate + 3 days). - First Available Date: If no slots are found within the 4-day window, the system automatically locates the earliest upcoming slot (up to 45 days ahead) in
first_available. - Waiting List Readiness:
waitlist_available: trueindicates that if none of the slots suit the client, the client can be placed on the waitlist (/waitlist).
Query Parameters
| Parameter | Type | Source & Description |
|---|---|---|
location_id required | uuid | Sourced from Step 3 Salon location UUID (salons[].location_id). |
professional_id required | uuid | Sourced from Step 3 or 4 Professional UUID (salons[].professionals[].professional_id or pricelist[].specialists[].professional_id). |
service_ids required | string | Sourced from Step 4 Comma-separated service and addon UUIDs (pricelist[].service_id). |
date required | string | Starting date in format YYYY-MM-DD for the 4-day availability window. |
curl -X GET "https://api.bjuti.ee/v1/agent/booking/availability-slots?location_id=96fb29cf-...&professional_id=8a1e47b2-...&service_ids=c14d9b2e-...,8b14da21-...&date=2026-11-15" \
-H "Authorization: Bearer <access_token>"
{
"status": "success",
"data": {
"location_id": "96fb29cf-a031-4ce8-b541-ef12998a1234",
"professional_id": "8a1e47b2-3c10-482a-99cd-482b991a0021",
"requested_date": "2026-11-15",
"total_duration_minutes": 80,
"dates": [
{
"date": "2026-11-15",
"day_of_week": "Sunday",
"slots_count": 0,
"slots": []
},
{
"date": "2026-11-16",
"day_of_week": "Monday",
"slots_count": 2,
"slots": ["10:00", "14:30"]
},
{
"date": "2026-11-17",
"day_of_week": "Tuesday",
"slots_count": 3,
"slots": ["11:00", "13:00", "16:00"]
},
{
"date": "2026-11-18",
"day_of_week": "Wednesday",
"slots_count": 0,
"slots": []
}
],
"first_available": null,
"waitlist_available": true
}
}
9. Initiate Booking & 15-Minute Hold
Locks the selected slot for exactly 15 minutes with status On Hold. Enforces the one-active-booking-per-category rule and dispatches a 6-digit confirmation code to the client's email address.
Parameters (JSON body)
| Field | Type | Source & Description |
|---|---|---|
location_id required | uuid | Sourced from Step 3 Salon location UUID. |
professional_id required | uuid | Sourced from Step 3 or 4 Specialist UUID. |
service_ids required | array[uuid] | Sourced from Step 4 Array of treatment UUIDs from pricelist. |
date required | string | Sourced from Step 5 Chosen appointment date in YYYY-MM-DD. |
start_time required | string | Sourced from Step 5 Open slot start time from slots[date][] (e.g. "14:00"). |
contact_firstname required | string | Client first name. |
contact_lastname optional | string | Client last name. |
contact_phone required | string | Client mobile phone number. |
contact_email required | string | Client email (where 6-digit confirmation code will be dispatched). |
message_text optional | string | Optional note or request for the specialist. |
result_photo_base64 optional | string | Desired style/result reference photo (Base64). |
curl -X POST https://api.bjuti.ee/v1/agent/booking/hold \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"location_id": "96fb29cf-a031-4ce8-b541-ef12998a1234",
"professional_id": "8a1e47b2-3c10-482a-99cd-482b991a0021",
"service_ids": ["c14d9b2e-7412-4aa3-8fa9-994b2a8901aa"],
"date": "2026-11-15",
"start_time": "14:00",
"contact_firstname": "Mary",
"contact_lastname": "Smith",
"contact_phone": "+37255123456",
"contact_email": "mary.smith@example.com",
"message_text": "Prefer lighter tone highlights."
}'
{
"status": "success",
"data": {
"booking_id": "3b29c1e0-71a2-47e9-a02b-118833fa0011",
"status": "On Hold",
"hold_expires_at": "2026-11-08T21:12:30+02:00",
"hold_duration_seconds": 900,
"message": "Time reserved for 15 minutes. Verification code sent to mary.smith@example.com."
}
}
{
"status": "error",
"code": "ACTIVE_BOOKING_EXISTS",
"message": "Client already has an active booking in category 'hair' on 2026-11-20 11:00."
}
10. Confirm Booking with Email Verification Code
Confirms an On Hold reservation by validating the client's 6-digit email confirmation code. Protected against brute-force attacks (up to 5 invalid attempts before lock). If the salon requires a deposit, a secure payment URL is issued.
Parameters (JSON body)
| Field | Type | Source & Description |
|---|---|---|
booking_id required | uuid | Sourced from Step 6 POST /v1/agent/booking/hold response field data.booking_id. |
verification_code required | string | 6-digit verification code sent to client's email (e.g. "481902"). |
curl -X POST https://api.bjuti.ee/v1/agent/booking/confirm \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"booking_id": "3b29c1e0-71a2-47e9-a02b-118833fa0011",
"verification_code": "481902"
}'
{
"status": "success",
"data": {
"booking_id": "3b29c1e0-71a2-47e9-a02b-118833fa0011",
"status": "Confirmed",
"confirmed_at": "2026-11-08T20:58:12+02:00",
"requires_deposit": false,
"payment_url": null,
"summary": {
"salon": "Studio Elegance Downtown",
"professional": "Kadri Kallas",
"date": "2026-11-15",
"start_time": "14:00",
"total_price": 45.00
}
}
}
{
"status": "error",
"code": "INVALID_VERIFICATION_CODE",
"message": "Invalid code. 3 attempts remaining."
}
11. Release Hold Slot Early
If the client decides to cancel or choose a different time, the agent can release the hold immediately without waiting for the 15-minute expiration timer.
Parameters (JSON body)
| Field | Type | Source & Description |
|---|---|---|
booking_id required | uuid | Sourced from Step 6 UUID of the active on-hold reservation (data.booking_id). |
curl -X POST https://api.bjuti.ee/v1/agent/booking/release-hold \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"booking_id": "3b29c1e0-71a2-47e9-a02b-118833fa0011"
}'
{
"status": "success",
"message": "Booking hold released successfully. Slot is available again."
}
12. Waiting List API (Waitlist)
Adds client to the professional's waiting list when no suitable opening is available on requested dates. If the client is already queued, preferences are updated while preserving their position. When an opening occurs, slots are allocated via FIFO.
Parameters (JSON body)
| Field | Type | Source & Description |
|---|---|---|
location_id required | uuid | Sourced from Step 3 Salon location UUID (salons[].location_id). |
professional_id required | uuid | Sourced from Step 3 or 4 Specialist UUID. |
service_ids required | array[uuid] | Sourced from Step 4 Array of treatment UUIDs from pricelist. |
contact_firstname required | string | Client first name. |
contact_lastname optional | string | Client last name. |
contact_phone required | string | Client mobile phone number. |
contact_email required | string | Client email address. |
message_text optional | string | Client notes on preferred dates or times. |
curl -X POST https://api.bjuti.ee/v1/agent/booking/waitlist \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"location_id": "96fb29cf-a031-4ce8-b541-ef12998a1234",
"professional_id": "8a1e47b2-3c10-482a-99cd-482b991a0021",
"service_ids": ["c14d9b2e-7412-4aa3-8fa9-994b2a8901aa"],
"contact_firstname": "Mary",
"contact_lastname": "Smith",
"contact_phone": "+37255123456",
"contact_email": "mary.smith@example.com",
"message_text": "Prefer weekday evenings after 17:00."
}'
{
"status": "success",
"message": "Client successfully added to waiting list.",
"data": {
"waitlist_id": "18cf41a0-8910-4bc3-90b1-4478129031ef",
"already_waiting": false,
"status": "waiting",
"title": "Women's Haircut & Blow-dry",
"duration_minutes": 60,
"created_at": "2026-11-08T21:25:00+02:00"
}
}
{
"status": "success",
"message": "Client is already on the waiting list; request details updated.",
"data": {
"waitlist_id": "18cf41a0-8910-4bc3-90b1-4478129031ef",
"already_waiting": true,
"status": "waiting",
"title": "Women's Haircut & Blow-dry",
"duration_minutes": 60
}
}
13. Query Client Active Bookings
Allows an agent to check a client's active upcoming reservations prior to initiating a new booking, avoiding duplicate appointments in the same category.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
contact_email required | string | Client email address |
category optional | string | Category code filter (e.g. hair) |
curl -X GET "https://api.bjuti.ee/v1/agent/booking/my-active?contact_email=mary.smith@example.com" \
-H "Authorization: Bearer <access_token>"
{
"status": "success",
"data": [
{
"booking_id": "77a102bb-8199-4c01-bf10-9941a8291001",
"status": "Confirmed",
"category": "hair",
"service_name": "Women's Haircut",
"salon_name": "Studio Elegance Downtown",
"start_time": "2026-11-20T11:00:00+02:00"
}
]
}
What is the Bjuti MCP Server?
The Model Context Protocol (MCP) is an open standard enabling AI models and autonomous assistants (e.g. Claude Desktop, Cursor, bespoke agents) to securely interface with real-world business tools. Bjuti provides a dedicated, native MCP daemon that empowers agents to search salons, compute available slots, and manage reservations directly without middleware code.
https://api.bjuti.ee/mcp.The daemon supports both JSON-RPC 2.0 requests and Server-Sent Events (SSE) streaming connections.
MCP Client Configuration (Examples)
If you are integrating Claude Desktop, Cursor, or any MCP-compliant AI framework, add the Bjuti MCP endpoint to your client configuration:
Example: Claude Desktop (`claude_desktop_config.json`)
{
"mcpServers": {
"bjuti": {
"url": "https://api.bjuti.ee/mcp",
"headers": {
"Authorization": "Bearer <YOUR_ACCESS_TOKEN>"
}
}
}
}
Example: Direct JSON-RPC Request over HTTPS
curl -X POST https://api.bjuti.ee/mcp \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "bjuti_find_salons",
"arguments": {
"lat": 59.4369,
"lng": 24.7535,
"radius_km": 15
}
}
}'
Published Bjuti MCP Tools
The Bjuti MCP server exposes the following specialized tools to connected AI agents:
| Tool Name | Input Parameters | Description |
|---|---|---|
bjuti_agent_auth |
client_id, client_secret |
Authenticates the agent and returns a 15-minute Bearer access token. |
bjuti_get_service_categories |
country (optional) |
Retrieves available beauty service categories (Hair, Nails, Facial, etc.). |
bjuti_find_salons |
lat, lng, radius_km, query |
Searches salons by GPS coordinates or text query. |
bjuti_get_salon_pricelist |
location_id |
Fetches the official pricelist of treatments and prices for a salon location. |
bjuti_get_available_slots |
location_id, professional_id, service_ids, date |
Computes available appointment slots based on calendar schedules. |
bjuti_hold_booking |
location_id, professional_id, service_ids, date, start_time, contact_firstname, contact_phone, contact_email |
Locks a booking slot for 15 minutes and dispatches a 6-digit verification code to the client email. |
bjuti_confirm_booking |
booking_id, verification_code |
Confirms an On Hold booking using the 6-digit email verification code. |
bjuti_release_hold |
booking_id |
Releases an active 15-minute hold immediately before expiration. |
bjuti_join_waitlist |
location_id, professional_id, service_ids, contact_firstname, contact_phone, contact_email |
Places client on the waiting list when requested dates are unavailable. |
bjuti_get_active_booking |
contact_email, category_id |
Checks for active upcoming reservations to prevent duplicate bookings. |