Guides

Guide - Branch Management

Invite-based branch creation flow, branch status lifecycle, and API endpoints for managing multi-branch organizations in booki-api.

Each organization can have multiple branches. Branches are created through an invite-based flow — the owner invites a branch manager by email, the manager accepts, and the branch is created during that process.


Data Model

Each branch (IBranch) stores:

FieldTypeDescription
_idObjectIdUnique branch ID
organizationIdObjectIdParent organization
managerIdObjectIdLinked BRANCH_MANAGER user
namestringHuman-readable name
slugstringURL-safe identifier (auto-generated from name)
addressobjectRegion, province, city, barangay, zip
statusstringactive, suspended, or closed
deletedAtDate | nullSoft delete timestamp

Note: The branch → manager relationship lives in Branch.managerId, not in the user document. IUser has no branchId field.


Invite Flow (Creating a Branch)

Branches are not created directly. Instead, owners invite a branch manager by email and the branch is created when the manager accepts.

1. Owner POSTs invite (email + branch name)
        ↓
2. Manager receives email with invite link (contains token)
        ↓
3. Manager verifies token via GET endpoint
        ↓
4. Manager POSTs branch details (address, personal info)
        ↓
5. Branch + BRANCH_MANAGER user created together

Auto-generated on creation:

  • slug — derived from branch name (e.g. "Manila Branch""manila-branch")
  • status — defaults to active
  • createdAt timestamp

Uniqueness constraints:

  • Branch name must be unique within the organization
  • Branch slug must be unique within the organization
  • Manager email must be unique across the entire system

API Endpoints

Send Branch Invite

POST /api/organizations/branches/invite
Authorization: Bearer <owner_token>
Content-Type: application/json

{
  "email": "manager@example.com"
}

Response (200):

{ "message": "Branch manager invite sent successfully." }

List Branch Invites

GET /api/organizations/branches/invite
Authorization: Bearer <owner_token>

Response (200):

{
  "invites": [
    {
      "_id": "507f1f77bcf86cd799439014",
      "email": "manager@example.com",
      "branchName": "Manila Branch",
      "status": "pending",
      "createdAt": "2026-02-21T00:00:00.000Z"
    }
  ]
}

Resend Branch Invite

PUT /api/organizations/branches/invite/:id/resend
Authorization: Bearer <owner_token>

Response (200):

{ "message": "Invite resent successfully." }

Cancel Branch Invite

PUT /api/organizations/branches/invite/:id/cancel
Authorization: Bearer <owner_token>

Response (200):

{ "message": "Invite cancelled successfully." }

Verify Invite Token (Public)

Called by the manager's invite link before submitting branch creation form.

GET /api/organizations/branches/invite/token/:token/verify

Returns invite details (email, branch name) if valid. Returns 400 if expired or already used.


Create Branch (from Token)

POST /api/organizations/branches/token/:token
Content-Type: application/json

{
  "address": {
    "region": "NCR",
    "province": "Metro Manila",
    "municipalOrCity": "Manila",
    "barangay": "Ermita",
    "zip": "1000"
  },
  "firstName": "Juan",
  "lastName": "Dela Cruz",
  "phone": "09161234567",
  "password": "SecurePassword123"
}

Response (201):

{ "message": "Branch successfully created." }

Get Branches (Paginated)

GET /api/organizations/branches
Authorization: Bearer <owner_token>
Query: page, limit, search

Response (200):

{
  "data": [
    {
      "_id": "507f1f77bcf86cd799439011",
      "name": "Manila Branch",
      "slug": "manila-branch",
      "organizationId": "507f1f77bcf86cd799439012",
      "managerId": "507f1f77bcf86cd799439013",
      "managerName": "Juan Dela Cruz",
      "status": "active",
      "createdAt": "2026-02-21T00:00:00.000Z"
    }
  ],
  "page": 1,
  "limit": 10,
  "total": 3,
  "totalPages": 1
}

Update Branch Status

Status is supplied as a route parameter, not a request body field.

Allowed values: activate, suspend, close

PUT /api/organizations/branches/:id/status/:status
Authorization: Bearer <owner_token>

# Example: suspend a branch
PUT /api/organizations/branches/507f1f77bcf86cd799439011/status/suspend

Response (200):

{ "message": "Branch has been suspended successfully." }

Error responses:

StatusMessage
404Branch not found
400Branch does not belong to your organization
400Branch is already suspended (or active / closed)

Branch Status Lifecycle

ACTIVE ──suspend──→ SUSPENDED
SUSPENDED ──activate──→ ACTIVE
ACTIVE / SUSPENDED ──close──→ CLOSED
StatusAccepts new bookingsManager accessReversible
activeYesFull
suspendedNoRead-onlyYes (activate)
closedNoRevokedNo

Branch Manager Permissions

Branch managers are scoped to their own branch only:

Can accessCannot access
Own branch bookingsOther branches' bookings or data
Own branch customersOrganization-level settings
Own branch reportsSubscription / billing info

Booking Rules

  • A booking must be assigned to a branch at creation (branchId required).
  • The branch must be active to accept new bookings.
  • The branch must belong to the booking's organizationId.
  • Branch managers cannot see bookings from other branches.