REST API Reference

SureBooking REST API

Token-authenticated API for integrating SureBooking with mobile apps, third-party services, and custom frontends.

🔸 Overview

Base URL

https://yourdomain.com/api/v1

Response Format

JSON (Content-Type: application/json)

All API responses follow a consistent envelope structure:

{
  "success": true,
  "data": { ... },       // resource data or array
  "message": "...",      // optional human-readable message
  "meta": { ... }        // pagination info (list endpoints only)
}

Pagination meta (list endpoints)

{
  "meta": {
    "current_page": 1,
    "last_page": 5,
    "per_page": 15,
    "total": 73
  }
}

🔒 Authentication

All API endpoints require a valid Bearer token. Requests without a token receive 401 Unauthorized.

Sending the token

Include the token in the Authorization header of every request:

GET /api/v1/appointments HTTP/1.1
Host: yourdomain.com
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json

Example with cURL

curl -H "Authorization: Bearer YOUR_API_TOKEN" \
     -H "Accept: application/json" \
     https://yourdomain.com/api/v1/appointments

Rate Limiting

Each API token has a configurable rate limit (requests per minute). When exceeded, the API returns 429 Too Many Requests. The limit can be adjusted per client in Admin → API Clients.

🔑 Token Management

API tokens are managed from the admin panel. Each token belongs to an API Client record that controls its name, status, and rate limit.

Creating a token

  1. Login to the Admin Panel at /admin
  2. Navigate to Admin → API Clients
  3. Click Add New and enter a name for the client (e.g., "Mobile App")
  4. Save. Then click Generate Token on the client detail page
  5. Copy the token immediately — it will not be shown again in full
You can generate multiple tokens per client and revoke individual tokens at any time from Admin → API Clients → [client] → Tokens.

Revoking a token

Go to Admin → API Clients → [client name] and click Revoke next to the token. The token becomes invalid immediately.

Updating rate limits

On the client detail page click Update Config to change the requests-per-minute limit for that client.

📅 Appointments

GET /api/v1/appointments List appointments

Returns a paginated list of appointments.

Query parameters

Parameter Type Description
statusintegerFilter by status value (see status table below)
date_fromstringFilter from date (YYYY-MM-DD)
date_tostringFilter to date (YYYY-MM-DD)
branch_idintegerFilter by branch ID
per_pageintegerItems per page (default: 15, max: 100)
pageintegerPage number (default: 1)

Example response

