openapi: 3.0.3
info:
  title: Numbors API
  version: 1.0.0
  description: |
    The Numbors REST API lets you programmatically manage contacts, invoices,
    transactions, inventory, payroll, CRM, and every other module available
    in the Numbors platform.

    All endpoints (except authentication) require a valid JWT Bearer token
    **and** a company context supplied via the `X-Company-Id` header.
  contact:
    name: Numbors Support
    url: https://app.numbors.com/hub
  license:
    name: Proprietary

servers:
  - url: https://app.numbors.com/api
    description: Production
  - url: http://localhost:3003/api
    description: Local development

security:
  - BearerAuth: []
  - ApiKeyAuth: []

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        Obtain a token via `POST /api/auth/login`, then send it as
        `Authorization: Bearer <token>` on every subsequent request.
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        Long-lived API key created in Settings > API Keys.
        Send as `X-API-Key: nb_your_key_here`. No X-Company-Id header needed —
        the key is scoped to the company it was created for.

  headers:
    X-Company-Id:
      description: The MongoDB ObjectId of the company to operate on. Required for all endpoints after authentication.
      schema:
        type: string
        example: 507f1f77bcf86cd799439011

  parameters:
    idParam:
      name: id
      in: path
      required: true
      schema:
        type: string
      description: MongoDB ObjectId
    pageParam:
      name: page
      in: query
      schema:
        type: integer
        default: 1
      description: Page number
    limitParam:
      name: limit
      in: query
      schema:
        type: integer
        default: 25
      description: Items per page

  schemas:
    Error:
      type: object
      properties:
        error:
          type: string
          example: Invalid credentials
    Success:
      type: object
      properties:
        success:
          type: boolean
          example: true
        message:
          type: string
    PaginatedMeta:
      type: object
      properties:
        total:
          type: integer
        page:
          type: integer
        limit:
          type: integer

tags:
  - name: Authentication
    description: Register, login, and retrieve the current user.
  - name: Modules
    description: Query enabled modules and license information.
  - name: Companies
    description: List companies accessible to the authenticated user.
  - name: Contacts
    description: Manage customers, suppliers, and other contacts.
  - name: Documents
    description: Create and manage invoices, bills, and other financial documents.
  - name: Accounts
    description: Bank accounts and cash accounts.
  - name: Transactions
    description: Income and expense transactions.
  - name: Items
    description: Products and services used on invoices and bills.
  - name: Categories
    description: Income and expense categories.
  - name: Taxes
    description: Tax rates applied to line items.
  - name: Currencies
    description: Multi-currency support.
  - name: Estimates
    description: Quotes and estimates sent to customers.
  - name: Credit Notes
    description: Credit notes issued against invoices.
  - name: Accounting
    description: Chart of accounts and journal entries.
  - name: Inventory
    description: Warehouses, stock transfers, and adjustments.
  - name: Projects
    description: Project management and time tracking.
  - name: Payroll
    description: Departments, employees, and pay runs.
  - name: Point of Sale
    description: POS terminals, sessions, orders, and loyalty programmes.
  - name: CRM
    description: Pipelines, leads, deals, activities, and campaigns.
  - name: Contracts & Proposals
    description: Manage contracts and send proposals.
  - name: Helpdesk
    description: Ticket categories, tickets, SLAs, and knowledge-base articles.
  - name: Orders
    description: Sales orders and purchase orders.
  - name: Banking
    description: Open-banking feeds, connections, and auto-categorisation rules.
  - name: Transfers
    description: Inter-account transfers.