{
  "success": true,
  "data": [
    {
      "id": 101,
      "status": 1,
      "note": null,
      "createdAt": "2026-07-10T09:00:00.000000Z",
      "branch": { "id": 2, "name": "Downtown Branch", "address": "123 Main St", "phone": "0901234567" },
      "customer": { "id": 5, "name": "Nguyen Van A", "email": "customer@example.com", "phone": "0912345678", "isGuest": false },
      "appointmentDetail": [
        {
          "id": 1,
          "service": { "id": 3, "name": "Deep Tissue Massage" },
          "employee": { "id": 7, "name": "Tran Thi B" },
          "price": 350000,
          "priceFrom": 320000,
          "duration": 60,
          "timeStart": "2026-07-12 10:00:00",
          "timeEnd": "2026-07-12 11:00:00"
        }
      ],
      "payment": { "method": "bank_transfer", "amount": 350000, "status": "pending" }
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 3,
    "per_page": 15,
    "total": 42
  }
}
GET /api/v1/appointments/{id} Get appointment detail

Returns full appointment data including branch, customer, all service line items with employee assignments, and payment info.

Error response (404)

{ "success": false, "message": "Appointment not found." }
PATCH /api/v1/appointments/{id}/status Update appointment status

Transitions an appointment through its lifecycle. Only valid transitions are accepted — attempting an out-of-sequence change returns 422 with the list of allowed next statuses.

Status values

Value Constant Meaning
-1STATUS_DRAFDraft — saved but not yet submitted
1STATUS_NEWNew — submitted, awaiting review
2STATUS_CANCELCancelled
3STATUS_SUCCESSCompleted successfully
4STATUS_ACCEPTEDAccepted by the salon

Allowed transitions

Current status Can transition to Side effects
-1 — DRAFT 1 — NEW History logged
1 — NEW 4 — ACCEPTED, 2 — CANCEL History logged · Email sent to customer
4 — ACCEPTED 3 — SUCCESS, 2 — CANCEL History logged · Email sent
3 — SUCCESS Terminal state
2 — CANCEL Terminal state

Request body (JSON)

Field Type Description
statusinteger (required)Target status value (see table above)
reasonstring (optional)Cancellation reason — used when transitioning to status 2

Example — accept appointment (NEW → ACCEPTED)

PATCH /api/v1/appointments/101/status
Authorization: Bearer {token}
Content-Type: application/json

{ "status": 4 }

Example — cancel appointment (NEW → CANCEL)

PATCH /api/v1/appointments/101/status
Authorization: Bearer {token}
Content-Type: application/json

{ "status": 2, "reason": "Customer requested cancellation" }

Success response 200

{
  "success": true,
  "message": "Appointment status updated.",
  "data": { "id": 101, "status": 4, ... }
}

Invalid transition response 422

{
  "success": false,
  "message": "Status transition not allowed.",
  "current": 1,
  "allowed": [4, 2]
}

🏠 Branches

GET /api/v1/branches List branches

Returns a paginated list of active branches.

Query parameters

ParameterTypeDescription
searchstringFilter by branch name (partial match)
per_pageintegerItems per page (default: 15, max: 100)
pageintegerPage number (default: 1)

Response fields

id, name, slug, address, phone, image, status, createdAt

GET /api/v1/branches/{id} Get branch detail

Returns a single active branch. Returns 404 if not found or inactive.

📁 Service Categories

GET /api/v1/service-categories List service categories

Returns a list of active service categories. When branch_id is supplied, returns only categories that have at least one active service at that branch (flat list, no pagination).

Query parameters

ParameterTypeDescription
branch_idintegerReturn categories that have active services at this branch (bypasses pagination)
per_pageintegerItems per page (default: 15, max: 100) — ignored when branch_id is set
pageintegerPage number (default: 1) — ignored when branch_id is set

Example response

{
  "success": true,
  "data": [
    {
      "id": 3,
      "name": "Hair Care",
      "image": "uploads/categories/hair-care.jpg",
      "description": "All hair styling and treatment services",
      "branchId": 1,
      "status": 1
    }
  ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 15, "total": 4 }
}
GET /api/v1/service-categories/{id} Get category detail with services

Returns a single active category together with its active services (including variants for each service). Returns 404 if not found or inactive.

Example response

{
  "success": true,
  "data": {
    "id": 3,
    "name": "Hair Care",
    "image": "uploads/categories/hair-care.jpg",
    "description": "All hair styling and treatment services",
    "branchId": 1,
    "status": 1,
    "services": [
      {
        "id": 12,
        "name": "Hair Cut",
        "image": "uploads/services/haircut.jpg",
        "price": 150000,
        "priceOld": null,
        "isPriceFrom": true,
        "duration": 30,
        "status": 1,
        "category": { "id": 3, "name": "Hair Care" },
        "variants": [
          { "id": 5, "name": "Short Hair", "price": 150000, "isPriceFrom": false, "duration": 30 },
          { "id": 6, "name": "Long Hair",  "price": 200000, "isPriceFrom": false, "duration": 45 }
        ]
      }
    ]
  }
}

✨ Services

GET /api/v1/services List services

Returns a paginated list of active services. When branch_id is supplied, returns all services available at that branch (flat list, no pagination).

Query parameters

ParameterTypeDescription
searchstringFilter by service name (partial match)
branch_idintegerReturn services available at this branch (bypasses pagination)
category_idintegerFilter by service category ID (combinable with branch_id)
per_pageintegerItems per page (default: 15, max: 100)
pageintegerPage number (default: 1)

Price display logic

When a service has variants, the top-level price reflects the minimum price across active variants and isPriceFrom is true if any variant has that flag set. Use the variants array for per-option pricing.

Example response

{
  "success": true,
  "data": [
    {
      "id": 12,
      "name": "Hair Cut",
      "image": "uploads/services/haircut.jpg",
      "price": 150000,
      "priceOld": null,
      "isPriceFrom": true,
      "duration": 30,
      "status": 1,
      "category": { "id": 3, "name": "Hair Care" },
      "variants": [
        { "id": 5, "name": "Short Hair", "price": 150000, "isPriceFrom": false, "duration": 30 },
        { "id": 6, "name": "Long Hair",  "price": 200000, "isPriceFrom": false, "duration": 45 }
      ]
    },
    {
      "id": 13,
      "name": "Head Massage",
      "image": "uploads/services/massage.jpg",
      "price": 120000,
      "priceOld": 150000,
      "isPriceFrom": false,
      "duration": 45,
      "status": 1,
      "category": { "id": 3, "name": "Hair Care" },
      "variants": []
    }
  ],
  "meta": { "current_page": 1, "last_page": 2, "per_page": 15, "total": 18 }
}
GET /api/v1/services/{id} Get service detail

Returns a single active service with its category and full variants list. Returns 404 if not found or inactive.

Response fields

FieldTypeDescription
idintegerService ID
namestringService name
imagestring|nullIcon/image path
priceintegerDisplay price — min variant price when variants exist, otherwise service price
priceOldinteger|nullOriginal price before discount (service level)
isPriceFrombooleanWhether to show as "from X" — true if any active variant has this flag
durationintegerService duration in minutes (service level)
statusintegerStatus value
categoryobjectService category — id, name
variantsarrayActive variants — each has id, name, price, isPriceFrom, duration. Empty array when service has no variants.

👤 Customers

GET /api/v1/customers List customers

Returns a paginated list of customers. The search parameter matches against name, email, and phone simultaneously.

Query parameters

ParameterTypeDescription
searchstringSearch by name, email, or phone (partial match)
per_pageintegerItems per page (default: 15, max: 100)
pageintegerPage number (default: 1)

Response fields

id, name, email, phone, isGuest, createdAt

GET /api/v1/customers/{id} Get customer detail with appointment history

Returns a single customer along with their paginated appointment history. Returns 404 if not found.

Query parameters

ParameterTypeDescription
appointments_per_pageintegerAppointments per page (default: 10, max: 50)
appointments_pageintegerAppointment page number (default: 1)

Example response

{
  "success": true,
  "data": {
    "id": 5,
    "name": "Nguyen Van A",
    "email": "customer@example.com",
    "phone": "0912345678",
    "isGuest": false,
    "createdAt": "2026-06-01T08:00:00.000000Z",
    "appointments": [
      {
        "id": 101,
        "code": "APT-20260712-001",
        "status": 3,
        "statusText": "Completed",
        "dateAppointment": "2026-07-12",
        "timeStart": "10:00:00",
        "timeEnd": "11:00:00",
        "totalPrice": 350000,
        "branch": { "id": 2, "name": "Downtown Branch" },
        "createdAt": "2026-07-10T09:00:00.000000Z"
      }
    ]
  },
  "meta": {
    "appointments": {
      "current_page": 1,
      "last_page": 3,
      "per_page": 10,
      "total": 25
    }
  }
}

⚠️ Error Responses

HTTP Code Meaning Common cause
400Bad RequestMalformed JSON body
401UnauthorizedMissing or invalid token
404Not FoundResource does not exist or is inactive
422Unprocessable EntityValidation failed or status transition not allowed
429Too Many RequestsRate limit exceeded for this token
500Server ErrorUnexpected server error (check Laravel logs)

Validation error envelope (422)

{
  "success": false,
  "message": "The status field is required.",
  "errors": {
    "status": ["The status field is required."]
  }
}

SureBooking — REST API Reference

© 2026 DreamTeam. All rights reserved.  |  Install Guide  |  User Guide  |  FAQ