paths:
  # ── Authentication ──────────────────────────────────────────────────
  /auth/register:
    post:
      tags: [Authentication]
      summary: Register a new user
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, email, password]
              properties:
                name:
                  type: string
                  example: Jane Smith
                email:
                  type: string
                  format: email
                  example: jane@example.com
                password:
                  type: string
                  format: password
                  example: SecurePass!123
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  token:
                    type: string
                  user:
                    type: object
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      email:
                        type: string
        '400':
          description: Validation error or email already registered
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /auth/login:
    post:
      tags: [Authentication]
      summary: Log in and receive a JWT
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email:
                  type: string
                  format: email
                  example: jane@example.com
                password:
                  type: string
                  format: password
      responses:
        '200':
          description: Login successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  token:
                    type: string
                    description: "JWT token — use as `Authorization: Bearer <token>`"
                  user:
                    type: object
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      email:
                        type: string
                      companies:
                        type: array
                        items:
                          type: object
        '401':
          description: Invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /auth/me:
    get:
      tags: [Authentication]
      summary: Get current authenticated user
      responses:
        '200':
          description: Current user info
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  user:
                    type: object
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      email:
                        type: string
                      companies:
                        type: array
                        items:
                          type: object
                      roles:
                        type: array
                        items:
                          type: object

  # ── Modules ─────────────────────────────────────────────────────────
  /modules/enabled:
    get:
      tags: [Modules]
      summary: List enabled modules
      description: Returns the list of enabled modules for client-side caching.
      responses:
        '200':
          description: Enabled modules
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  modules:
                    type: array
                    items:
                      type: string
                  cacheKey:
                    type: string
                  ttl:
                    type: integer
                    example: 300
                  timestamp:
                    type: integer

  /modules/check/{alias}:
    get:
      tags: [Modules]
      summary: Check if a specific module is accessible
      parameters:
        - name: alias
          in: path
          required: true
          schema:
            type: string
          description: Module alias (e.g. `crm`, `payroll`, `pos`)
      responses:
        '200':
          description: Module accessibility
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  module:
                    type: string
                  accessible:
                    type: boolean

  /modules/licenses:
    get:
      tags: [Modules]
      summary: Get detailed license information
      responses:
        '200':
          description: License details for all modules
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  modules:
                    type: array
                    items:
                      type: object
                      properties:
                        alias:
                          type: string
                        isCore:
                          type: boolean
                        isLicensed:
                          type: boolean
                        isEnabled:
                          type: boolean
                        isAccessible:
                          type: boolean
                  summary:
                    type: object
                    properties:
                      total:
                        type: integer
                      licensed:
                        type: integer
                      enabled:
                        type: integer

  # ── Companies ───────────────────────────────────────────────────────
  /companies:
    get:
      tags: [Companies]
      summary: List accessible companies
      responses:
        '200':
          description: List of companies
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object

  # ── Contacts ────────────────────────────────────────────────────────
  /contacts:
    get:
      tags: [Contacts]
      summary: List contacts
      parameters:
        - name: type
          in: query
          schema:
            type: string
            enum: [customer, supplier, both]
          description: Filter by contact type
        - name: enabled
          in: query
          schema:
            type: boolean
        - name: search
          in: query
          schema:
            type: string
          description: Search by name or email
        - $ref: '#/components/parameters/pageParam'
        - $ref: '#/components/parameters/limitParam'
      responses:
        '200':
          description: Paginated contacts
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
                  meta:
                    $ref: '#/components/schemas/PaginatedMeta'
    post:
      tags: [Contacts]
      summary: Create a contact
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  example: Acme Ltd
                email:
                  type: string
                  format: email
                type:
                  type: string
                  enum: [customer, supplier, both]
                phone:
                  type: string
                taxNumber:
                  type: string
      responses:
        '201':
          description: Contact created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /contacts/{id}:
    get:
      tags: [Contacts]
      summary: Get a contact
      parameters:
        - $ref: '#/components/parameters/idParam'
      responses:
        '200':
          description: Contact details
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    put:
      tags: [Contacts]
      summary: Update a contact
      parameters:
        - $ref: '#/components/parameters/idParam'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                email:
                  type: string
                type:
                  type: string
      responses:
        '200':
          description: Contact updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
    delete:
      tags: [Contacts]
      summary: Delete a contact
      parameters:
        - $ref: '#/components/parameters/idParam'
      responses:
        '200':
          description: Contact deleted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Success'

  # ── Documents ───────────────────────────────────────────────────────
  /documents:
    get:
      tags: [Documents]
      summary: List documents (invoices, bills)
      parameters:
        - name: type
          in: query
          schema:
            type: string
            enum: [invoice, bill]
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, sent, paid, overdue, void]
        - $ref: '#/components/parameters/pageParam'
        - $ref: '#/components/parameters/limitParam'
      responses:
        '200':
          description: Paginated documents
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
                  meta:
                    $ref: '#/components/schemas/PaginatedMeta'
    post:
      tags: [Documents]
      summary: Create a document
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [type, contact]
              properties:
                type:
                  type: string
                  enum: [invoice, bill]
                contact:
                  type: string
                  description: Contact ObjectId
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      item:
                        type: string
                      quantity:
                        type: number
                      price:
                        type: number
                dueDate:
                  type: string
                  format: date
      responses:
        '201':
          description: Document created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /documents/{id}:
    get:
      tags: [Documents]
      summary: Get a document
      parameters:
        - $ref: '#/components/parameters/idParam'
      responses:
        '200':
          description: Document details with populated contact and items
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    put:
      tags: [Documents]
      summary: Update a document
      parameters:
        - $ref: '#/components/parameters/idParam'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Document updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
    delete:
      tags: [Documents]
      summary: Delete a document
      parameters:
        - $ref: '#/components/parameters/idParam'
      responses:
        '200':
          description: Document deleted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Success'

  # ── Accounts ────────────────────────────────────────────────────────
  /accounts:
    get:
      tags: [Accounts]
      summary: List bank and cash accounts
      responses:
        '200':
          description: List of accounts
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Accounts]
      summary: Create an account
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, type]
              properties:
                name:
                  type: string
                  example: Business Current Account
                type:
                  type: string
                  enum: [bank, cash, credit_card]
                currency:
                  type: string
                  example: GBP
                openingBalance:
                  type: number
      responses:
        '201':
          description: Account created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Transactions ────────────────────────────────────────────────────
  /transactions:
    get:
      tags: [Transactions]
      summary: List transactions
      parameters:
        - name: type
          in: query
          schema:
            type: string
            enum: [income, expense]
        - name: account
          in: query
          schema:
            type: string
          description: Account ObjectId filter
        - $ref: '#/components/parameters/pageParam'
        - $ref: '#/components/parameters/limitParam'
      responses:
        '200':
          description: Paginated transactions
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
                  meta:
                    $ref: '#/components/schemas/PaginatedMeta'
    post:
      tags: [Transactions]
      summary: Create a transaction
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [type, account, amount]
              properties:
                type:
                  type: string
                  enum: [income, expense]
                account:
                  type: string
                  description: Account ObjectId
                amount:
                  type: number
                description:
                  type: string
                category:
                  type: string
                  description: Category ObjectId
                contact:
                  type: string
                  description: Contact ObjectId
                paidAt:
                  type: string
                  format: date-time
      responses:
        '201':
          description: Transaction created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Items ───────────────────────────────────────────────────────────
  /items:
    get:
      tags: [Items]
      summary: List products and services
      responses:
        '200':
          description: List of items
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Items]
      summary: Create an item
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  example: Web Development
                type:
                  type: string
                  enum: [product, service]
                salePrice:
                  type: number
                purchasePrice:
                  type: number
                category:
                  type: string
                  description: Category ObjectId
      responses:
        '201':
          description: Item created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Categories ──────────────────────────────────────────────────────
  /categories:
    get:
      tags: [Categories]
      summary: List categories
      parameters:
        - name: type
          in: query
          schema:
            type: string
            enum: [income, expense, other]
      responses:
        '200':
          description: List of categories
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Categories]
      summary: Create a category
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, type]
              properties:
                name:
                  type: string
                type:
                  type: string
                  enum: [income, expense, other]
      responses:
        '201':
          description: Category created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /categories/{id}:
    put:
      tags: [Categories]
      summary: Update a category
      parameters:
        - $ref: '#/components/parameters/idParam'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                type:
                  type: string
      responses:
        '200':
          description: Category updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Taxes ───────────────────────────────────────────────────────────
  /taxes:
    get:
      tags: [Taxes]
      summary: List tax rates
      responses:
        '200':
          description: List of taxes
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Taxes]
      summary: Create a tax rate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, rate]
              properties:
                name:
                  type: string
                  example: Standard Rate
                rate:
                  type: number
                  example: 20
                type:
                  type: string
      responses:
        '201':
          description: Tax created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /taxes/{id}:
    put:
      tags: [Taxes]
      summary: Update a tax rate
      parameters:
        - $ref: '#/components/parameters/idParam'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                rate:
                  type: number
      responses:
        '200':
          description: Tax updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Currencies ──────────────────────────────────────────────────────
  /currencies:
    get:
      tags: [Currencies]
      summary: List currencies
      responses:
        '200':
          description: List of currencies
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Currencies]
      summary: Create a currency
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [code, name]
              properties:
                code:
                  type: string
                  example: EUR
                name:
                  type: string
                  example: Euro
                rate:
                  type: number
                  example: 1.17
      responses:
        '201':
          description: Currency created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Estimates ───────────────────────────────────────────────────────
  /estimates:
    get:
      tags: [Estimates]
      summary: List estimates
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, sent, accepted, declined, expired]
        - $ref: '#/components/parameters/pageParam'
        - $ref: '#/components/parameters/limitParam'
      responses:
        '200':
          description: Paginated estimates
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
                  meta:
                    $ref: '#/components/schemas/PaginatedMeta'
    post:
      tags: [Estimates]
      summary: Create an estimate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [contact]
              properties:
                contact:
                  type: string
                items:
                  type: array
                  items:
                    type: object
                expiryDate:
                  type: string
                  format: date
      responses:
        '201':
          description: Estimate created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /estimates/{id}:
    get:
      tags: [Estimates]
      summary: Get an estimate
      parameters:
        - $ref: '#/components/parameters/idParam'
      responses:
        '200':
          description: Estimate details
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    put:
      tags: [Estimates]
      summary: Update an estimate
      parameters:
        - $ref: '#/components/parameters/idParam'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Estimate updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
    delete:
      tags: [Estimates]
      summary: Delete an estimate
      parameters:
        - $ref: '#/components/parameters/idParam'
      responses:
        '200':
          description: Estimate deleted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Success'

  # ── Credit Notes ────────────────────────────────────────────────────
  /credit-notes:
    get:
      tags: [Credit Notes]
      summary: List credit notes
      responses:
        '200':
          description: List of credit notes
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Credit Notes]
      summary: Create a credit note
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [contact]
              properties:
                contact:
                  type: string
                amount:
                  type: number
                reason:
                  type: string
      responses:
        '201':
          description: Credit note created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Accounting ──────────────────────────────────────────────────────
  /accounting/chart-of-accounts:
    get:
      tags: [Accounting]
      summary: List chart of accounts
      responses:
        '200':
          description: Chart of accounts sorted by code
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Accounting]
      summary: Create a chart of account entry
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, code, type]
              properties:
                name:
                  type: string
                  example: Office Supplies
                code:
                  type: string
                  example: "6100"
                type:
                  type: string
                  enum: [asset, liability, equity, income, expense]
      responses:
        '201':
          description: Account created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /accounting/journal:
    get:
      tags: [Accounting]
      summary: List journal entries
      responses:
        '200':
          description: Journal entries sorted by date
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Accounting]
      summary: Create a journal entry
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [date, lines]
              properties:
                date:
                  type: string
                  format: date
                description:
                  type: string
                lines:
                  type: array
                  items:
                    type: object
                    properties:
                      account:
                        type: string
                      debit:
                        type: number
                      credit:
                        type: number
      responses:
        '201':
          description: Journal entry created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Inventory ───────────────────────────────────────────────────────
  /inventory/warehouses:
    get:
      tags: [Inventory]
      summary: List warehouses
      responses:
        '200':
          description: List of warehouses
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Inventory]
      summary: Create a warehouse
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  example: Main Warehouse
                address:
                  type: string
      responses:
        '201':
          description: Warehouse created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /inventory/transfers:
    get:
      tags: [Inventory]
      summary: List stock transfers
      responses:
        '200':
          description: List of stock transfers
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Inventory]
      summary: Create a stock transfer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [fromWarehouse, toWarehouse, items]
              properties:
                fromWarehouse:
                  type: string
                toWarehouse:
                  type: string
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      item:
                        type: string
                      quantity:
                        type: number
      responses:
        '201':
          description: Transfer created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /inventory/adjustments:
    post:
      tags: [Inventory]
      summary: Create a stock adjustment
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [warehouse, items]
              properties:
                warehouse:
                  type: string
                reason:
                  type: string
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      item:
                        type: string
                      quantity:
                        type: number
      responses:
        '201':
          description: Adjustment created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Projects ────────────────────────────────────────────────────────
  /projects:
    get:
      tags: [Projects]
      summary: List projects
      responses:
        '200':
          description: List of projects with populated customer
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Projects]
      summary: Create a project
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  example: Website Redesign
                customer:
                  type: string
                  description: Contact ObjectId
                budget:
                  type: number
                startDate:
                  type: string
                  format: date
                endDate:
                  type: string
                  format: date
      responses:
        '201':
          description: Project created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /projects/{id}:
    get:
      tags: [Projects]
      summary: Get a project
      parameters:
        - $ref: '#/components/parameters/idParam'
      responses:
        '200':
          description: Project details with tasks and customer
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    put:
      tags: [Projects]
      summary: Update a project
      parameters:
        - $ref: '#/components/parameters/idParam'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Project updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /projects/{id}/tasks:
    post:
      tags: [Projects]
      summary: Add a task to a project
      parameters:
        - $ref: '#/components/parameters/idParam'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  example: Design mockups
                assignedTo:
                  type: string
                dueDate:
                  type: string
                  format: date
      responses:
        '201':
          description: Task added
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /projects/time:
    get:
      tags: [Projects]
      summary: List time entries
      responses:
        '200':
          description: Time entries with populated project and user
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Projects]
      summary: Create a time entry
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [project, startTime, endTime]
              properties:
                project:
                  type: string
                  description: Project ObjectId
                startTime:
                  type: string
                  format: date-time
                endTime:
                  type: string
                  format: date-time
                description:
                  type: string
      responses:
        '201':
          description: Time entry created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Payroll ─────────────────────────────────────────────────────────
  /payroll/departments:
    get:
      tags: [Payroll]
      summary: List departments
      responses:
        '200':
          description: List of departments
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Payroll]
      summary: Create a department
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  example: Engineering
      responses:
        '201':
          description: Department created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /payroll/employees:
    get:
      tags: [Payroll]
      summary: List employees
      responses:
        '200':
          description: Employees with populated department and position
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Payroll]
      summary: Create an employee
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [firstName, lastName]
              properties:
                firstName:
                  type: string
                lastName:
                  type: string
                email:
                  type: string
                  format: email
                department:
                  type: string
                  description: Department ObjectId
                position:
                  type: string
                  description: Position ObjectId
                salary:
                  type: number
      responses:
        '201':
          description: Employee created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /payroll/pay-runs:
    get:
      tags: [Payroll]
      summary: List pay runs
      responses:
        '200':
          description: Pay runs sorted by pay date
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Payroll]
      summary: Create a pay run
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [payDate, period]
              properties:
                payDate:
                  type: string
                  format: date
                period:
                  type: string
                  example: "2025-01"
                employees:
                  type: array
                  items:
                    type: string
      responses:
        '201':
          description: Pay run created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Point of Sale ───────────────────────────────────────────────────
  /pos/terminals:
    get:
      tags: [Point of Sale]
      summary: List POS terminals
      responses:
        '200':
          description: List of terminals
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Point of Sale]
      summary: Create a POS terminal
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  example: Checkout 1
                location:
                  type: string
      responses:
        '201':
          description: Terminal created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /pos/sessions:
    get:
      tags: [Point of Sale]
      summary: List POS sessions
      responses:
        '200':
          description: Sessions with populated terminal and user
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object

  /pos/sessions/open:
    post:
      tags: [Point of Sale]
      summary: Open a new POS session
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [terminal]
              properties:
                terminal:
                  type: string
                  description: Terminal ObjectId
                openingFloat:
                  type: number
      responses:
        '201':
          description: Session opened
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /pos/orders:
    post:
      tags: [Point of Sale]
      summary: Create a POS order
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [session, items]
              properties:
                session:
                  type: string
                  description: Session ObjectId
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      item:
                        type: string
                      quantity:
                        type: number
                      price:
                        type: number
                paymentMethod:
                  type: string
                  enum: [cash, card, other]
      responses:
        '201':
          description: Order created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /pos/loyalty:
    get:
      tags: [Point of Sale]
      summary: List loyalty programmes
      responses:
        '200':
          description: List of loyalty programmes
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object

  /pos/loyalty/programs:
    post:
      tags: [Point of Sale]
      summary: Create a loyalty programme
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  example: Points Rewards
                pointsPerPound:
                  type: number
                  example: 1
      responses:
        '201':
          description: Programme created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── CRM ─────────────────────────────────────────────────────────────
  /crm/pipelines:
    get:
      tags: [CRM]
      summary: List pipelines
      responses:
        '200':
          description: List of pipelines
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [CRM]
      summary: Create a pipeline
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, stages]
              properties:
                name:
                  type: string
                  example: Sales Pipeline
                stages:
                  type: array
                  items:
                    type: object
                    properties:
                      name:
                        type: string
                      order:
                        type: integer
      responses:
        '201':
          description: Pipeline created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /crm/leads:
    get:
      tags: [CRM]
      summary: List leads
      responses:
        '200':
          description: List of leads
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [CRM]
      summary: Create a lead
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                email:
                  type: string
                  format: email
                source:
                  type: string
                  enum: [website, referral, cold_call, social_media, other]
      responses:
        '201':
          description: Lead created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /crm/deals:
    get:
      tags: [CRM]
      summary: List deals
      responses:
        '200':
          description: Deals with populated contact and pipeline
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [CRM]
      summary: Create a deal
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, pipeline]
              properties:
                name:
                  type: string
                  example: Enterprise Contract
                pipeline:
                  type: string
                  description: Pipeline ObjectId
                contact:
                  type: string
                  description: Contact ObjectId
                value:
                  type: number
                stage:
                  type: string
                  description: Stage ObjectId
      responses:
        '201':
          description: Deal created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /crm/activities:
    get:
      tags: [CRM]
      summary: List activities
      responses:
        '200':
          description: Activities sorted by scheduled date
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [CRM]
      summary: Create an activity
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [type, subject]
              properties:
                type:
                  type: string
                  enum: [call, email, meeting, task, note]
                subject:
                  type: string
                scheduledAt:
                  type: string
                  format: date-time
                deal:
                  type: string
                  description: Deal ObjectId
                contact:
                  type: string
                  description: Contact ObjectId
      responses:
        '201':
          description: Activity created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /crm/campaigns:
    get:
      tags: [CRM]
      summary: List campaigns
      responses:
        '200':
          description: List of campaigns
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [CRM]
      summary: Create a campaign
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, type]
              properties:
                name:
                  type: string
                  example: Spring Sale
                type:
                  type: string
                  enum: [email, sms, social]
                startDate:
                  type: string
                  format: date
                endDate:
                  type: string
                  format: date
      responses:
        '201':
          description: Campaign created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Contracts & Proposals ───────────────────────────────────────────
  /contracts:
    get:
      tags: [Contracts & Proposals]
      summary: List contracts
      responses:
        '200':
          description: Contracts with populated contact
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Contracts & Proposals]
      summary: Create a contract
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title, contact]
              properties:
                title:
                  type: string
                contact:
                  type: string
                  description: Contact ObjectId
                startDate:
                  type: string
                  format: date
                endDate:
                  type: string
                  format: date
                value:
                  type: number
      responses:
        '201':
          description: Contract created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /contracts/proposals:
    get:
      tags: [Contracts & Proposals]
      summary: List proposals
      responses:
        '200':
          description: Proposals with populated contact
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Contracts & Proposals]
      summary: Create a proposal
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title, contact]
              properties:
                title:
                  type: string
                contact:
                  type: string
                  description: Contact ObjectId
                sections:
                  type: array
                  items:
                    type: object
                    properties:
                      heading:
                        type: string
                      content:
                        type: string
                value:
                  type: number
      responses:
        '201':
          description: Proposal created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Helpdesk ────────────────────────────────────────────────────────
  /helpdesk/categories:
    get:
      tags: [Helpdesk]
      summary: List ticket categories
      responses:
        '200':
          description: List of ticket categories
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Helpdesk]
      summary: Create a ticket category
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  example: Billing
      responses:
        '201':
          description: Category created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /helpdesk/tickets:
    get:
      tags: [Helpdesk]
      summary: List tickets
      responses:
        '200':
          description: Tickets with populated contact, category, and assignee
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Helpdesk]
      summary: Create a ticket
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [subject]
              properties:
                subject:
                  type: string
                  example: Cannot access my account
                description:
                  type: string
                category:
                  type: string
                  description: TicketCategory ObjectId
                priority:
                  type: string
                  enum: [low, medium, high, urgent]
                contact:
                  type: string
                  description: Contact ObjectId
      responses:
        '201':
          description: Ticket created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /helpdesk/slas:
    get:
      tags: [Helpdesk]
      summary: List SLAs
      responses:
        '200':
          description: List of SLAs
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Helpdesk]
      summary: Create an SLA
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  example: Standard SLA
                responseTime:
                  type: integer
                  description: Hours
                resolutionTime:
                  type: integer
                  description: Hours
      responses:
        '201':
          description: SLA created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /helpdesk/articles:
    get:
      tags: [Helpdesk]
      summary: List knowledge-base articles
      responses:
        '200':
          description: List of articles
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Helpdesk]
      summary: Create an article
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title, body]
              properties:
                title:
                  type: string
                body:
                  type: string
                category:
                  type: string
                published:
                  type: boolean
                  default: false
      responses:
        '201':
          description: Article created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Orders ──────────────────────────────────────────────────────────
  /sales/orders:
    get:
      tags: [Orders]
      summary: List sales orders
      responses:
        '200':
          description: Sales orders with populated contact
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Orders]
      summary: Create a sales order
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [contact, items]
              properties:
                contact:
                  type: string
                  description: Contact ObjectId
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      item:
                        type: string
                      quantity:
                        type: number
                      price:
                        type: number
      responses:
        '201':
          description: Sales order created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /purchases/orders:
    get:
      tags: [Orders]
      summary: List purchase orders
      responses:
        '200':
          description: Purchase orders with populated contact
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Orders]
      summary: Create a purchase order
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [contact, items]
              properties:
                contact:
                  type: string
                  description: Contact ObjectId
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      item:
                        type: string
                      quantity:
                        type: number
                      price:
                        type: number
      responses:
        '201':
          description: Purchase order created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Banking ─────────────────────────────────────────────────────────
  /banking/feeds:
    get:
      tags: [Banking]
      summary: List bank feed transactions
      responses:
        '200':
          description: Bank feed transactions sorted by date
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object

  /banking/feeds/connections:
    get:
      tags: [Banking]
      summary: List bank connections
      responses:
        '200':
          description: List of bank connections
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Banking]
      summary: Create a bank connection
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [provider, account]
              properties:
                provider:
                  type: string
                account:
                  type: string
                  description: Account ObjectId
      responses:
        '201':
          description: Connection created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  /banking/feeds/rules:
    get:
      tags: [Banking]
      summary: List auto-categorisation rules
      responses:
        '200':
          description: List of bank rules
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Banking]
      summary: Create an auto-categorisation rule
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [pattern, category]
              properties:
                pattern:
                  type: string
                  description: Text pattern to match against transaction descriptions
                category:
                  type: string
                  description: Category ObjectId
                contact:
                  type: string
                  description: Contact ObjectId (optional auto-assign)
      responses:
        '201':
          description: Rule created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object

  # ── Transfers ───────────────────────────────────────────────────────
  /transfers:
    get:
      tags: [Transfers]
      summary: List inter-account transfers
      responses:
        '200':
          description: Transfers with populated accounts
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
    post:
      tags: [Transfers]
      summary: Create a transfer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [fromAccount, toAccount, amount]
              properties:
                fromAccount:
                  type: string
                  description: Source Account ObjectId
                toAccount:
                  type: string
                  description: Destination Account ObjectId
                amount:
                  type: number
                  example: 500
                description:
                  type: string
                paidAt:
                  type: string
                  format: date-time
      responses:
        '201':
          description: Transfer created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
