openapi: 3.0.3
info:
  title: DALSEEN Platform API
  version: 1.0.1
  description: DALSEEN tenant + platform HTTP API. **Contract:** `docs/current/DECISIONS.md` §5a (D1/D2/D4 amended 2026-04-29)
    and `docs/current/BACKEND-CONVENTIONS.md`. **Postman:** 317 requests; OpenAPI **operations** = unique `(method, path)` (**336**); duplicate
    Postman rows are merged into one operation. **Tenancy / IAM (Spatie)** — `GET /permissions`, `GET`/`POST`/`PATCH`/`DELETE /roles`,
    `GET`/`POST`/`PATCH`/`DELETE /users`, `PUT /users/{tenantUser}/roles`, `POST /users/invite`; see tag **02 — Tenancy & Onboarding**.
servers:
  - url: http://localhost:8000/api/v1
    description: Local development
tags:
- name: 00 — Reference · Canonical API errors
  description: 00 — Reference · Canonical API errors
- name: 01 — Auth & Identity
  description: 01 — Auth & Identity
- name: 02 — Tenancy & Onboarding
  description: 02 — Tenancy & Onboarding
- name: 03 — Catalog
  description: 03 — Catalog
- name: 04 — Inventory
  description: 04 — Inventory
- name: 05 — Sales / POS
  description: 05 — Sales / POS
- name: 06 — Returns / RMA
  description: 06 — Returns / RMA
- name: 07 — Customers, Loyalty, Gift Cards
  description: 07 — Customers, Loyalty, Gift Cards
- name: 08 — Suppliers & Purchasing
  description: 08 — Suppliers & Purchasing
- name: 09 — Promotions
  description: 09 — Promotions
- name: 10 — E-com & Marketplaces
  description: 10 — E-com & Marketplaces
- name: 11 — Dine / Orders & KDS
  description: 11 — Dine / Orders & KDS
- name: 12 — Dine / Tables & Reservations
  description: 12 — Dine / Tables & Reservations
- name: 13 — Dine / Menus, Modifiers, Combos
  description: 13 — Dine / Menus, Modifiers, Combos
- name: 14 — Dine / Recipes & Production
  description: 14 — Dine / Recipes & Production
- name: 15 — Dine / Delivery & Aggregators
  description: 15 — Dine / Delivery & Aggregators
- name: 16 — Pay (PSP)
  description: 16 — Pay (PSP)
- name: 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
  description: 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
- name: 17.1 — Chart of Accounts
  description: 17.1 — Chart of Accounts
- name: 17.10 — Dimensions (cost centers, projects)
  description: 17.10 — Dimensions (cost centers, projects)
- name: 17.11 — Financial reports
  description: 17.11 — Financial reports
- name: 17.12 — Settings & integrations
  description: 17.12 — Settings & integrations
- name: 17.13 — Audit trail
  description: 17.13 — Audit trail
- name: 17.2 — Fiscal calendar & periods
  description: 17.2 — Fiscal calendar & periods
- name: 17.3 — Opening balances
  description: 17.3 — Opening balances
- name: 17.4 — Tax · VAT · ZATCA
  description: 17.4 — Tax · VAT · ZATCA
- name: 17.5 — Customers & AR
  description: 17.5 — Customers & AR
- name: 17.6 — Vendors & AP
  description: 17.6 — Vendors & AP
- name: 17.7 — Journal & GL
  description: 17.7 — Journal & GL
- name: 17.8 — Vouchers (CR / CP / JV)
  description: 17.8 — Vouchers (CR / CP / JV)
- name: 17.9 — Banking
  description: 17.9 — Banking
- name: 18 — HR
  description: 18 — HR
- name: 19 — Platform & Billing
  description: 19 — Platform & Billing
- name: 20 — Reports
  description: 20 — Reports
paths:
  /accounting/ap/aging:
    get:
      operationId: get_accounting_ap_aging
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.6 — Vendors & AP
      summary: AP aging report
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **AP aging report**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: as_of
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/ar/aging:
    get:
      operationId: get_accounting_ar_aging
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.5 — Customers & AR
      summary: AR aging report
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **AR aging report**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: as_of
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/audit:
    get:
      operationId: get_accounting_audit
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.13 — Audit trail
      summary: List audit events
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **List audit events**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: entity
        in: query
        schema:
          type: string
        example: journal_entry
      - name: from
        in: query
        schema:
          type: string
        example: '2026-04-01'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/audit/{entity}/{id}:
    get:
      operationId: get_accounting_audit_entity_id
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.13 — Audit trail
      summary: Audit on a single entity
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Audit on a single entity**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: entity
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `entity` (see Laravel routes + Postman examples).
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/bank-accounts:
    get:
      operationId: get_accounting_bank_accounts
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.9 — Banking
      summary: List bank accounts
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **List bank accounts**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_accounting_bank_accounts
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.9 — Banking
      summary: Create bank account
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Create bank account**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/bank/lines/{id}/match:
    post:
      operationId: post_accounting_bank_lines_id_match
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.9 — Banking
      summary: Match statement line → JE
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Match statement line → JE**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/bank/lines/{id}/unmatch:
    post:
      operationId: post_accounting_bank_lines_id_unmatch
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.9 — Banking
      summary: Unmatch
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Unmatch**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/bank/statements/{id}/lines:
    get:
      operationId: get_accounting_bank_statements_id_lines
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.9 — Banking
      summary: List statement lines
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **List statement lines**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - name: status
        in: query
        schema:
          type: string
        example: unmatched
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/bank/statements/{id}/suggestions:
    get:
      operationId: get_accounting_bank_statements_id_suggestions
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.9 — Banking
      summary: Auto-match suggestions
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Auto-match suggestions**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/bank/{id}/statements/import:
    post:
      operationId: post_accounting_bank_id_statements_import
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.9 — Banking
      summary: Import bank statement
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Import bank statement**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/coa:
    get:
      operationId: get_accounting_coa
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: List CoA — flat | List CoA — tree
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **List CoA — flat**.


        **Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All calls require
        tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money in request/response
        follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2). Endpoint-specific:
        **List CoA — tree**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: format
        in: query
        schema:
          type: string
        example: tree
      - name: include_archived
        in: query
        schema:
          type: string
        example: 'false'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_accounting_coa
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: Create account (leaf) | Create account (parent / rollup)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Create account (leaf)**.


        **Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All calls require
        tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money in request/response
        follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2). Endpoint-specific:
        **Create account (parent / rollup)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/coa/bulk:
    post:
      operationId: post_accounting_coa_bulk
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: Bulk activity (CSV-style)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Bulk activity (CSV-style)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/coa/export:
    get:
      operationId: get_accounting_coa_export
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: Export CoA (CSV/XLSX)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Export CoA (CSV/XLSX)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: format
        in: query
        schema:
          type: string
        example: xlsx
      - name: include_balances
        in: query
        schema:
          type: string
        example: 'true'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/coa/import:
    post:
      operationId: post_accounting_coa_import
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: Import CoA (CSV/XLSX)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Import CoA (CSV/XLSX)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/coa/recompute:
    post:
      operationId: post_accounting_coa_recompute
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: Recompute parent rollups
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Recompute parent rollups**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/coa/seed:
    post:
      operationId: post_accounting_coa_seed
      tags:
      - 02 — Tenancy & Onboarding
      summary: Seed COA | Seed CoA from template
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Seed CoA from template**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/coa/templates:
    get:
      operationId: get_accounting_coa_templates
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: List CoA templates
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **List CoA templates**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/coa/templates/{code}:
    get:
      operationId: get_accounting_coa_templates_code
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: Preview template
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Preview template**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: code
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `code` (see Laravel routes + Postman examples).
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/coa/validate:
    get:
      operationId: get_accounting_coa_validate
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: CoA validation report
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **CoA validation report**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/coa/{code}:
    delete:
      operationId: delete_accounting_coa_code
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: Delete account (hard)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Delete account (hard)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: code
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `code` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    get:
      operationId: get_accounting_coa_code
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: Get account
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Get account**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: code
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `code` (see Laravel routes + Postman examples).
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    patch:
      operationId: patch_accounting_coa_code
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: Update account
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Update account**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: code
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `code` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/coa/{code}/archive:
    post:
      operationId: post_accounting_coa_code_archive
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: Archive account
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Archive account**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: code
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `code` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/coa/{code}/merge:
    post:
      operationId: post_accounting_coa_code_merge
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: Merge account into another
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Merge account into another**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: code
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `code` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/coa/{code}/reparent:
    post:
      operationId: post_accounting_coa_code_reparent
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: Re-parent account
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Re-parent account**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: code
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `code` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/coa/{code}/unarchive:
    post:
      operationId: post_accounting_coa_code_unarchive
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.1 — Chart of Accounts
      summary: Unarchive account
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Unarchive account**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: code
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `code` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/credit-notes:
    post:
      operationId: post_accounting_credit_notes
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.5 — Customers & AR
      summary: Customer credit note
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Customer credit note**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/currencies:
    get:
      operationId: get_accounting_currencies
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.12 — Settings & integrations
      summary: List currencies
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **List currencies**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/customers:
    get:
      operationId: get_accounting_customers
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.5 — Customers & AR
      summary: List customers (accounting)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **List customers (accounting)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: has_balance
        in: query
        schema:
          type: string
        example: 'true'
      - name: q
        in: query
        schema:
          type: string
        example: ali
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/customers/{id}/ledger:
    get:
      operationId: get_accounting_customers_id_ledger
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.5 — Customers & AR
      summary: Customer ledger
      description: |
        **Live AR activity (Milestone 1.K-d-0):** `BuildTenantCustomerArActivityService` — period **`from`** / **`to`** (**`Y-m-d`**, inclusive). **`opening`** / **`closing`** and **`lines[]`** from **`ar_customer_receipts`**, **`ar_customer_credit_notes`**, **`ar_customer_write_offs`**, and **`sales`** (**`SaleStatus::Posted`**, **`customer_id`** set, **`currency_code`** = tenant **`default_currency`**). **Signs:** charges (**sales**) **increase** balance (**`debit_minor`**); receipts / credit notes / write-offs **reduce** it (**`credit_minor`**). **`ledger_scope`** discloses operational subledger scope. **`data.accounting_truth`**: **`live`** / **`production`**. **`GET …/accounting/customers/{id}/statement`** JSON (**1.K-d-1**) reuses this builder for the **`as_of`** calendar month; **`GET …/accounting/customers/statement/download`** streams the **1.K-d-2** immutable PDF for the issued **`generation_id`**.
        Tenant `Authorization`; money in minor units (DECISIONS D2).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - name: from
        in: query
        schema:
          type: string
        example: '2026-04-01'
      - name: to
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: |
            Success. **`AccountingSuccessEnvelopeDataWithTruth`** — **`data.accounting_truth`** is **`live`** / **`production`** (**1.K-d-0**). **`data`** includes **`customer_id`**, **`currency_code`**, **`opening`**, **`closing`**, **`ledger_scope`**, **`lines[]`** (each line: **`date`**, **`type`**, **`source_id`**, **`source_type`**, **`reference`**, **`description`**, **`debit_minor`**, **`credit_minor`**, **`balance_minor`**, legacy **`debit`** / **`credit`** / **`balance`**, **`doc_kind`**, **`doc_no`**).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountingSuccessEnvelopeDataWithTruth'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/customers/{id}/statement:
    get:
      operationId: get_accounting_customers_id_statement
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.5 — Customers & AR
      summary: Customer statement (JSON + signed PDF link)
      description: |
        **Live AR statement numbers (Milestone 1.K-d-1):** `BuildTenantCustomerArActivityService` — same operational subledger as **`GET …/ledger`**, with period **`statement_period_from`** = first day of **`as_of`** month and **`statement_period_to`** = **`as_of`** (inclusive). Response includes **`opening_minor`**, **`closing_minor`**, **`currency_code`**, **`lines[]`**, **`ledger_scope`**, optional legacy **`opening`** / **`closing`**, and **`data.accounting_truth`**: **`live`** / **`production`** (no **`replacement_milestone`**).

        **Milestone 1.K-d-2 — live PDF:** **`IssueTenantCustomerStatementPdfService`** renders HTML (**bilingual EN/AR**, DALSEEN header **`#0E2F44`**) via **Spatie Browsershot** (or **`STATEMENT_PDF_DRIVER=fake`** in tests), stores an **immutable** file under **`storage/app/private/statements/{company_id}/{year}/{month}/statement-{company_id}-{customer_id}-{as_of_yyyymmdd}-{generation_id}.pdf`**, persists **`customer_statement_documents`**, and returns a **signed** **`download_url`** (**default `expires_in` = 604800 s = 7 days**, `CUSTOMER_STATEMENT_URL_TTL_SECONDS`). Each **`GET …/statement`** creates a **new** **`generation_id`** (new PDF). **`statement_pdf`**: **`status: live`**, **`generation_id`**, **`byte_size`**, **`immutable: true`**.

        **Statement history:** **`GET …/customers/{id}/statement-pdfs`** lists prior generations. **`GET …/statement-pdfs/{statementPdf}/download-url`** mints a **fresh** signed URL for an **existing** PDF (same bytes). **`permission:accounting.customers.view`** on JSON routes.

        Tenant `Authorization`; money in minor units (DECISIONS D2).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - name: as_of
        in: query
        schema:
          type: string
        example: '2026-04-30'
      - name: format
        in: query
        schema:
          type: string
        example: pdf
      responses:
        '200':
          description: |
            Success. **`AccountingSuccessEnvelopeDataWithTruth`** — **`data.accounting_truth`** is **`live`** / **`production`** (**1.K-d-1** JSON + **1.K-d-2** PDF). **`data`** includes **`download_url`**, **`expires_in`** (seconds, default **7 days**), **`as_of`**, **`statement_period_from`**, **`statement_period_to`**, **`opening_minor`**, **`closing_minor`**, **`currency_code`**, **`lines[]`**, **`ledger_scope`**, **`statement_pdf`** (**`live`** payload), and optional **`opening`** / **`closing`**. **`audit_logs`**: append-only row **`event=accounting.customer_statement.generated`** with **`context`** JSON (**`generation_id`**, **`customer_id`**, **`as_of`**).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountingSuccessEnvelopeDataWithTruth'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/customers/{id}/statement-pdfs:
    get:
      operationId: get_accounting_customers_id_statement_pdfs
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.5 — Customers & AR
      summary: Customer statement PDF history
      description: |
        Lists up to **100** immutable **`customer_statement_documents`** rows for the customer (**newest first**): **`generation_id`**, **`as_of`**, period bounds, **`byte_size`**, **`created_at`**. Use **`GET …/statement-pdfs/{statementPdf}/download-url`** to mint a fresh signed download link.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Success — **`data.items[]`** history rows.
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                additionalProperties: true
                properties:
                  data:
                    type: object
                    additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/customers/{id}/statement-pdfs/{statementPdf}/download-url:
    get:
      operationId: get_accounting_customers_id_statement_pdfs_statement_pdf_download_url
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.5 — Customers & AR
      summary: Renew signed download URL for existing statement PDF
      description: |
        Returns **`download_url`** + **`expires_in`** for an **existing** **`generation_id`** (**same PDF file**; new signature / expiry only).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
      - name: statementPdf
        in: path
        required: true
        schema:
          type: string
        description: 'ULID `generation_id` (same as `customer_statement_documents.id`).'
      responses:
        '200':
          description: Success — **`data.download_url`**, **`data.expires_in`**, **`data.generation_id`**.
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                additionalProperties: true
                properties:
                  data:
                    type: object
                    additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Document not found or not owned by this customer / tenant.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/customers/statement/download:
    get:
      operationId: get_accounting_customers_statement_download
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.5 — Customers & AR
      summary: Download customer statement PDF (signed URL)
      description: |
        **No bearer `Authorization`.** Access only via **temporary signed URL** from **`GET …/accounting/customers/{id}/statement`** or **`GET …/statement-pdfs/{statementPdf}/download-url`** (`generation_id`, `signature`, `expires` query params).

        **Binary response (1.K-d-2):** streams the **immutable** PDF from **`local`** disk (`storage/app/private/...`). **`audit_logs`**: **`event=accounting.customer_statement.downloaded`** with **`context`** JSON (**`generation_id`**, **`customer_id`**, **`as_of`**).
      parameters:
      - name: generation_id
        in: query
        required: true
        schema:
          type: string
        description: ULID from **`statement_pdf.generation_id`** (same as **`customer_statement_documents.id`**).
      - name: signature
        in: query
        required: true
        schema:
          type: string
      - name: expires
        in: query
        required: true
        schema:
          type: integer
      responses:
        '200':
          description: PDF bytes (`application/pdf`).
          content:
            application/pdf:
              schema:
                type: string
                format: binary
        '403':
          description: Invalid or expired signature.
        '404':
          description: Unknown token or missing file.
  /accounting/customers/{id}/write-off:
    post:
      operationId: post_accounting_customers_id_write_off
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.5 — Customers & AR
      summary: Apply credit / write-off
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Apply credit / write-off**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/dimensions:
    get:
      operationId: get_accounting_dimensions
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.10 — Dimensions (cost centers, projects)
      summary: List dimension types
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **List dimension types**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/dimensions/{code}:
    patch:
      operationId: patch_accounting_dimensions_code
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.10 — Dimensions (cost centers, projects)
      summary: Update dimension settings
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Update dimension settings**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: code
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `code` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/dimensions/{code}/values:
    get:
      operationId: get_accounting_dimensions_code_values
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.10 — Dimensions (cost centers, projects)
      summary: List dimension values
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **List dimension values**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: code
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `code` (see Laravel routes + Postman examples).
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_accounting_dimensions_code_values
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.10 — Dimensions (cost centers, projects)
      summary: Create dimension value
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Create dimension value**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: code
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `code` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/fiscal-calendar:
    get:
      operationId: get_accounting_fiscal_calendar
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.2 — Fiscal calendar & periods
      summary: Get fiscal calendar
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Get fiscal calendar**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    patch:
      operationId: patch_accounting_fiscal_calendar
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.2 — Fiscal calendar & periods
      summary: Update fiscal calendar
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Update fiscal calendar**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/fx-rates:
    get:
      operationId: get_accounting_fx_rates
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.12 — Settings & integrations
      summary: FX rates
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **FX rates**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: from
        in: query
        schema:
          type: string
        example: '2026-04-01'
      - name: pair
        in: query
        schema:
          type: string
        example: USD/SAR
      - name: to
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_accounting_fx_rates
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.12 — Settings & integrations
      summary: Set FX rate (manual)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Set FX rate (manual)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/gl:
    get:
      operationId: get_accounting_gl
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.7 — Journal & GL
      summary: GL — single account
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **GL — single account**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: account_code
        in: query
        schema:
          type: string
        example: '1101'
      - name: dimensions[branch_id]
        in: query
        schema:
          type: string
        example: '1'
      - name: from
        in: query
        schema:
          type: string
        example: '2026-04-01'
      - name: to
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/gl/export:
    get:
      operationId: get_accounting_gl_export
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.7 — Journal & GL
      summary: GL — bulk export
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **GL — bulk export**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: format
        in: query
        schema:
          type: string
        example: xlsx
      - name: from
        in: query
        schema:
          type: string
        example: '2026-04-01'
      - name: to
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/journal-entries:
    get:
      operationId: get_accounting_journal_entries
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.7 — Journal & GL
      summary: List journal entries
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **List journal entries**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: from
        in: query
        schema:
          type: string
        example: '2026-04-01'
      - name: kind
        in: query
        schema:
          type: string
        example: all
      - name: to
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_accounting_journal_entries
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.7 — Journal & GL
      summary: Manual journal entry (post)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Manual journal entry (post)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/journal-entries/{id}:
    get:
      operationId: get_accounting_journal_entries_id
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.7 — Journal & GL
      summary: Get journal entry
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Get journal entry**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/journal-entries/{id}/adjust:
    post:
      operationId: post_accounting_journal_entries_id_adjust
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.7 — Journal & GL
      summary: Adjust journal entry (manager-only)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Adjust journal entry (manager-only)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/journal-entries/{id}/reverse:
    post:
      operationId: post_accounting_journal_entries_id_reverse
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.7 — Journal & GL
      summary: Reverse journal entry
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Reverse journal entry**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/opening-balances:
    get:
      operationId: get_accounting_opening_balances
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.3 — Opening balances
      summary: Get opening balances
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Get opening balances**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: as_of
        in: query
        schema:
          type: string
        example: '2026-01-01'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_accounting_opening_balances
      tags:
      - 02 — Tenancy & Onboarding
      summary: Opening balances | Set/replace opening balances
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Set/replace opening balances**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/opening-balances/import:
    post:
      operationId: post_accounting_opening_balances_import
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.3 — Opening balances
      summary: Import opening trial balance (CSV/XLSX)
      description: |
        **Live import (Milestone 1.K-e):** Fetches **`file_url`** from the same **URL allowlist** + HTTP limits as **`POST …/accounting/coa/import`** (`config/coa_import.php`; **`coa-import.test`** in **`testing`**). Parses **CSV** or minimal **XLSX** (`CoaMinimalXlsxReader`). **`header_map.code`**, **`header_map.debit`**, **`header_map.credit`** are **first-row header labels** (exact match after trim) mapping to **`account_code`** and **minor-unit** **`debit`** / **`credit`**.

        **Validation:** at least **two** data rows; each row **non-negative** integer minors; **not** both debit and credit positive; **balanced** totals; **no** posted **`OB-{as_of}`** journal yet for the tenant (**422** **`OPENING_BALANCE_IMPORT_ALREADY_POSTED`** otherwise). Unknown / non-postable accounts return **422** **`VALIDATION_FAILED`** (same as **`POST …/opening-balances`**). Malformed file / bad numbers / imbalance → **422** **`COA_IMPORT_INVALID_FILE`** (or **`COA_IMPORT_FETCH_FAILED`** / **`COA_IMPORT_URL_NOT_ALLOWED`**).

        **Post:** synchronous **`PostOpeningBalancesService`** → **`journal_entry_id`**, **`posted_row_count`**, **`total_debit`**, **`total_credit`**, **`will_post`** (= line count). **`data.accounting_truth`**: **`live`** / **`production`** (no **`replacement_milestone`**). **`Idempotency-Key`** required; **202 Accepted** (cached replay for **2xx** idempotency store).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '202':
          description: |
            Accepted. **`AccountingSuccessEnvelopeDataWithTruth`** — **`data.accounting_truth`** is **`live`** / **`production`** (**1.K-e**). **`data`** includes **`journal_entry_id`**, **`posted_row_count`**, **`total_debit`**, **`total_credit`**, **`will_post`**.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountingSuccessEnvelopeDataWithTruth'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: |
            **`COA_IMPORT_*`**, **`OPENING_BALANCE_IMPORT_ALREADY_POSTED`**, or **`VALIDATION_FAILED`** (per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/payments:
    post:
      operationId: post_accounting_payments
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.6 — Vendors & AP
      summary: Pay vendor (Pay)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Pay vendor (Pay)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/periods:
    get:
      operationId: get_accounting_periods
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.2 — Fiscal calendar & periods
      summary: List periods
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **List periods**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: fy
        in: query
        schema:
          type: string
        example: '2026'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/periods/{key}/checks:
    get:
      operationId: get_accounting_periods_key_checks
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.2 — Fiscal calendar & periods
      summary: Period readiness check
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Period readiness check**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: key
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `key` (see Laravel routes + Postman examples).
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/periods/{key}/close:
    post:
      operationId: post_accounting_periods_key_close
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.2 — Fiscal calendar & periods
      summary: Close period
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Close period**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: key
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `key` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/periods/{key}/reopen:
    post:
      operationId: post_accounting_periods_key_reopen
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.2 — Fiscal calendar & periods
      summary: Reopen period
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Reopen period**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: key
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `key` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/posting-bridges:
    get:
      operationId: get_accounting_posting_bridges
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.12 — Settings & integrations
      summary: Posting bridges status
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Posting bridges status**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/receipts:
    post:
      operationId: post_accounting_receipts
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.5 — Customers & AR
      summary: Receive customer payment (Collect)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Receive customer payment (Collect)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/recurring-je:
    get:
      operationId: get_accounting_recurring_je
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.7 — Journal & GL
      summary: Recurring JE list
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Recurring JE list**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_accounting_recurring_je
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.7 — Journal & GL
      summary: Create recurring JE
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Create recurring JE**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/reports/bs:
    get:
      operationId: get_accounting_reports_bs
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.11 — Financial reports
      summary: Balance Sheet
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Balance Sheet**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: as_of
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: |
            Success. **`data.accounting_truth`** (**Milestone 1.K-b-3**): `data_source=live`, `sla_status=production`; **`replacement_milestone`** omitted.
            **`data`** is GL-backed cumulative through **`as_of`** (`entry_date <= as_of`, posted **`journal_lines`** only): **`assets`**, **`liabilities`**, **`equity`** (includes **net income** from cumulative revenue minus expense through **`as_of`** so **assets = liabilities + equity** when the ledger balances), **`equity_accounts`**, **`net_income_in_equity`**, **`liabilities_plus_equity`**, **`balanced`**, and **`sections[]`** (per **`asset` / `liability` / `equity`** CoA rows with **`account_id`**, **`account_code`**, names, **`debit`/`credit`/`net`** in minor units).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountingSuccessEnvelopeDataWithTruth'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/reports/cashflow:
    get:
      operationId: get_accounting_reports_cashflow
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.11 — Financial reports
      summary: Cashflow statement
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Cashflow statement**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: method
        in: query
        schema:
          type: string
        example: indirect
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: |
            Success. **Stage 6.C-2 / 6.F:** GL-backed **direct-on-cash** movement for the calendar **`period`** (`YYYY-MM`) on accounts with **`is_cash_equivalent`**, bucketed by **`cash_flow_bucket`** (`operating` \| `investing` \| `financing` \| `unclassified`). Minor units in **`operating`**, **`investing`**, **`financing`**, **`unclassified`**, **`net_change`**. **`coverage`** explains when no cash accounts are flagged. **`method`** is echoed; indirect-method worksheets are **not** separate from this v1 aggregate. **`data.accounting_truth`:** `data_source=live`, `sla_status=production`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountingSuccessEnvelopeDataWithTruth'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/reports/drill:
    get:
      operationId: get_accounting_reports_drill
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.11 — Financial reports
      summary: Account drill-down
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Account drill-down**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: account_code
        in: query
        schema:
          type: string
        example: '4000'
      - name: from
        in: query
        schema:
          type: string
        example: '2026-04-01'
      - name: to
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: |
            Success. **`data.accounting_truth`** (**Milestone 1.K-b-2**): `data_source=live`, `sla_status=production`; **`replacement_milestone`** omitted.
            **`data`** is GL-backed from posted **`journal_lines`** for the account and date range (same logic as `GET /accounting/gl` via **`ShowTenantGlAccountStatementService`**): **`opening`**, **`closing`**, **`total`** (net change `closing - opening`), **`lines[]`** with **`je_id`**, **`date`**, **`doc_no`**, **`debit`**, **`credit`**, **`balance`** (running, minor units), plus account metadata (**`name_en`**, **`name_ar`**, **`account_type`**).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountingSuccessEnvelopeDataWithTruth'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Unknown **`account_code`** for the tenant (no matching chart-of-accounts row).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/reports/equity:
    get:
      operationId: get_accounting_reports_equity
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.11 — Financial reports
      summary: Statement of changes in equity
      description: |
        **Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, and reports. Tenant `Authorization`; **`permission:accounting.reports.view`** (Spatie). Money in minor units (DECISIONS D2).
        **EN:** GL-backed reconciliation of **total equity** between **`from`** and **`to`** (workflow: accountant / owner reviews period equity roll-forward after month-end close).
        **AR:** تسوية **إجمالي حقوق الملكية** من دفتر الأستاذ بين **`from`** و **`to`** (مسار العمل: مراجعة المحاسب بعد إقفال الشهر).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: dimensions[branch_id]
        in: query
        schema:
          type: string
        example: '1'
      - name: from
        in: query
        schema:
          type: string
        example: '2026-01-01'
      - name: to
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: |
            Success. **`data.accounting_truth`** (**Milestone 1.K-b-5**): `data_source=live`, `sla_status=production`; **`replacement_milestone`** omitted.
            **Thin v1 equity movement:** **`opening_equity`** = same **total equity** as **`GET /accounting/reports/bs?as_of=(from − 1 day)`** (equity-type CoA net **+** cumulative revenue minus expense through that date, posted lines only). **`closing`** = same as **`GET …/bs?as_of=to`**. **`retained`** = **`closing − opening_equity − dividends − other`** (reconciles the period). **`dividends`** and **`other`** are **`0`** until CoA subtypes map distributions / OCI (**documented limitation**). Optional **`dimensions[branch_id]`**: strict **`journal_lines.branch_id`** match; **`null`** branch lines excluded when set (same as P&L).
            **Workflow note:** Call once after P&L / BS review to confirm **`opening_equity` + `retained` = `closing`** without extra round-trips.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountingSuccessEnvelopeDataWithTruth'
              examples:
                equity_roll_forward:
                  summary: Period roll-forward (EN) / تسوية الفترة (AR)
                  value:
                    data:
                      from: '2026-04-01'
                      to: '2026-04-30'
                      opening_equity: 1000000
                      retained: 50000
                      dividends: 0
                      other: 0
                      closing: 1050000
                      accounting_truth:
                        data_source: live
                        sla_status: production
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/reports/pl:
    get:
      operationId: get_accounting_reports_pl
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.11 — Financial reports
      summary: P&L
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **P&L**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: dimensions[branch_id]
        in: query
        schema:
          type: string
        example: '1'
      - name: from
        in: query
        schema:
          type: string
        example: '2026-04-01'
      - name: to
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: |
            Success. **`data.accounting_truth`** (**Milestone 1.K-b-4**): `data_source=live`, `sla_status=production`; **`replacement_milestone`** omitted.
            **Thin v1 P&L:** posted **`journal_lines`** only; **`from <= entry_date <= to`** inclusive; **`revenue`** = Σ **`credit − debit`** on **`revenue`** accounts; **`cogs = 0`** (no CoA split yet — document to clients); **`gross_profit = revenue − cogs`**; **`opex`** = Σ **`debit − credit`** on **`expense`** accounts; **`ebitda = gross_profit − opex`**; **`other = 0`**; **`net = gross_profit − opex − other`**. **Asset / liability / equity** lines excluded from P&L totals. Optional **`dimensions[branch_id]`**: non-empty → filter **`journal_lines.branch_id`** (strict match; **`null`** branch lines excluded — same as **`GET /accounting/gl`**). **`sections`**: **`revenue`**, **`cogs`** (empty **`rows`**, **`section_total: 0`**), **`opex`**, **`other`** (empty **`rows`**, **`section_total: 0`**); minor units per D2.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountingSuccessEnvelopeDataWithTruth'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/reports/trial-balance:
    get:
      operationId: get_accounting_reports_trial_balance
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.11 — Financial reports
      summary: Trial balance
      description: |
        **GL-backed cumulative trial balance (**1.K-b-1**):** Posted **`journal_entries`** / **`journal_lines`** through **`as_of`** (inclusive); **`data.accounting_truth`**: `data_source=live`, `sla_status=production` (no `replacement_milestone`). Rows: accounts with activity; **`totals.debit`** / **`totals.credit`** in minor units; **`totals.balanced`** when they match. **`cashflow`** remains stub-labeled (**Stage 6**); other GL-backed reports are live per milestones.
        Tenant `Authorization`; money per DECISIONS D2.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: as_of
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: |
            Success. **`AccountingSuccessEnvelopeDataWithTruth`** — **`data.accounting_truth`** is **`live`** / **`production`** for GL-backed trial balance (**1.K-b-1**).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountingSuccessEnvelopeDataWithTruth'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/settings:
    get:
      operationId: get_accounting_settings
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.12 — Settings & integrations
      summary: Get accounting settings
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Get accounting settings**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    patch:
      operationId: patch_accounting_settings
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.12 — Settings & integrations
      summary: Update accounting settings
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Update accounting settings**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/vat:
    get:
      operationId: get_accounting_vat
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.4 — Tax · VAT · ZATCA
      summary: Get VAT view
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Get VAT view**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-Q2
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/vat-codes:
    get:
      operationId: get_accounting_vat_codes
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.4 — Tax · VAT · ZATCA
      summary: List VAT codes
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **List VAT codes**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_accounting_vat_codes
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.4 — Tax · VAT · ZATCA
      summary: Create VAT code
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Create VAT code**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/vat/file:
    post:
      operationId: post_accounting_vat_file
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.4 — Tax · VAT · ZATCA
      summary: File VAT return (ZATCA)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **File VAT return (ZATCA)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/vendor-debit-notes:
    post:
      operationId: post_accounting_vendor_debit_notes
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.6 — Vendors & AP
      summary: Debit note (vendor)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Debit note (vendor)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/vendors:
    get:
      operationId: get_accounting_vendors
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.6 — Vendors & AP
      summary: List vendors (accounting)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **List vendors (accounting)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: q
        in: query
        schema:
          type: string
        example: almarai
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/vendors/{id}/ledger:
    get:
      operationId: get_accounting_vendors_id_ledger
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.6 — Vendors & AP
      summary: Vendor ledger
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Vendor ledger**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - name: from
        in: query
        schema:
          type: string
        example: '2026-04-01'
      - name: to
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/voucher-types:
    get:
      operationId: get_accounting_voucher_types
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.8 — Vouchers (CR / CP / JV)
      summary: List voucher types
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **List voucher types**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/vouchers/cp:
    post:
      operationId: post_accounting_vouchers_cp
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.8 — Vouchers (CR / CP / JV)
      summary: Create cash payment (CP)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Create cash payment (CP)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/vouchers/cr:
    post:
      operationId: post_accounting_vouchers_cr
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.8 — Vouchers (CR / CP / JV)
      summary: Create cash receipt (CR)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Create cash receipt (CR)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/year-end/close:
    post:
      operationId: post_accounting_year_end_close
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.2 — Fiscal calendar & periods
      summary: Year-end close (rollover)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Year-end close (rollover)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/zatca/invoices/{sale_id}:
    get:
      operationId: get_accounting_zatca_invoices_sale_id
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.4 — Tax · VAT · ZATCA
      summary: ZATCA invoice clearance status
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **ZATCA invoice clearance status**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: sale_id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `sale_id` (see Laravel routes + Postman examples).
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /accounting/zatca/queue:
    get:
      operationId: get_accounting_zatca_queue
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.4 — Tax · VAT · ZATCA
      summary: ZATCA submission queue (B2B)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **ZATCA submission queue (B2B)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: status
        in: query
        schema:
          type: string
        example: pending
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /aggregator/inbox:
    get:
      operationId: get_aggregator_inbox
      tags:
      - 15 — Dine / Delivery & Aggregators
      summary: Aggregator inbox
      description: |
        Generated from Postman — `Aggregator inbox` (`docs/postman/DALSEEN.postman_collection.json`).
        **Branch scoping:** `perm:dine.aggregator.inbox.view,branch` — `X-Branch-Id` required for multi-branch users (422 if omitted).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/BranchId'
      - name: status
        in: query
        schema:
          type: string
        example: pending
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Missing `X-Branch-Id` when required (multi-branch user).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /aggregator/{id}/accept:
    post:
      operationId: post_aggregator_id_accept
      tags:
      - 15 — Dine / Delivery & Aggregators
      summary: Accept aggregator order
      description: Generated from Postman — `Accept aggregator order` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /aggregator/{id}/reject:
    post:
      operationId: post_aggregator_id_reject
      tags:
      - 15 — Dine / Delivery & Aggregators
      summary: Reject aggregator order
      description: Generated from Postman — `Reject aggregator order` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /auth/login:
    post:
      operationId: post_auth_login
      tags:
      - 01 — Auth & Identity
      summary: Login (tenant)
      description: '`POST /auth/login` — Tenant Sanctum login with `company_slug`, `email`, and `password`. Returns `data.token`
        (plain-text bearer, not JWT), `mfa_required`, `user`, `company`, and `branches`. Copy `data.token` into the `token`
        environment variable. See saved examples for **401**, **422**, and **404** tenant errors.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security: []
  /auth/logout:
    post:
      operationId: post_auth_logout
      tags:
      - 01 — Auth & Identity
      summary: Logout
      description: '`POST /auth/logout` — Revokes the current Sanctum token. Returns **204** with empty body on success.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /auth/mfa:
    post:
      operationId: post_auth_mfa
      tags:
      - 01 — Auth & Identity
      summary: MFA verify
      description: '`POST /auth/mfa` — Complete MFA after login when `mfa_required` is true. Uses bearer token with `mfa-pending`
        ability until verified.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /bank/reconcile:
    post:
      operationId: post_bank_reconcile
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.9 — Banking
      summary: Bank reconcile (close batch)
      description: |
        **Live GL-aware (Milestone 1.K-c):** period **`statement_balance_minor`** = Σ **`bank_statement_lines.amount_minor`** for the bank account with **`occurred_on`** in **`[period_start, period_end]`** (calendar month from **`period`** `YYYY-MM`). **`book_balance_minor`** = cumulative **posted** GL on the bank’s linked **`chart_of_accounts`** row (**`debit_minor − credit_minor`**, `journal_entries.entry_date <= period_end`, same tenant). **`variance_minor` = `statement_balance_minor` − `book_balance_minor`** (sign locked). **`matched`** / **`unmatched`** (and **`matched_count`** / **`unmatched_count`**) count statement lines in that same window using **`matched_journal_line_id`**. **`reconciliation_status`** is **`reconciled`** only when **`variance_minor === 0`** and **`unmatched === 0`**; otherwise **`open`**; **`reconciled_at`** is set only when reconciled. **`journal_entry_id`** is always **`null`** — variance **JE posting is deferred** (no `JournalEntryPoster`). **`closing_balance`** is accepted for validation compatibility but **not authoritative** for v1 math; when sent, echoed as **`closing_balance_input`**. **`data.accounting_truth`**: **`live`** / **`production`** (no **`replacement_milestone`**).
        Tenant `Authorization`; `Idempotency-Key` required. Money rules per DECISIONS D2.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: |
            Success. **`AccountingSuccessEnvelopeDataWithTruth`** — **`data.accounting_truth`** is **`live`** / **`production`** (**1.K-c**). **`data`** includes **`period_start`**, **`period_end`**, **`statement_balance_minor`**, **`book_balance_minor`**, **`variance_minor`**, **`matched`**, **`unmatched`**, **`matched_count`**, **`unmatched_count`**, **`reconciliation_status`**, **`reconciled_at`**, **`journal_entry_id`** (**`null`**); optional **`closing_balance_input`** when **`closing_balance`** was sent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccountingSuccessEnvelopeDataWithTruth'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /branches:
    post:
      operationId: post_branches
      tags:
      - 02 — Tenancy & Onboarding
      summary: Create branch
      description: '`POST /branches` — Creates a branch for the tenant (`audit.write`; no idempotency middleware). **201** returns `data.id` and `data.name`. When `LIMITS_ENFORCED` is true and the effective plan cap for **`max_branches`** would be exceeded, responds **402** with `error.code` **`LIMIT_REACHED`** (`SubscriptionLimitReachedResponse`).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '201':
          description: Created (`data` with `id`, `name` per implementation).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: Subscription / plan limit — branch quota (`error.code` = `LIMIT_REACHED`; typically `fields.limit_type` = `max_branches`). Not used for inventory prerequisite **402** (those use other `error.code` values).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubscriptionLimitReachedResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /carts:
    post:
      operationId: post_carts
      tags:
      - 05 — Sales / POS
      summary: Hold cart
      description: '`POST /carts/hold` — Park an in-progress cart for later resume.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - $ref: '#/components/parameters/BranchId'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /carts/{id}:
    patch:
      operationId: patch_carts_id
      tags:
      - 05 — Sales / POS
      summary: Resume cart
      description: |
        `PATCH /carts/{id}` — Resume a held cart (`perm:pos.carts.resume,branch`).
        **Branch scoping:** `X-Branch-Id` required for multi-branch users (422 if omitted).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/BranchId'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /catalog/attributes:
    get:
      operationId: get_catalog_attributes
      tags:
      - 03 — Catalog
      summary: List attributes
      description: Generated from Postman — `List attributes` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_catalog_attributes
      tags:
      - 03 — Catalog
      summary: Create attribute
      description: Generated from Postman — `Create attribute` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /catalog/brands:
    get:
      operationId: get_catalog_brands
      tags:
      - 03 — Catalog
      summary: List brands
      description: Generated from Postman — `List brands` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_catalog_brands
      tags:
      - 03 — Catalog
      summary: Create brand
      description: Generated from Postman — `Create brand` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /catalog/categories:
    delete:
      operationId: delete_catalog_categories
      tags:
      - 03 — Catalog
      summary: Bulk delete / archive categories
      description: Generated from Postman — `Bulk delete / archive categories` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - name: ids
        in: query
        schema:
          type: string
        example: 4,7,11
      - name: mode
        in: query
        schema:
          type: string
        example: archive
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    get:
      operationId: get_catalog_categories
      tags:
      - 03 — Catalog
      summary: List categories
      description: Generated from Postman — `List categories` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: parent_id
        in: query
        schema:
          type: string
        example: 'null'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    patch:
      operationId: patch_catalog_categories
      tags:
      - 03 — Catalog
      summary: Bulk update categories
      description: Generated from Postman — `Bulk update categories` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_catalog_categories
      tags:
      - 03 — Catalog
      summary: Create category
      description: Generated from Postman — `Create category` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /catalog/categories/{id}:
    delete:
      operationId: delete_catalog_categories_id
      tags:
      - 03 — Catalog
      summary: Delete category
      description: Generated from Postman — `Delete category` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    patch:
      operationId: patch_catalog_categories_id
      tags:
      - 03 — Catalog
      summary: Update category
      description: Generated from Postman — `Update category` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /catalog/search:
    get:
      operationId: get_catalog_search
      tags:
      - 03 — Catalog
      summary: Search products
      description: Generated from Postman — `Search products` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: category_id
        in: query
        schema:
          type: string
        example: '5'
      - name: page
        in: query
        schema:
          type: string
        example: '1'
      - name: q
        in: query
        schema:
          type: string
        example: latte
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /combos:
    get:
      operationId: get_combos
      tags:
      - 13 — Dine / Menus, Modifiers, Combos
      summary: List combos
      description: Generated from Postman — `List combos` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_combos
      tags:
      - 13 — Dine / Menus, Modifiers, Combos
      summary: Create combo
      description: Generated from Postman — `Create combo` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /companies/{id}:
    patch:
      operationId: patch_companies_id
      tags:
      - 02 — Tenancy & Onboarding
      summary: Update company profile
      description: 'Generated from Postman — `Update company profile` (`docs/postman/DALSEEN.postman_collection.json`).
        Optional **`default_return_window_days`** (integer 1–9999): tenant default return window when `products.return_window_days` is null;
        falls back to env `RETURNS_DEFAULT_WINDOW_DAYS` / `config/returns.php` when unset.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /cost-layers:
    get:
      operationId: get_cost_layers
      tags:
      - 04 — Inventory
      summary: Cost layers
      description: |
        Generated from Postman — `Cost layers` (`docs/postman/DALSEEN.postman_collection.json`).
        **Branch scoping:** `perm:inventory.cost_layers.view,branch` — `X-Branch-Id` required for multi-branch users (422 if omitted); single-branch users may omit it.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/BranchId'
      - name: product_id
        in: query
        schema:
          type: string
        example: '101'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Missing or invalid `X-Branch-Id` when required (multi-branch user).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /couriers/{id}/close-shift:
    post:
      operationId: post_couriers_id_close_shift
      tags:
      - 15 — Dine / Delivery & Aggregators
      summary: Close rider shift
      description: Generated from Postman — `Close rider shift` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /customers:
    get:
      operationId: get_customers
      tags:
      - 07 — Customers, Loyalty, Gift Cards
      summary: List customers
      description: Generated from Postman — `List customers` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: q
        in: query
        schema:
          type: string
        example: ali
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_customers
      tags:
      - 07 — Customers, Loyalty, Gift Cards
      summary: Create customer
      description: Generated from Postman — `Create customer` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /customers/credit-holds:
    get:
      operationId: get_customers_credit_holds
      tags:
      - 07 — Customers, Loyalty, Gift Cards
      summary: B2B credit holds queue
      description: Generated from Postman — `B2B credit holds queue` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /customers/{id}:
    patch:
      operationId: patch_customers_id
      tags:
      - 07 — Customers, Loyalty, Gift Cards
      summary: Update customer
      description: Generated from Postman — `Update customer` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /dashboard/zero-friction:
    get:
      operationId: get_dashboard_zero_friction
      tags:
      - 20 — Reports
      summary: Dashboard — Zero‑Friction snapshot
      description: |
        **English:** Compact KPIs for unknown‑SKU workflow and backfill health (tenant scoped).
        **Arabic:** مؤشرات لوحة التحكم لوضع بلا احتكاك.
        **Permission:** `reports.view` (and related catalog/inventory permissions per UI).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /debit-notes:
    post:
      operationId: post_debit_notes
      tags:
      - 08 — Suppliers & Purchasing
      summary: Debit note
      description: Generated from Postman — `Debit note` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /delivery/assign:
    post:
      operationId: post_delivery_assign
      tags:
      - 15 — Dine / Delivery & Aggregators
      summary: Assign courier
      description: Generated from Postman — `Assign courier` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /delivery/queue:
    get:
      operationId: get_delivery_queue
      tags:
      - 15 — Dine / Delivery & Aggregators
      summary: Delivery queue
      description: |
        Generated from Postman — `Delivery queue` (`docs/postman/DALSEEN.postman_collection.json`).
        **Branch scoping:** `perm:dine.delivery.queue.view,branch` — `X-Branch-Id` required for multi-branch users (422 if omitted).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/BranchId'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Missing `X-Branch-Id` when required (multi-branch user).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /delivery/stack:
    post:
      operationId: post_delivery_stack
      tags:
      - 15 — Dine / Delivery & Aggregators
      summary: Stack run
      description: Generated from Postman — `Stack run` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /delivery/{id}/handoff:
    post:
      operationId: post_delivery_id_handoff
      tags:
      - 15 — Dine / Delivery & Aggregators
      summary: Driver handoff
      description: Generated from Postman — `Driver handoff` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /delivery/{id}/pod:
    post:
      operationId: post_delivery_id_pod
      tags:
      - 15 — Dine / Delivery & Aggregators
      summary: Capture POD
      description: Generated from Postman — `Capture POD` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /ecom/orders:
    post:
      operationId: post_ecom_orders
      tags:
      - 10 — E-com & Marketplaces
      summary: Place e-com order
      description: Generated from Postman — `Place e-com order` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /ecom/orders/{id}/confirm:
    post:
      operationId: post_ecom_orders_id_confirm
      tags:
      - 10 — E-com & Marketplaces
      summary: Confirm e-com order (received → confirmed)
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /ecom/orders/{id}/prepare:
    post:
      operationId: post_ecom_orders_id_prepare
      tags:
      - 10 — E-com & Marketplaces
      summary: Prepare e-com order (confirmed → prepared)
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /ecom/orders/{id}/fulfill:
    post:
      operationId: post_ecom_orders_id_fulfill
      tags:
      - 10 — E-com & Marketplaces
      summary: Fulfill e-com order
      description: Generated from Postman — `Fulfill e-com order` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /ecom/orders/{id}/deliver:
    post:
      operationId: post_ecom_orders_id_deliver
      tags:
      - 10 — E-com & Marketplaces
      summary: Mark e-com order delivered (shipped → delivered)
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /ecom/orders/{id}/complete:
    post:
      operationId: post_ecom_orders_id_complete
      tags:
      - 10 — E-com & Marketplaces
      summary: Complete e-com order (delivered → completed)
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /ecom/orders/{id}/return:
    post:
      operationId: post_ecom_orders_id_return
      tags:
      - 10 — E-com & Marketplaces
      summary: Return e-com order
      description: Generated from Postman — `Return e-com order` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /workflows/ecom-orders:
    get:
      operationId: get_workflows_ecom_orders
      tags:
      - 10 — E-com & Marketplaces
      summary: E-com orders workflow aggregate (§1.8)
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /workflows/finance-period-close:
    get:
      operationId: get_workflows_finance_period_close
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      summary: Finance period-close workflow aggregate (§1.8)
      description: |
        **Stage 6.C-4:** Open fiscal period count and ZATCA pending/submitted sale counts with suggested next API paths. Requires `accounting.reports.view`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /workflows/ecom-fulfillment:
    get:
      operationId: get_workflows_ecom_fulfillment
      tags:
      - 10 — E-com & Marketplaces
      summary: E-com fulfillment workflow aggregate (§1.8)
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /feature-flags:
    get:
      operationId: get_feature_flags
      tags:
      - 19 — Platform & Billing
      summary: Feature flags
      description: Generated from Postman — `Feature flags` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /feature-flags/{key}:
    patch:
      operationId: patch_feature_flags_key
      tags:
      - 19 — Platform & Billing
      summary: Update feature flag
      description: Generated from Postman — `Update feature flag` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: key
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `key` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /frictionless-events:
    get:
      operationId: get_frictionless_events
      tags:
      - 04 — Inventory
      summary: Frictionless events
      description: Generated from Postman — `Frictionless events` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: status
        in: query
        schema:
          type: string
        example: open
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /gift-cards:
    post:
      operationId: post_gift_cards
      tags:
      - 07 — Customers, Loyalty, Gift Cards
      summary: Issue gift card
      description: Generated from Postman — `Issue gift card` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /gift-cards/{code}/redeem:
    post:
      operationId: post_gift_cards_code_redeem
      tags:
      - 07 — Customers, Loyalty, Gift Cards
      summary: Redeem gift card
      description: Generated from Postman — `Redeem gift card` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: code
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `code` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /grn:
    post:
      operationId: post_grn
      tags:
      - 04 — Inventory
      summary: Goods Receipt (GRN) — strict always
      description: Generated from Postman — `Goods Receipt (GRN) — strict always` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - $ref: '#/components/parameters/BranchId'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/1-1s:
    get:
      operationId: get_hr_1_1s
      tags:
      - 18 — HR
      summary: 1-on-1s
      description: Generated from Postman — `1-on-1s` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/assets:
    get:
      operationId: get_hr_assets
      tags:
      - 18 — HR
      summary: Assets
      description: Generated from Postman — `Assets` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/candidates:
    get:
      operationId: get_hr_candidates
      tags:
      - 18 — HR
      summary: Candidates
      description: Generated from Postman — `Candidates` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: job_id
        in: query
        schema:
          type: string
        example: '1'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/contracts:
    post:
      operationId: post_hr_contracts
      tags:
      - 18 — HR
      summary: Create contract
      description: Generated from Postman — `Create contract` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/courses:
    get:
      operationId: get_hr_courses
      tags:
      - 18 — HR
      summary: Courses
      description: Generated from Postman — `Courses` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/employees:
    get:
      operationId: get_hr_employees
      tags:
      - 18 — HR
      summary: List employees
      description: Generated from Postman — `List employees` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_hr_employees
      tags:
      - 18 — HR
      summary: Create employee
      description: Generated from Postman — `Create employee` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/enrollments:
    post:
      operationId: post_hr_enrollments
      tags:
      - 18 — HR
      summary: Enrollments
      description: Generated from Postman — `Enrollments` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/expenses:
    post:
      operationId: post_hr_expenses
      tags:
      - 18 — HR
      summary: Expenses
      description: Generated from Postman — `Expenses` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/goals:
    get:
      operationId: get_hr_goals
      tags:
      - 18 — HR
      summary: Goals
      description: Generated from Postman — `Goals` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/jobs:
    get:
      operationId: get_hr_jobs
      tags:
      - 18 — HR
      summary: List jobs (ATS)
      description: Generated from Postman — `List jobs (ATS)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/loans:
    post:
      operationId: post_hr_loans
      tags:
      - 18 — HR
      summary: Loans
      description: Generated from Postman — `Loans` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/payroll/runs:
    post:
      operationId: post_hr_payroll_runs
      tags:
      - 18 — HR
      summary: Payroll run
      description: Generated from Postman — `Payroll run` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/policies:
    get:
      operationId: get_hr_policies
      tags:
      - 18 — HR
      summary: Policies
      description: Generated from Postman — `Policies` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/reviews:
    get:
      operationId: get_hr_reviews
      tags:
      - 18 — HR
      summary: Reviews
      description: Generated from Postman — `Reviews` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /hr/tickets:
    post:
      operationId: post_hr_tickets
      tags:
      - 18 — HR
      summary: Helpdesk tickets
      description: Generated from Postman — `Helpdesk tickets` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /inventory-backfills:
    get:
      operationId: get_inventory_backfills
      tags:
      - 04 — Inventory
      summary: Inventory backfills — list
      description: |
        **English:** Lists Scenario‑2 backfill receipts (inbound stock recorded at system time).
        **Arabic:** قائمة تعبئات المخزون الرجعية (سيناريو 2).
        **Permission:** `inventory.backfills.view`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_inventory_backfills
      tags:
      - 04 — Inventory
      summary: Inventory backfills — create
      description: |
        **English:** Records inbound stock + cost layer for an existing variant (unknown product at POS is **not** required).
        Optional `pending_product_id` enables pending‑linked variance warnings. `force=true` bypasses warnings (audit +
        `inventory_receipts.variance_warnings`).
        **Arabic:** تسجيل وارد مخزون وتكلفة؛ معرف `pending_product_id` يفعّل فحوصات الكمية/التكلفة مقابل المبيعات المعلقة.
        **Permission:** `inventory.backfills.create`. **Idempotency:** `Idempotency-Key` required.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - name: force
        in: query
        required: false
        schema:
          type: boolean
          default: false
        description: 'EN: Record despite variance warnings. AR: التسجيل رغم التحذيرات.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - branch_id
              - variant_id
              - quantity
              - unit_cost_minor
              properties:
                branch_id:
                  $ref: '#/components/schemas/ResourceId'
                variant_id:
                  $ref: '#/components/schemas/ResourceId'
                quantity:
                  type: number
                unit_cost_minor:
                  type: integer
                supplier_invoice_date:
                  type: string
                  format: date
                supplier_invoice_number:
                  type: string
                supplier_id:
                  $ref: '#/components/schemas/ResourceId'
                pending_product_id:
                  $ref: '#/components/schemas/ResourceId'
                  description: 'EN: Optional link for ZF variance context. AR: اختياري لربط سيناريو المنتجات المعلقة.'
            examples:
              happy_path:
                summary: EN happy / AR مسار ناجح
                value:
                  branch_id: 01HQXBT7N8FK2WVMC9YE3DRPJ5
                  variant_id: 01HQXBT7N8FK2WVMC9YE3DRPJ4
                  quantity: 4
                  unit_cost_minor: 250
              variance_negative_stock:
                summary: NEGATIVE_STOCK_AFTER_BACKFILL warning (no force)
                value:
                  branch_id: 01HQXBT7N8FK2WVMC9YE3DRPJ5
                  variant_id: 01HQXBT7N8FK2WVMC9YE3DRPJ4
                  quantity: 10
                  unit_cost_minor: 100
      responses:
        '201':
          description: Created (`data` includes movement / layer / receipt ids).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Variance envelopes or validation.
          content:
            application/json:
              schema:
                oneOf:
                - $ref: '#/components/schemas/VarianceErrorResponse'
                - $ref: '#/components/schemas/VarianceWarningResponse'
                - $ref: '#/components/schemas/ErrorResponse'
              examples:
                variance_errors:
                  summary: VARIANCE_ERRORS (e.g. INVALID_QUANTITY)
                  value:
                    error:
                      code: VARIANCE_ERRORS
                      message_en: One or more variance checks failed.
                      message_ar: فشلت واحدة أو أكثر من فحوصات التباين.
                      errors:
                        - code: INVALID_QUANTITY
                          severity: error
                          message_en: Received quantity must be positive.
                          message_ar: الكمية المستلمة يجب أن تكون أكبر من صفر.
                          details:
                            quantity_received: 0
                variance_warnings_negative_stock:
                  summary: VARIANCE_WARNINGS NEGATIVE_STOCK_AFTER_BACKFILL
                  value:
                    error:
                      code: VARIANCE_WARNINGS
                      message_en: Variance warnings require acknowledgment.
                      message_ar: تحذيرات التباين تتطلب تأكيداً.
                      warnings:
                        - code: NEGATIVE_STOCK_AFTER_BACKFILL
                          severity: warning
                          message_en: Stock would remain negative after backfill.
                          message_ar: المخزون قد يبقى سالباً بعد التعبئة
                          details: {}
                          suggestion_en: Confirm physical count or enable force.
                          suggestion_ar: تأكد من الجرد الفعلي أو استخدم force
                      hint: Add ?force=true to record despite warnings.
      security:
      - bearerAuth: []
  /journal-entries:
    post:
      operationId: post_journal_entries
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 17.7 — Journal & GL
      summary: Manual journal entry (root alias)
      description: '**Accounting (Books)** — Double-entry, COA, GL, VAT/ZATCA, AR/AP, banking, dimensions, and reports. All
        calls require tenant `Authorization`; mutating routes require `Idempotency-Key` per `docs/current/BACKEND-CONVENTIONS.md`. Money
        in request/response follows tenant accounting rules (minor units / `currency_code` per resource; see DECISIONS D2).
        Endpoint-specific: **Manual journal entry (root alias)**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /kds/items/{id}/{action}:
    post:
      operationId: post_kds_items_id_action
      tags:
      - 11 — Dine / Orders & KDS
      summary: KDS transition
      description: Generated from Postman — `KDS transition` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - name: action
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `action` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /loyalty/breakage:
    post:
      operationId: post_loyalty_breakage
      tags:
      - 07 — Customers, Loyalty, Gift Cards
      summary: Loyalty breakage (admin/job)
      description: Generated from Postman — `Loyalty breakage (admin/job)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /loyalty/redeem:
    post:
      operationId: post_loyalty_redeem
      tags:
      - 07 — Customers, Loyalty, Gift Cards
      summary: Loyalty redeem
      description: Generated from Postman — `Loyalty redeem` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
      x-current-state: documented at docs/handoff/FLOAT-MONEY-API-AUDIT.md (Tier A — float or major-unit money in live JSON
        until Track B).
      x-target-state: 'Amended D2: monetary fields use components.schemas.Money after Track B.'
  /marketplaces/{partner}/sync:
    post:
      operationId: post_marketplaces_partner_sync
      tags:
      - 10 — E-com & Marketplaces
      summary: Sync marketplace catalog
      description: Generated from Postman — `Sync marketplace catalog` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: partner
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `partner` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /me:
    get:
      operationId: get_me
      tags:
      - 00 — Reference · Canonical API errors
      summary: Reference · Error envelope (sample status codes) | Me
      description: 'Illustrative examples. **`code` / HTTP status** match common handlers in `bootstrap/app.php`; `message_*`
        strings may vary slightly by endpoint. Validation failures use **422** with non-empty `fields`.


        `GET /me` — Current user profile, resolved permissions (`permissions[]`), roles, and company context. Requires `Authorization`.
        See **401** example (missing/invalid token).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
      security: []
    patch:
      operationId: patch_me
      tags:
      - 01 — Auth & Identity
      summary: Update profile
      description: '`PATCH /me` — Update profile fields (e.g. name, locale). Mutations follow tenant validation rules.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /me/branches:
    get:
      operationId: get_me_branches
      tags:
      - 01 — Auth & Identity
      summary: My branches
      description: '`GET /me/branches` — Canonical branch list for branch pickers (full DTO vs login payload per `DECISIONS.md`
        D4).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /me/invoices:
    get:
      operationId: get_me_invoices
      tags:
      - 19 — Platform & Billing
      summary: List my platform SaaS invoices
      description: |
        Tenant-scoped list (`permission:billing.me_invoices.read`). Safe payload: amounts in minor units, line items, public `discount_code` snapshot only (no internal platform discount row id).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: page
        in: query
        schema:
          type: integer
          minimum: 1
      - name: per_page
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 100
      responses:
        '200':
          description: Success — `data[]` of `TenantPlatformInvoiceDetail` (includes `lines`), `meta` pagination.
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/TenantPlatformInvoiceDetail'
                  meta:
                    type: object
                    properties:
                      page:
                        type: integer
                      per_page:
                        type: integer
                      total:
                        type: integer
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /me/invoices/{id}:
    get:
      operationId: get_me_invoices_id
      tags:
      - 19 — Platform & Billing
      summary: Show my platform SaaS invoice
      description: '`GET /me/invoices/{id}` — same permission as list; **404** if invoice belongs to another tenant.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      responses:
        '200':
          description: Success — `data` is `TenantPlatformInvoiceDetail`.
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                properties:
                  data:
                    $ref: '#/components/schemas/TenantPlatformInvoiceDetail'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /me/ess:
    get:
      operationId: get_me_ess
      tags:
      - 18 — HR
      summary: ESS
      description: Generated from Postman — `ESS` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /me/invoices/{id}/pay:
    post:
      operationId: post_me_invoices_id_pay
      tags:
      - 19 — Platform & Billing
      summary: Pay platform invoice (tenant side)
      description: Generated from Postman — `Pay platform invoice (tenant side)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /me/mfa:
    post:
      operationId: post_me_mfa
      tags:
      - 01 — Auth & Identity
      summary: Enable MFA
      description: '`POST /me/mfa` — Start MFA enrollment; follow with verify flow per product spec.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /me/limits:
    get:
      operationId: get_me_limits
      tags:
      - 01 — Auth & Identity
      summary: My effective subscription limits
      description: '`GET /me/limits` — Tenant-safe effective caps: `data.plan_code`, `data.plan_id`, and `data.limits[]` with `{ limit_type, effective_value }` only (no `source`, `plan_value`, or override audit fields).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success — body `data` matches implementation (`plan_code`, `plan_id`, `limits` array).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /me/modules:
    get:
      operationId: get_me_modules
      tags:
      - 01 — Auth & Identity
      summary: My modules
      description: '`GET /me/modules` — Enabled product modules / entitlements for the current tenant user.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /me/plan:
    get:
      operationId: get_me_plan
      tags:
      - 01 — Auth & Identity
      summary: My subscription plan
      description: '`GET /me/plan` — `data.plan_code`, `data.plan_id`, and `data.subscription` (null if none). When present, `subscription` includes `id`, `status`, `billing_cycle`, `trial_ends_at` (ISO8601 or null), `current_period_start` / `current_period_end` (date strings).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success — body `data` matches implementation (see operation description).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /me/password:
    post:
      operationId: post_me_password
      tags:
      - 01 — Auth & Identity
      summary: Change password
      description: '`POST /me/password` — Change password with `current_password` / `password` / `password_confirmation`.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /me/usage:
    get:
      operationId: get_me_usage
      tags:
      - 01 — Auth & Identity
      summary: My subscription usage (summary)
      description: '`GET /me/usage` — `data.usage[]` entries `{ limit_type, current }` for every plan limit key (same enum as quotas; `daily_api_requests` / `storage_mb` may report `0` until wired).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: 'Success — `data.usage` is an array of objects with `limit_type` and `current` (per implementation).'
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /me/setup-progress:
    get:
      operationId: get_me_setup_progress
      tags:
      - 01 — Auth & Identity
      summary: Setup progress
      description: '`GET /me/setup-progress` — Tenant onboarding/setup checklist for dashboard resume.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /menu-items/bulk-availability:
    post:
      operationId: post_menu_items_bulk_availability
      tags:
      - 13 — Dine / Menus, Modifiers, Combos
      summary: Bulk-update item availability (86)
      description: Generated from Postman — `Bulk-update item availability (86)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /menus:
    get:
      operationId: get_menus
      tags:
      - 13 — Dine / Menus, Modifiers, Combos
      summary: List menus
      description: Generated from Postman — `List menus` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_menus
      tags:
      - 13 — Dine / Menus, Modifiers, Combos
      summary: Create menu
      description: Generated from Postman — `Create menu` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /merchants/{id}/mdr:
    put:
      operationId: put_merchants_id_mdr
      tags:
      - 16 — Pay (PSP)
      summary: Set MDR schedule
      description: Generated from Postman — `Set MDR schedule` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /modifier-groups:
    get:
      operationId: get_modifier_groups
      tags:
      - 13 — Dine / Menus, Modifiers, Combos
      summary: List modifier groups
      description: Generated from Postman — `List modifier groups` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_modifier_groups
      tags:
      - 13 — Dine / Menus, Modifiers, Combos
      summary: Create modifier group
      description: Generated from Postman — `Create modifier group` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /order-items/{id}:
    patch:
      operationId: patch_order_items_id
      tags:
      - 11 — Dine / Orders & KDS
      summary: Modify item
      description: Generated from Postman — `Modify item` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /order-items/{id}/void:
    post:
      operationId: post_order_items_id_void
      tags:
      - 11 — Dine / Orders & KDS
      summary: Void item (manager PIN)
      description: Generated from Postman — `Void item (manager PIN)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /orders:
    post:
      operationId: post_orders
      tags:
      - 11 — Dine / Orders & KDS
      summary: Open order
      description: Generated from Postman — `Open order` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - $ref: '#/components/parameters/BranchId'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /orders/{id}/cancel:
    post:
      operationId: post_orders_id_cancel
      tags:
      - 11 — Dine / Orders & KDS
      summary: Cancel order
      description: Generated from Postman — `Cancel order` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /orders/{id}/close:
    post:
      operationId: post_orders_id_close
      tags:
      - 11 — Dine / Orders & KDS
      summary: Close order (creates Sale)
      description: Generated from Postman — `Close order (creates Sale)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /orders/{id}/fire:
    post:
      operationId: post_orders_id_fire
      tags:
      - 11 — Dine / Orders & KDS
      summary: Fire order
      description: Generated from Postman — `Fire order` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /orders/{id}/items:
    post:
      operationId: post_orders_id_items
      tags:
      - 11 — Dine / Orders & KDS
      summary: Add item
      description: Generated from Postman — `Add item` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /orders/{id}/serve:
    post:
      operationId: post_orders_id_serve
      tags:
      - 11 — Dine / Orders & KDS
      summary: Serve order
      description: Generated from Postman — `Serve order` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /pay/charge:
    post:
      operationId: post_pay_charge
      tags:
      - 16 — Pay (PSP)
      summary: Charge (active capture)
      description: Generated from Postman — `Charge (active capture)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /pay/disputes:
    post:
      operationId: post_pay_disputes
      tags:
      - 16 — Pay (PSP)
      summary: Open dispute (merchant-initiated)
      description: Generated from Postman — `Open dispute (merchant-initiated)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /pay/partner/transactions:
    post:
      operationId: post_pay_partner_transactions
      tags:
      - 16 — Pay (PSP)
      summary: Record partner-pushed txn (HMAC)
      description: Generated from Postman — `Record partner-pushed txn (HMAC)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /pay/partners/{id}/keys:
    post:
      operationId: post_pay_partners_id_keys
      tags:
      - 16 — Pay (PSP)
      summary: Issue partner sandbox keys
      description: Generated from Postman — `Issue partner sandbox keys` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /pay/payouts:
    post:
      operationId: post_pay_payouts
      tags:
      - 16 — Pay (PSP)
      summary: Manual / out-of-cycle payout
      description: Generated from Postman — `Manual / out-of-cycle payout` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
      x-current-state: documented at docs/handoff/FLOAT-MONEY-API-AUDIT.md (Tier A — float or major-unit money in live JSON
        until Track B).
      x-target-state: 'Amended D2: monetary fields use components.schemas.Money after Track B.'
  /pay/settlements:
    get:
      operationId: get_pay_settlements
      tags:
      - 16 — Pay (PSP)
      summary: Tenant settlements (read-only)
      description: Generated from Postman — `Tenant settlements (read-only)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: from
        in: query
        schema:
          type: string
        example: '2026-04-01'
      - name: to
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
      x-current-state: documented at docs/handoff/FLOAT-MONEY-API-AUDIT.md (Tier A — float or major-unit money in live JSON
        until Track B).
      x-target-state: 'Amended D2: monetary fields use components.schemas.Money after Track B.'
  /pay/settlements/{id}/lines:
    get:
      operationId: get_pay_settlements_id_lines
      tags:
      - 16 — Pay (PSP)
      summary: Settlement lines (drill-down)
      description: Generated from Postman — `Settlement lines (drill-down)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - name: page
        in: query
        schema:
          type: string
        example: '1'
      - name: per_page
        in: query
        schema:
          type: string
        example: '50'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
      x-current-state: documented at docs/handoff/FLOAT-MONEY-API-AUDIT.md (Tier A — float or major-unit money in live JSON
        until Track B).
      x-target-state: 'Amended D2: monetary fields use components.schemas.Money after Track B.'
  /pay/softpos-devices:
    post:
      operationId: post_pay_softpos_devices
      tags:
      - 16 — Pay (PSP)
      summary: Issue SoftPOS device
      description: Generated from Postman — `Issue SoftPOS device` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /pay/terminals:
    post:
      operationId: post_pay_terminals
      tags:
      - 16 — Pay (PSP)
      summary: Issue terminal
      description: Generated from Postman — `Issue terminal` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /pay/transactions:
    get:
      operationId: get_pay_transactions
      tags:
      - 16 — Pay (PSP)
      summary: List transactions
      description: Generated from Postman — `List transactions` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: from
        in: query
        schema:
          type: string
        example: '2026-04-01'
      - name: merchant_id
        in: query
        schema:
          type: string
        example: ''
      - name: scheme
        in: query
        schema:
          type: string
        example: ''
      - name: status
        in: query
        schema:
          type: string
        example: ''
      - name: to
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_pay_transactions
      tags:
      - 16 — Pay (PSP)
      summary: Record direct SoftPOS txn
      description: Generated from Postman — `Record direct SoftPOS txn` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /pay/transactions/{id}/refund:
    post:
      operationId: post_pay_transactions_id_refund
      tags:
      - 16 — Pay (PSP)
      summary: Refund (record-only)
      description: Generated from Postman — `Refund (record-only)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /plans:
    get:
      operationId: get_plans
      tags:
      - 19 — Platform & Billing
      summary: Active plan catalog (read-only)
      description: |
        `GET /plans` — **Not** admin CRUD: returns a **read-only** catalog of **active, non-archived** plans for quoting/UI (`ListActivePlansService`).
        Each `data[]` item is `{ code, name }` where `name` is `name_en` fallback `name_ar` fallback `code`. Requires platform Sanctum token + `permission:platform.plans.read` (`IndexPlansController`).
        **Contrast:** `GET /platform/plans` is paginated **admin** listing (summaries, optional `include_archived`, counts); this route is the slim public-style picker.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: page
        in: query
        schema:
          type: integer
          minimum: 1
      - name: per_page
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 100
      responses:
        '200':
          description: Success — `data` array of `ActivePlanCatalogRow`, `meta` with `page`, `per_page`, `total`.
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ActivePlanCatalogRow'
                  meta:
                    type: object
                    properties:
                      page:
                        type: integer
                      per_page:
                        type: integer
                      total:
                        type: integer
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden — missing `platform.plans.read` or not a platform actor
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/auth/login:
    post:
      operationId: post_platform_auth_login
      tags:
      - 01 — Auth & Identity
      summary: 'Platform: login'
      description: '`POST /platform/auth/login` — Platform operator login; use `platformToken` for folder 19 routes.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security: []
  /platform/health:
    get:
      operationId: get_platform_health
      tags:
      - 19 — Platform & Billing
      summary: Health overview
      description: |
        **DB-backed snapshots (Milestone 1.F-1):** Returns **`data.services[]`** from the latest **`service_health_snapshots`** row per `(service, region)` by `bucket_start`.
        When no snapshots exist, **`services`** is an empty array. **`data.platform_ops_truth`:** `data_source: live`, `sla_status: non_sla` — rows are **persisted telemetry**, not a substitute for external uptime SLAs or customer-facing SRE commitments until product defines otherwise.
        Requires `platform.health.read`. Originally generated from Postman — `Health overview` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: |
            Success. **`data.platform_ops_truth`** is mandatory. Shape matches **`PlatformSuccessEnvelopeStubOpsData`**; for this route **`platform_ops_truth.data_source`** is **`live`** when reading snapshots (see operation description).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlatformSuccessEnvelopeStubOpsData'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/incidents:
    post:
      operationId: post_platform_incidents
      tags:
      - 19 — Platform & Billing
      summary: Create platform incident
      description: |
        **Milestone 1.F-4:** Creates a **`platform_incidents`** row in **`open`** state. **`data.platform_ops_truth`:** `data_source: live`, `sla_status: non_sla`.
        Requires `platform.incidents.create`. See **`docs/current/PLATFORM-OPS-CONTRACT.md`**.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - title
              properties:
                title:
                  type: string
                  maxLength: 191
                description:
                  type: string
                  nullable: true
      responses:
        '201':
          description: Created. **`data.platform_ops_truth`** is mandatory (`live` / `non_sla`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlatformSuccessEnvelopeStubOpsData'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/incidents/metrics:
    get:
      operationId: get_platform_incidents_metrics
      tags:
      - 19 — Platform & Billing
      summary: Incident MTTR metrics
      description: |
        **Milestone 1.F-4:** Rollup of resolved incidents in the date window (MySQL **`TIMESTAMPDIFF`** from **`opened_at`** to **`resolved_at`**).
        Query: **`from`**, **`to`** (`Y-m-d`). **`data.platform_ops_truth`:** `data_source: live`, `sla_status: non_sla`. Requires `platform.incidents.read`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: from
        in: query
        schema:
          type: string
          format: date
      - name: to
        in: query
        schema:
          type: string
          format: date
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlatformSuccessEnvelopeStubOpsData'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/analytics/revenue:
    get:
      operationId: get_platform_analytics_revenue
      tags:
      - 19 — Platform & Billing
      summary: Cross-tenant revenue (MRR / ARR)
      description: |
        **Milestone 1.G-1:** ARR and MRR from **`tenant_subscriptions`** joined to **`plans`** (**active** / **past_due**, **`ended_at`** null). **`top`** (1–50) caps **`top_tenants_by_mrr`**.
        **`data.platform_ops_truth`:** `data_source: live`, `sla_status: non_sla`, `scope: cross_tenant_subscription_rollups`. Requires `platform.analytics.revenue.read`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: top
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 50
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlatformSuccessEnvelopeStubOpsData'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/analytics/retention:
    get:
      operationId: get_platform_analytics_retention
      tags:
      - 19 — Platform & Billing
      summary: Cross-tenant retention (churn + cohorts)
      description: |
        **Milestone 1.G-2:** Churn rollups and first-subscription **cohort_month** retention from **`tenant_subscriptions`**
        (MySQL **`DATE_FORMAT`**). Query **`from`**, **`to`** (`Y-m-d`), optional **`cohort_months`** (1–24, default **6**).
        **`data.platform_ops_truth`:** `scope: cross_tenant_subscription_retention`. Requires `platform.analytics.retention.read`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: from
        in: query
        required: true
        schema:
          type: string
          format: date
      - name: to
        in: query
        required: true
        schema:
          type: string
          format: date
      - name: cohort_months
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 24
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlatformSuccessEnvelopeStubOpsData'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/analytics/acquisition:
    get:
      operationId: get_platform_analytics_acquisition
      tags:
      - 19 — Platform & Billing
      summary: Cross-tenant acquisition (signup funnel snapshot)
      description: |
        **Milestone 1.G-3:** Counts of **`signups`** rows **created** in **`[from,to]`**, grouped by **current** `status` (not transition history).
        **`data.platform_ops_truth`:** `scope: cross_tenant_signup_funnel`. Requires `platform.analytics.acquisition.read`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: from
        in: query
        required: true
        schema:
          type: string
          format: date
      - name: to
        in: query
        required: true
        schema:
          type: string
          format: date
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlatformSuccessEnvelopeStubOpsData'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/cutover/readiness:
    get:
      operationId: get_platform_cutover_readiness
      tags:
      - 19 — Platform & Billing
      summary: Cutover readiness checklist (Stage 7.A)
      description: |
        **Live readiness checks** for v1 cutover: pending app migrations (`database/migrations` vs `migrations` table),
        tenant subscription health (past-due open rows; active/trial tenants missing an open subscription),
        fiscal period close hygiene (stale open periods), referential integrity (orphan users/customers/fiscal periods vs
        non–soft-deleted companies), plus static product roadmap rows. **`cutover_truth.data_source`** is **`live_catalog`**.
        Requires `platform.cutover.readiness.read`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlatformCutoverReadinessEnvelope'
              example:
                data:
                  checklist_version: 2
                  rollup_status: pass
                  checks:
                  - id: pending_migrations
                    status: pass
                    summary_en: All discovered migration files are recorded in the migrations table.
                    summary_ar: جميع ملفات الترحيل المكتشفة مسجّلة في جدول الترحيلات.
                    metrics:
                      pending_count: 0
                      pending_sample: []
                  - id: subscription_health
                    status: pass
                    summary_en: No past-due open subscriptions; active and trial tenants have an open subscription row.
                    summary_ar: لا اشتراكات مفتوحة متأخرة؛ الشركات النشطة والتجريبية لديها صف اشتراك مفتوح.
                    metrics:
                      past_due_open_rows: 0
                      active_trial_missing_open_subscription: 0
                  - id: accounting_period_close
                    status: pass
                    summary_en: 'Open fiscal periods: 0; none are stale beyond the one-month grace window.'
                    summary_ar: 'فترات مفتوحة: 0؛ لا توجد فترات قديمة خارج نافذة شهر واحد.'
                    metrics:
                      open_period_rows: 0
                      stale_open_period_rows: 0
                  - id: referential_integrity
                    status: pass
                    summary_en: No orphan tenant rows detected for users, customers, or fiscal periods vs active companies.
                    summary_ar: لا صفوف يتيمة للمستخدمين أو العملاء أو الفترات المالية مقابل الشركات النشطة.
                    metrics:
                      orphan_users: 0
                      orphan_customers: 0
                      orphan_fiscal_periods: 0
                      total_orphan_rows: 0
                  - id: tenant_notifications
                    status: implemented
                    summary_en: Tenant notification preferences, dispatch pipeline, and in-app inbox (Stage 6.A-2).
                    summary_ar: تفضيلات الإشعارات وقناة الإرسال وصندوق داخل التطبيق (المرحلة 6.A-2).
                  cutover_truth:
                    data_source: live_catalog
                    sla_status: non_sla
                    generated_at: '2026-04-27T12:00:00+00:00'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/cutover/write-freeze-status:
    get:
      operationId: get_platform_cutover_write_freeze_status
      tags:
      - 19 — Platform & Billing
      summary: Global write-freeze flag (Stage 7.B)
      description: |
        Reads **`config('cutover.global_freeze_writes')`** (env **`CUTOVER_GLOBAL_FREEZE_WRITES`** via `config/cutover.php`).
        Returns **`config_key`**, **`env_var`**, human **`interpretation_*`**, and **`cutover_truth.generated_at`**.
        Route enforcement is a follow-on; this endpoint is observability-only. Requires `platform.cutover.freeze.read`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlatformCutoverWriteFreezeEnvelope'
              example:
                data:
                  global_freeze_writes: false
                  config_key: cutover.global_freeze_writes
                  env_var: CUTOVER_GLOBAL_FREEZE_WRITES
                  interpretation_en: Global write-freeze is off; tenant writes follow normal authorization and validation.
                  interpretation_ar: تجميد الكتابة العام غير مفعّل؛ تستمر كتابات المستأجر وفق الصلاحيات والتحقق المعتاد.
                  cutover_truth:
                    data_source: config
                    sla_status: non_sla
                    generated_at: '2026-04-27T12:00:00+00:00'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/msp/compliance/dashboard:
    get:
      operationId: get_platform_msp_compliance_dashboard
      tags:
      - 19 — Platform & Billing
      summary: MSP SAMA security-event dashboard (Stage 6.D-1)
      description: |
        Rolling-window counts and recent rows from **`msp_sama_security_events`**. Requires `platform.msp.compliance.dashboard.read`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/incidents/{id}/{action}:
    post:
      operationId: post_platform_incidents_id_action
      tags:
      - 19 — Platform & Billing
      summary: Incident transition
      description: |
        **Milestone 1.F-4 (persisted):** Validates the linear state machine **open → investigating → identified → monitoring → resolved → closed**,
        writes **`incident_transitions`**, updates **`platform_incidents`**, optional Slack + email (**`config/platform_incidents.php`**), and **`audit_logs`**.
        **`data.platform_ops_truth`:** `data_source: live`, `sla_status: non_sla`. Path **`action`**: `investigate`, `acknowledge` (alias → investigating), `identify`, `monitor`, `mitigate` (alias → monitoring), `resolve`, `close`.
        Requires `platform.incidents.transition`. See **`docs/current/PLATFORM-OPS-CONTRACT.md`**.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - name: action
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `action` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: |
            Success. **`PlatformSuccessEnvelopeStubOpsData`** envelope; **`platform_ops_truth`** is **`live`** / **`non_sla`** for this route.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlatformSuccessEnvelopeStubOpsData'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/releases/{id}/promote:
    post:
      operationId: post_platform_releases_id_promote
      tags:
      - 19 — Platform & Billing
      summary: Promote release
      description: |
        **Milestone 1.F-2:** `PlatformReleasePromoteStubService` echoes ring/percent — **no** deployment persistence. Use external CI/CD for real promotions.
        **`data.platform_ops_truth`**: `data_source: non_sla`, `implementation: stub`, `recommendation`, `documented_in` (see **`docs/current/PLATFORM-OPS-CONTRACT.md`**). Requires `platform.releases.manage`. Postman — `Promote release`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: |
            Success. **`platform_ops_truth`** uses the **1.F-2** non-SLA stub contract (`implementation: stub`, etc.).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlatformSuccessEnvelopeStubOpsData'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/releases/{id}/rollback:
    post:
      operationId: post_platform_releases_id_rollback
      tags:
      - 19 — Platform & Billing
      summary: Rollback release
      description: |
        **Milestone 1.F-3:** `PlatformReleaseRollbackStubService` returns **synthetic** rollback fields — **no** infra rollback.
        **`data.platform_ops_truth`**: same **non-SLA stub** contract as promote (**1.F-2**). Requires `platform.releases.manage`. Postman — `Rollback release`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: |
            Success. **`platform_ops_truth`** uses the **1.F-2** non-SLA stub contract.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlatformSuccessEnvelopeStubOpsData'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/signups:
    get:
      operationId: get_platform_signups
      tags:
      - 02 — Tenancy & Onboarding
      summary: 'Platform: signups queue'
      description: 'Generated from Postman — `Platform: signups queue` (`docs/postman/DALSEEN.postman_collection.json`).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: status
        in: query
        schema:
          type: string
        example: submitted
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/signups/{id}:
    get:
      operationId: get_platform_signups_id
      tags:
      - 02 — Tenancy & Onboarding
      summary: 'Platform: signup workbench'
      description: 'Generated from Postman — `Platform: signup workbench` (`docs/postman/DALSEEN.postman_collection.json`).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/signups/{id}/{step}:
    post:
      operationId: post_platform_signups_id_step
      tags:
      - 02 — Tenancy & Onboarding
      summary: 'Platform: KYC step'
      description: 'Generated from Postman — `Platform: KYC step` (`docs/postman/DALSEEN.postman_collection.json`).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - name: step
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `step` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/tenants:
    get:
      operationId: get_platform_tenants
      tags:
      - 19 — Platform & Billing
      summary: Tenants list
      description: Generated from Postman — `Tenants list` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: status
        in: query
        schema:
          type: string
        example: active
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/tenants/provision:
    post:
      operationId: post_platform_tenants_provision
      tags:
      - 02 — Tenancy & Onboarding
      summary: 'Platform: provision tenant'
      description: 'Generated from Postman — `Platform: provision tenant` (`docs/postman/DALSEEN.postman_collection.json`).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/tenants/{id}:
    get:
      operationId: get_platform_tenants_id
      tags:
      - 19 — Platform & Billing
      summary: Tenant drawer
      description: Generated from Postman — `Tenant drawer` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/tenants/{id}/impersonate:
    post:
      operationId: post_platform_tenants_id_impersonate
      tags:
      - 19 — Platform & Billing
      summary: Impersonate
      description: Generated from Postman — `Impersonate` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/tenants/{id}/quote:
    post:
      operationId: post_platform_tenants_id_quote
      tags:
      - 19 — Platform & Billing
      summary: Quote subscription change
      description: |
        Preview SaaS subscription invoice amounts in **minor units (halalas)** for an active plan + optional add-ons + optional `discount_code`.
        VAT 15% is computed **after** discount on the pre-tax subtotal. `id` is the tenant **company** ULID.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
        description: Tenant company ULID.
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlatformTenantSubscriptionQuoteBody'
      responses:
        '200':
          description: Success — `data` matches `PlatformSubscriptionQuoteTotals` (all monetary fields in minor units).
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                properties:
                  data:
                    $ref: '#/components/schemas/PlatformSubscriptionQuoteTotals'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed or discount code not applicable (`error.code` `DISCOUNT_CODE_NOT_APPLICABLE`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/tenants/{id}/reactivate:
    post:
      operationId: post_platform_tenants_id_reactivate
      tags:
      - 19 — Platform & Billing
      summary: Reactivate tenant
      description: Generated from Postman — `Reactivate tenant` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/tenants/{id}/subscription:
    post:
      operationId: post_platform_tenants_id_subscription
      tags:
      - 19 — Platform & Billing
      summary: Apply tenant subscription change
      description: |
        `POST /platform/tenants/{id}/subscription` — `permission:platform.billing.apply_subscription`, `audit.write`, `idempotent`.
        Body requires `plan_code` (active, non-archived plan). Optional `addons` (same shape as quote) and optional `discount_code` (platform catalog; discount applied **before** VAT; `uses_count` incremented when applied).
        Creates **`platform_invoices`** (with discount snapshot columns) and one **`platform_invoice_lines`** row for the net subscription charge.
        Returns **200** with `data.tenant_id`, `data.invoice_id`, `data.subscription_id`, and `data.warnings` (e.g. limit overrides).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
        description: Tenant company ULID.
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlatformTenantSubscriptionApplyBody'
      responses:
        '200':
          description: Success — `data` includes `tenant_id`, `invoice_id`, `subscription_id`, `warnings`.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (missing `platform.billing.apply_subscription` or not a platform actor)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed or discount code not applicable (`DISCOUNT_CODE_NOT_APPLICABLE`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/tenants/{id}/invoices:
    get:
      operationId: get_platform_tenants_id_invoices
      tags:
      - 19 — Platform & Billing
      summary: List tenant platform SaaS invoices
      description: |
        Paginated list of **`platform_invoices`** for Finance (`permission:platform.billing.invoices.read`).
        Includes line items and optional applied discount metadata (`applied_platform_discount_code_id`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
        description: Tenant company ULID.
      - name: page
        in: query
        schema:
          type: integer
          minimum: 1
      - name: per_page
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 100
      responses:
        '200':
          description: Success — `data[]` of `PlatformTenantInvoiceDetail`, `meta` pagination.
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - meta
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PlatformTenantInvoiceDetail'
                  meta:
                    type: object
                    properties:
                      page:
                        type: integer
                      per_page:
                        type: integer
                      total:
                        type: integer
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Tenant company not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/tenants/{id}/limit-overrides:
    get:
      operationId: get_platform_tenants_id_limit_overrides
      tags:
      - 19 — Platform & Billing
      summary: List tenant limit overrides
      description: '`GET …/limit-overrides` — `permission:platform.tenant_limits.read`. Returns `data` array and `meta.total`.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
        description: Tenant company ULID.
      responses:
        '200':
          description: Success — each row includes `id`, `limit_type`, `override_value`, `reason`, `granted_at`, `expires_at`, `granted_by` (nullable `{id, name, email}`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_platform_tenants_id_limit_overrides
      tags:
      - 19 — Platform & Billing
      summary: Create tenant limit override
      description: '`POST …/limit-overrides` — `permission:platform.tenant_limits.manage`, `audit.write` (no idempotency middleware). **201** on success.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
        description: Tenant company ULID.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlatformTenantLimitOverrideStoreBody'
      responses:
        '201':
          description: Created — `data` with override row fields.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/tenants/{id}/limit-overrides/{override}:
    delete:
      operationId: delete_platform_tenants_id_limit_overrides_override
      tags:
      - 19 — Platform & Billing
      summary: Delete tenant limit override
      description: '`DELETE …/limit-overrides/{override}` — `permission:platform.tenant_limits.manage`, `audit.write`. **204** empty body on success.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
        description: Tenant company ULID.
      - name: override
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
        description: Tenant limit override ULID.
      responses:
        '204':
          description: No content — override revoked.
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Company or override not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/tenants/{id}/effective-limits:
    get:
      operationId: get_platform_tenants_id_effective_limits
      tags:
      - 19 — Platform & Billing
      summary: Tenant effective limits (platform)
      description: '`GET …/effective-limits` — `permission:platform.tenant_limits.read`. Merged plan + active overrides (`plan_code`, `plan_id`, `limits[]` with `limit_type`, `effective_value`, `source`, `plan_value`, `override_value`).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
        description: Tenant company ULID.
      responses:
        '200':
          description: Success — `data` matches `GetTenantEffectiveLimitsService` payload.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Tenant not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/tenants/{id}/suspend:
    post:
      operationId: post_platform_tenants_id_suspend
      tags:
      - 19 — Platform & Billing
      summary: Suspend tenant
      description: Generated from Postman — `Suspend tenant` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/catalog/features:
    get:
      operationId: get_platform_catalog_features
      tags:
      - 19 — Platform & Billing
      summary: List catalog features
      description: '`GET /platform/catalog/features` — `permission:platform.plans.read`. Query `include_inactive` (boolean). Returns `data` rows and `meta.total`.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: include_inactive
        in: query
        required: false
        schema:
          type: boolean
      responses:
        '200':
          description: Success — each feature includes `id`, `code`, `name_ar`, `name_en`, `module`, descriptions, `sort_order`, `is_active`.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/discount-codes:
    get:
      operationId: get_platform_discount_codes
      tags:
      - 19 — Platform & Billing
      summary: List platform discount codes
      description: '`GET /platform/discount-codes` — `permission:platform.discount_codes.read`. Query `include_archived` (boolean).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: include_archived
        in: query
        required: false
        schema:
          type: boolean
      responses:
        '200':
          description: Success — `data` rows with `id`, `code`, names, discounts, validity, `uses_count`, `is_active`, `archived_at`.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_platform_discount_codes
      tags:
      - 19 — Platform & Billing
      summary: Create platform discount code
      description: '`POST /platform/discount-codes` — `permission:platform.discount_codes.manage`, `audit.write`, `idempotent`. **201**.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlatformDiscountCodeStoreBody'
      responses:
        '201':
          description: Created — subset of fields in `data`.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/discount-codes/{discountCode}:
    patch:
      operationId: patch_platform_discount_codes_discountCode
      tags:
      - 19 — Platform & Billing
      summary: Update platform discount code
      description: '`PATCH /platform/discount-codes/{discountCode}` — `permission:platform.discount_codes.manage`, `audit.write` (no idempotency middleware).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: discountCode
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlatformDiscountCodeUpdateBody'
      responses:
        '200':
          description: Success — `data` subset returned.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/discount-codes/{discountCode}/archive:
    post:
      operationId: post_platform_discount_codes_discountCode_archive
      tags:
      - 19 — Platform & Billing
      summary: Archive platform discount code
      description: '`POST …/archive` — `permission:platform.discount_codes.manage`, `audit.write`, `idempotent`.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: discountCode
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success — `data` includes `id`, `code`, `archived_at`, `is_active`.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/plans:
    get:
      operationId: get_platform_plans
      tags:
      - 19 — Platform & Billing
      summary: List platform plans
      description: '`GET /platform/plans` — `permission:platform.plans.read`. Query `page`, `per_page` (max 100), `include_archived`. Summaries include `limits_count`, `modules_count`, `features_count`.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: page
        in: query
        schema:
          type: integer
          minimum: 1
      - name: per_page
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 100
      - name: include_archived
        in: query
        schema:
          type: boolean
      responses:
        '200':
          description: Success — paginated `data` + `meta` (`page`, `per_page`, `total`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_platform_plans
      tags:
      - 19 — Platform & Billing
      summary: Create platform plan
      description: '`POST /platform/plans` — `permission:platform.plans.manage`, `audit.write`, `idempotent`. **201** — returns full plan detail (`ListPlatformPlansService::toDetail`). Optional `limits`, `modules` (must include every product module code), `feature_access` rows.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlatformPlanStoreBody'
      responses:
        '201':
          description: Created — `data` is plan detail (limits, modules, features).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/plans/{plan}:
    get:
      operationId: get_platform_plans_plan
      tags:
      - 19 — Platform & Billing
      summary: Show platform plan
      description: '`GET /platform/plans/{plan}` — `permission:platform.plans.read`. `{plan}` is plan ULID.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: plan
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      responses:
        '200':
          description: Success — plan detail payload.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Plan not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    patch:
      operationId: patch_platform_plans_plan
      tags:
      - 19 — Platform & Billing
      summary: Update platform plan metadata
      description: '`PATCH /platform/plans/{plan}` — `permission:platform.plans.manage`, `audit.write` (no idempotency middleware). Returns updated plan detail.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: plan
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlatformPlanPatchBody'
      responses:
        '200':
          description: Success — plan detail.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Plan not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/plans/{plan}/archive:
    post:
      operationId: post_platform_plans_plan_archive
      tags:
      - 19 — Platform & Billing
      summary: Archive platform plan
      description: '`POST …/archive` — `permission:platform.plans.manage`, `idempotent`. Cannot archive default plan (`422` / `CANNOT_ARCHIVE_DEFAULT_PLAN`).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: plan
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success — archived plan detail.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation or business rule (e.g. default plan)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/plans/{plan}/restore:
    post:
      operationId: post_platform_plans_plan_restore
      tags:
      - 19 — Platform & Billing
      summary: Restore archived platform plan
      description: '`POST …/restore` — `permission:platform.plans.manage`, `idempotent`.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: plan
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success — plan detail.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/plans/{plan}/clone:
    post:
      operationId: post_platform_plans_plan_clone
      tags:
      - 19 — Platform & Billing
      summary: Clone platform plan
      description: '`POST …/clone` — `permission:platform.plans.manage`, `idempotent`. Optional body `code` for new plan code. **201** — cloned plan detail.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: plan
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                code:
                  type: string
                  nullable: true
                  maxLength: 50
      responses:
        '201':
          description: Created — cloned plan detail.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/plans/{plan}/set-default:
    post:
      operationId: post_platform_plans_plan_set_default
      tags:
      - 19 — Platform & Billing
      summary: Set default platform plan
      description: '`POST …/set-default` — `permission:platform.plans.manage`, `idempotent`. Exactly one plan remains `is_default`.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: plan
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success — plan detail.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/plans/{plan}/limits:
    put:
      operationId: put_platform_plans_plan_limits
      tags:
      - 19 — Platform & Billing
      summary: Replace plan limits
      description: '`PUT …/limits` — `permission:platform.plans.manage`, `audit.write`. Full replace of `plan_limits` from body `limits` array.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: plan
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlatformPlanSyncLimitsBody'
      responses:
        '200':
          description: Success — plan detail after sync.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/plans/{plan}/modules:
    put:
      operationId: put_platform_plans_plan_modules
      tags:
      - 19 — Platform & Billing
      summary: Replace plan module access
      description: '`PUT …/modules` — `permission:platform.plans.manage`, `audit.write`. Body `modules` must list every product module (`retail`, `dine`, `pay`, `accounting`, `hr`) with `is_included`.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: plan
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlatformPlanSyncModulesBody'
      responses:
        '200':
          description: Success — plan detail.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /platform/plans/{plan}/features:
    put:
      operationId: put_platform_plans_plan_features
      tags:
      - 19 — Platform & Billing
      summary: Replace plan catalog feature access
      description: '`PUT …/features` — `permission:platform.plans.manage`, `audit.write`. Body `features` array of `{ catalog_feature_id, is_included }`.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: plan
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlatformPlanSyncFeaturesBody'
      responses:
        '200':
          description: Success — plan detail.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /pricing/price-lists:
    get:
      operationId: get_pricing_price_lists
      tags:
      - 03 — Catalog
      summary: List price lists
      description: Generated from Postman — `List price lists` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_pricing_price_lists
      tags:
      - 03 — Catalog
      summary: Create price list
      description: Generated from Postman — `Create price list` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /pricing/resolve:
    post:
      operationId: post_pricing_resolve
      tags:
      - 03 — Catalog
      summary: Resolve price
      description: Generated from Postman — `Resolve price` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /pending-products:
    get:
      operationId: get_pending_products
      tags:
      - 03 — Catalog
      - 04 — Inventory
      summary: Pending products — list (Zero‑Friction)
      description: |
        **English:** Lists unknown POS products awaiting catalog approval; supports filters for manager queues.
        **Arabic:** قائمة المنتجات غير المعروفة في نقطة البيع بانتظار الموافقة.
        **Permission:** `catalog.products.approve` (or catalog view per tenant matrix). Variance envelopes: see
        `VarianceErrorResponse` / `VarianceWarningResponse` on approve/backfill mutations.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: status
        in: query
        schema:
          type: string
          enum:
          - pending
          - approved
          - rejected
          - all
        description: 'EN: Row status. AR: حالة السجل.'
      - name: branch_id
        in: query
        schema:
          $ref: '#/components/schemas/ResourceId'
        description: 'EN: Pendings with sales in branch. AR: فرع مرتبط بالمبيعات.'
      - name: sold_after
        in: query
        schema:
          type: string
          format: date
        description: 'EN: `last_sale_at` ≥ date. AR: آخر بيع بعد التاريخ.'
      - name: sold_before
        in: query
        schema:
          type: string
          format: date
        description: 'EN: `last_sale_at` ≤ date. AR: آخر بيع قبل التاريخ.'
      - name: age_bucket
        in: query
        schema:
          type: string
          enum:
          - lte_30d
          - gt_30d
        description: 'EN: Age since first sale. AR: عمر الطلب من أول بيع.'
      - name: per_page
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 100
      responses:
        '200':
          description: Success (`data` list / pagination per conventions).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /pending-products/{pending_product}:
    get:
      operationId: get_pending_products_pending_product
      tags:
      - 03 — Catalog
      - 04 — Inventory
      summary: Pending product — show (sales by branch)
      description: |
        **English:** Detail for review, including `sales_by_branch` aggregates.
        **Arabic:** تفاصيل المنتج المعلّق مع تفصيل المبيعات حسب الفرع.
        **Permission:** `catalog.products.approve`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: pending_product
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not found (other tenant)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /pending-products/{pending_product}/approve:
    post:
      operationId: post_pending_products_pending_product_approve
      tags:
      - 03 — Catalog
      - 04 — Inventory
      summary: Pending product — approve
      description: |
        **English:** Links historical sale lines to `variant_id`, records inventory receipt/stock when valid, applies retro‑COGS.
        Blocking checks → HTTP 422 `VARIANCE_ERRORS`. Warnings → HTTP 422 `VARIANCE_WARNINGS` unless `force=true` (audited;
        `inventory_receipts.variance_warnings` populated when forced).
        **Arabic:** الموافقة وربط المبيعات السابقة بالمتغير؛ الأخطاء تمنع التنفيذ؛ التحذيرات تتطلب `force=true` بعد المراجعة.
        **Permission:** `catalog.products.approve`. **Idempotency:** `Idempotency-Key` header required.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - name: pending_product
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      - name: force
        in: query
        required: false
        schema:
          type: boolean
          default: false
        description: 'EN: Acknowledge warnings. AR: تأكيد التحذيرات والمتابعة.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - variant_id
              - branch_id
              - quantity_received
              - unit_cost_minor
              properties:
                variant_id:
                  $ref: '#/components/schemas/ResourceId'
                branch_id:
                  $ref: '#/components/schemas/ResourceId'
                branch_availability:
                  type: string
                  enum:
                  - this_branch
                  - all_branches
                  - selected
                selected_branch_ids:
                  type: array
                  items:
                    $ref: '#/components/schemas/ResourceId'
                quantity_received:
                  type: number
                unit_cost_minor:
                  type: integer
                barcode:
                  type: string
                supplier_invoice_date:
                  type: string
                  format: date
                supplier_invoice_number:
                  type: string
                supplier_id:
                  $ref: '#/components/schemas/ResourceId'
            examples:
              happy_path:
                summary: EN happy / AR مسار ناجح
                value:
                  variant_id: 01HQXBT7N8FK2WVMC9YE3DRPJ4
                  branch_id: 01HQXBT7N8FK2WVMC9YE3DRPJ5
                  branch_availability: this_branch
                  quantity_received: 5
                  unit_cost_minor: 100
              variance_warnings_quantity:
                summary: quantity_received below sold (warnings)
                value:
                  variant_id: 01HQXBT7N8FK2WVMC9YE3DRPJ4
                  branch_id: 01HQXBT7N8FK2WVMC9YE3DRPJ5
                  branch_availability: this_branch
                  quantity_received: 1
                  unit_cost_minor: 100
      responses:
        '200':
          description: Approved.
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                properties:
                  data:
                    type: object
                    additionalProperties: true
              examples:
                happy:
                  value:
                    data:
                      pending_product_id: 01HQXBT7N8FK2WVMC9YE3DRPJ6
                      approved_product_id: 01HQXBT7N8FK2WVMC9YE3DRPJ7
                      approved_variant_id: 01HQXBT7N8FK2WVMC9YE3DRPJ4
                      stock_movement_id: 01HQXBT7N8FK2WVMC9YE3DRPJ8
                      cost_layer_id: 01HQXBT7N8FK2WVMC9YE3DRPJ9
                      inventory_receipt_id: 01HQXBT7N8FK2WVMC9YE3DRPJA
                      linked_line_count: 2
                      net_stock_after: '3.0000'
                      warnings_acknowledged: []
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden (`catalog.products.approve`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not found (tenant isolation)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Variance or domain error envelope.
          content:
            application/json:
              schema:
                oneOf:
                - $ref: '#/components/schemas/VarianceErrorResponse'
                - $ref: '#/components/schemas/VarianceWarningResponse'
                - $ref: '#/components/schemas/ErrorResponse'
              examples:
                variance_errors:
                  summary: VARIANCE_ERRORS (e.g. INVALID_COST)
                  value:
                    error:
                      code: VARIANCE_ERRORS
                      message_en: One or more variance checks failed.
                      message_ar: فشلت واحدة أو أكثر من فحوصات التباين.
                      errors:
                        - code: INVALID_COST
                          severity: error
                          message_en: Cost must be positive.
                          message_ar: التكلفة يجب أن تكون أكبر من صفر.
                          details:
                            cost_minor: 0
                variance_warnings:
                  summary: VARIANCE_WARNINGS + hint
                  value:
                    error:
                      code: VARIANCE_WARNINGS
                      message_en: Variance warnings require acknowledgment.
                      message_ar: تحذيرات التباين تتطلب تأكيداً.
                      warnings:
                        - code: QUANTITY_INSUFFICIENT
                          severity: warning
                          message_en: 'Received 3 but sold 5. Difference: 2'
                          message_ar: كمية أقل من المباع
                          details:
                            received: 3
                            sold: 5
                            difference: 2
                          suggestion_en: Verify supplier invoice or check for a second invoice.
                          suggestion_ar: تأكد من كمية فاتورة المورد، هل يوجد فاتورة ثانية؟
                      hint: Add ?force=true to approve despite warnings.
      security:
      - bearerAuth: []
  /pending-products/{pending_product}/reject:
    post:
      operationId: post_pending_products_pending_product_reject
      tags:
      - 03 — Catalog
      - 04 — Inventory
      summary: Pending product — reject
      description: |
        **English:** Rejects pending SKU; dispatches `PendingProductRejected`.
        **Arabic:** رفض المنتج المعلّق؛ يرسل الحدث للمسارات اللاحقة.
        **Permission:** `catalog.products.approve`. **Idempotency:** `Idempotency-Key` required.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - name: pending_product
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/ResourceId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - rejection_reason
              properties:
                rejection_reason:
                  type: string
                  maxLength: 2000
                  description: 'EN: Manager reason. AR: سبب الرفض.'
      responses:
        '200':
          description: Rejected.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not found (tenant isolation)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /production-orders:
    post:
      operationId: post_production_orders
      tags:
      - 14 — Dine / Recipes & Production
      summary: Production order
      description: |
        Generated from Postman — `Production order` (`docs/postman/DALSEEN.postman_collection.json`).
        **Branch scoping:** `perm:dine.production_orders.create,branch` — `X-Branch-Id` required for multi-branch users (422 if omitted).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/BranchId'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /products:
    post:
      operationId: post_products
      tags:
      - 03 — Catalog
      summary: Create product
      description: '`POST /products` — Creates a catalog product (`permission:catalog.products.create`; no idempotency middleware). **201** returns `data.id`. When `LIMITS_ENFORCED` is true and the effective plan cap for **`max_products`** would be exceeded, responds **402** with `error.code` **`LIMIT_REACHED`** (`SubscriptionLimitReachedResponse`).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '201':
          description: Created (`data` with `id` per implementation).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: Subscription / plan limit — product quota (`error.code` = `LIMIT_REACHED`; typically `fields.limit_type` = `max_products`). Not used for inventory prerequisite **402** (those use other `error.code` values).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubscriptionLimitReachedResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /products/{id}:
    patch:
      operationId: patch_products_id
      tags:
      - 03 — Catalog
      summary: Update product
      description: Generated from Postman — `Update product` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /products/{id}/variants/generate:
    post:
      operationId: post_products_id_variants_generate
      tags:
      - 03 — Catalog
      summary: Generate variant matrix
      description: Generated from Postman — `Generate variant matrix` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /promotions:
    get:
      operationId: get_promotions
      tags:
      - 09 — Promotions
      summary: List promotions
      description: Generated from Postman — `List promotions` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: status
        in: query
        schema:
          type: string
        example: active
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_promotions
      tags:
      - 09 — Promotions
      summary: Create promotion
      description: Generated from Postman — `Create promotion` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /promotions/{id}:
    patch:
      operationId: patch_promotions_id
      tags:
      - 09 — Promotions
      summary: Update promotion
      description: Generated from Postman — `Update promotion` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /purchase-orders:
    get:
      operationId: get_purchase_orders
      tags:
      - 04 — Inventory
      summary: List POs
      description: Generated from Postman — `List POs` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: status
        in: query
        schema:
          type: string
        example: open
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_purchase_orders
      tags:
      - 04 — Inventory
      summary: Create PO
      description: Generated from Postman — `Create PO` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /purchase-orders/{id}:
    patch:
      operationId: patch_purchase_orders_id
      tags:
      - 04 — Inventory
      summary: Update PO
      description: Generated from Postman — `Update PO` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /qr/{token}/menu:
    get:
      operationId: get_qr_token_menu
      tags:
      - 12 — Dine / Tables & Reservations
      summary: Public QR — get menu
      description: Generated from Postman — `Public QR — get menu` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: token
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `token` (see Laravel routes + Postman examples).
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
      security: []
  /qr/{token}/orders:
    post:
      operationId: post_qr_token_orders
      tags:
      - 12 — Dine / Tables & Reservations
      summary: Public QR — place order
      description: Generated from Postman — `Public QR — place order` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: token
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `token` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security: []
  /quick-receives:
    post:
      operationId: post_quick_receives
      tags:
      - 04 — Inventory
      summary: Quick-receive (frictionless only)
      description: Generated from Postman — `Quick-receive (frictionless only)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - $ref: '#/components/parameters/BranchId'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /recipe-drift:
    get:
      operationId: get_recipe_drift
      tags:
      - 04 — Inventory
      summary: Recipe drift list
      description: Generated from Postman — `Recipe drift list` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_recipe_drift
      tags:
      - 04 — Inventory
      summary: Recipe drift submit
      description: Generated from Postman — `Recipe drift submit` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /recipes:
    get:
      operationId: get_recipes
      tags:
      - 14 — Dine / Recipes & Production
      summary: List recipes
      description: Generated from Postman — `List recipes` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_recipes
      tags:
      - 14 — Dine / Recipes & Production
      summary: Create recipe
      description: Generated from Postman — `Create recipe` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /recipes/{id}:
    patch:
      operationId: patch_recipes_id
      tags:
      - 14 — Dine / Recipes & Production
      summary: Update recipe (creates new version)
      description: Generated from Postman — `Update recipe (creates new version)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reconciliation/{id}/resolve:
    post:
      operationId: post_reconciliation_id_resolve
      tags:
      - 04 — Inventory
      summary: Reconcile event
      description: Generated from Postman — `Reconcile event` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/accounting/cogs-catchup:
    get:
      operationId: get_reports_accounting_cogs_catchup
      tags:
      - 17 — Accounting (Books, COA, Journal, GL, VAT, Banking)
      - 20 — Reports
      summary: Accounting — COGS catch‑up (ZF retro‑COGS)
      description: |
        **English:** Splits retroactive COGS into current‑period sales vs prior‑period catch‑up for margin analysis after
        pending approvals. Query `period_start` / `period_end` (inclusive dates, ISO‑8601).
        **Arabic:** تقرير تسوية تكلفة البضاعة المباعة للفترات عند الموافقة على منتجات معلقة.
        **Permission:** `reports.view`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period_start
        in: query
        required: true
        schema:
          type: string
          format: date
        description: 'EN: Range start (inclusive). AR: بداية الفترة.'
        example: '2026-01-01'
      - name: period_end
        in: query
        required: true
        schema:
          type: string
          format: date
        description: 'EN: Range end (inclusive). AR: نهاية الفترة.'
        example: '2026-04-30'
      responses:
        '200':
          description: Success (`data.period` as `YYYY-MM`, bucket totals).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/branches/comparison:
    get:
      operationId: get_reports_branches_comparison
      tags:
      - 20 — Reports
      summary: Branches — comparison
      description: Generated from Postman — `Branches — comparison` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: metric
        in: query
        schema:
          type: string
        example: net
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/branches/health-scorecard:
    get:
      operationId: get_reports_branches_health_scorecard
      tags:
      - 20 — Reports
      summary: Branches — health scorecard
      description: Generated from Postman — `Branches — health scorecard` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/branches/pnl:
    get:
      operationId: get_reports_branches_pnl
      tags:
      - 20 — Reports
      summary: Branches — P&L
      description: Generated from Postman — `Branches — P&L` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/customers/cohorts:
    get:
      operationId: get_reports_customers_cohorts
      tags:
      - 20 — Reports
      summary: Customers — cohorts
      description: Generated from Postman — `Customers — cohorts` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/customers/loyalty:
    get:
      operationId: get_reports_customers_loyalty
      tags:
      - 20 — Reports
      summary: Customers — loyalty
      description: Generated from Postman — `Customers — loyalty` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/customers/rfm:
    get:
      operationId: get_reports_customers_rfm
      tags:
      - 20 — Reports
      summary: Customers — RFM segmentation
      description: Generated from Postman — `Customers — RFM segmentation` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/customers/top:
    get:
      operationId: get_reports_customers_top
      tags:
      - 20 — Reports
      summary: Customers — top customers
      description: Generated from Postman — `Customers — top customers` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: limit
        in: query
        schema:
          type: string
        example: '50'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: |
            Success. **`accounting_truth`** at **root** is mandatory (**Milestone 1.K-a**): `TenantReportsReadStubService` finance slugs are not GL truth.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantFinanceDashboardStubEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/finance/ap-aging:
    get:
      operationId: get_reports_finance_ap_aging
      tags:
      - 20 — Reports
      summary: Finance — AP aging
      description: Generated from Postman — `Finance — AP aging` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: as_of
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: |
            Success. **`accounting_truth`** at **root** is mandatory (**Milestone 1.K-a**): `TenantReportsReadStubService` finance slugs are not GL truth.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantFinanceDashboardStubEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/finance/ar-aging:
    get:
      operationId: get_reports_finance_ar_aging
      tags:
      - 20 — Reports
      summary: Finance — AR aging
      description: Generated from Postman — `Finance — AR aging` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: as_of
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: |
            Success. **`accounting_truth`** at **root** is mandatory (**Milestone 1.K-a**): `TenantReportsReadStubService` finance slugs are not GL truth.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantFinanceDashboardStubEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/finance/bs:
    get:
      operationId: get_reports_finance_bs
      tags:
      - 20 — Reports
      summary: Finance — Balance Sheet
      description: Generated from Postman — `Finance — Balance Sheet` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: as_of
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: |
            Success. **`accounting_truth`** at **root** is mandatory (**Milestone 1.K-a**): `TenantReportsReadStubService` finance slugs are not GL truth.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantFinanceDashboardStubEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/finance/cashflow:
    get:
      operationId: get_reports_finance_cashflow
      tags:
      - 20 — Reports
      summary: Finance — Cashflow
      description: Generated from Postman — `Finance — Cashflow` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: |
            Success. **`accounting_truth`** at **root** is mandatory (**Milestone 1.K-a**): `TenantReportsReadStubService` finance slugs are not GL truth.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantFinanceDashboardStubEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/finance/equity-changes:
    get:
      operationId: get_reports_finance_equity_changes
      tags:
      - 20 — Reports
      summary: Finance — statement of equity changes
      description: Generated from Postman — `Finance — statement of equity changes` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: |
            Success. **`accounting_truth`** at **root** is mandatory (**Milestone 1.K-a**): `TenantReportsReadStubService` finance slugs are not GL truth.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantFinanceDashboardStubEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/finance/pl:
    get:
      operationId: get_reports_finance_pl
      tags:
      - 20 — Reports
      summary: Finance — P&L
      description: Generated from Postman — `Finance — P&L` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: |
            Success. **`accounting_truth`** at **root** is mandatory (**Milestone 1.K-a**): `TenantReportsReadStubService` finance slugs are not GL truth.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantFinanceDashboardStubEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/finance/trial-balance:
    get:
      operationId: get_reports_finance_trial_balance
      tags:
      - 20 — Reports
      summary: Finance — trial balance
      description: Generated from Postman — `Finance — trial balance` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: as_of
        in: query
        schema:
          type: string
        example: '2026-04-30'
      - name: include_archived
        in: query
        schema:
          type: string
        example: 'false'
      responses:
        '200':
          description: |
            Success. **`accounting_truth`** at **root** is mandatory (**Milestone 1.K-a**): `TenantReportsReadStubService` finance slugs are not GL truth.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantFinanceDashboardStubEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/finance/vat-detail:
    get:
      operationId: get_reports_finance_vat_detail
      tags:
      - 20 — Reports
      summary: Finance — VAT detail
      description: Generated from Postman — `Finance — VAT detail` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      - name: vat_code
        in: query
        schema:
          type: string
        example: STD
      responses:
        '200':
          description: |
            Success. **`accounting_truth`** at **root** is mandatory (**Milestone 1.K-a**): `TenantReportsReadStubService` finance slugs are not GL truth.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantFinanceDashboardStubEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/finance/vat-summary:
    get:
      operationId: get_reports_finance_vat_summary
      tags:
      - 20 — Reports
      summary: Finance — VAT summary
      description: Generated from Postman — `Finance — VAT summary` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: basis
        in: query
        schema:
          type: string
        example: accrual
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/inventory/aging:
    get:
      operationId: get_reports_inventory_aging
      tags:
      - 20 — Reports
      summary: Inventory — aging
      description: Generated from Postman — `Inventory — aging` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/inventory/cycle-count-accuracy:
    get:
      operationId: get_reports_inventory_cycle_count_accuracy
      tags:
      - 20 — Reports
      summary: Inventory — cycle count accuracy
      description: Generated from Postman — `Inventory — cycle count accuracy` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/inventory/lot-expiry:
    get:
      operationId: get_reports_inventory_lot_expiry
      tags:
      - 20 — Reports
      summary: Inventory — lot expiry
      description: Generated from Postman — `Inventory — lot expiry` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: within_days
        in: query
        schema:
          type: string
        example: '30'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/inventory/low-stock:
    get:
      operationId: get_reports_inventory_low_stock
      tags:
      - 20 — Reports
      summary: Inventory — low stock & reorder
      description: Generated from Postman — `Inventory — low stock & reorder` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: branch_id
        in: query
        schema:
          type: string
        example: '1'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/inventory/stock-on-hand:
    get:
      operationId: get_reports_inventory_stock_on_hand
      tags:
      - 20 — Reports
      summary: Inventory — stock on hand
      description: Generated from Postman — `Inventory — stock on hand` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: as_of
        in: query
        schema:
          type: string
        example: '2026-04-30'
      - name: branch_id
        in: query
        schema:
          type: string
        example: '1'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/inventory/turns:
    get:
      operationId: get_reports_inventory_turns
      tags:
      - 20 — Reports
      summary: Inventory — turns
      description: Generated from Postman — `Inventory — turns` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/inventory/valuation:
    get:
      operationId: get_reports_inventory_valuation
      tags:
      - 20 — Reports
      summary: Inventory — valuation
      description: Generated from Postman — `Inventory — valuation` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: as_of
        in: query
        schema:
          type: string
        example: '2026-04-30'
      - name: method
        in: query
        schema:
          type: string
        example: weighted_avg
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/inventory/wastage:
    get:
      operationId: get_reports_inventory_wastage
      tags:
      - 20 — Reports
      summary: Inventory — wastage
      description: Generated from Postman — `Inventory — wastage` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/inventory/zero-friction-health:
    get:
      operationId: get_reports_inventory_zero_friction_health
      tags:
      - 20 — Reports
      summary: Inventory — ZF health
      description: |
        **English:** Zero‑Friction health metrics (unknown SKU / backfill posture). **Arabic:** صحة سير عمل بلا احتكاك.
        **Permission:** `reports.view`. See also `GET /reports/zero-friction/pending-approvals-aging`,
        `GET /reports/zero-friction/backfill-needed`, `GET /dashboard/zero-friction`.
        Postman source: `Inventory — ZF health` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/kds-times:
    get:
      operationId: get_reports_kds_times
      tags:
      - 20 — Reports
      summary: KDS times (F&B)
      description: Generated from Postman — `KDS times (F&B)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: branch_id
        in: query
        schema:
          type: string
        example: '1'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/menu-engineering:
    get:
      operationId: get_reports_menu_engineering
      tags:
      - 20 — Reports
      summary: Menu engineering
      description: Generated from Postman — `Menu engineering` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/pay/acquirer-mix:
    get:
      operationId: get_reports_pay_acquirer_mix
      tags:
      - 20 — Reports
      summary: Pay — acquirer mix
      description: Generated from Postman — `Pay — acquirer mix` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/pay/auth-decline-rate:
    get:
      operationId: get_reports_pay_auth_decline_rate
      tags:
      - 20 — Reports
      summary: Pay — auth & decline rate
      description: Generated from Postman — `Pay — auth & decline rate` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/pay/chargeback-rate:
    get:
      operationId: get_reports_pay_chargeback_rate
      tags:
      - 20 — Reports
      summary: Pay — chargeback rate
      description: Generated from Postman — `Pay — chargeback rate` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/pay/mdr-by-scheme:
    get:
      operationId: get_reports_pay_mdr_by_scheme
      tags:
      - 20 — Reports
      summary: Pay — MDR by scheme
      description: Generated from Postman — `Pay — MDR by scheme` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/prep-vs-actual:
    get:
      operationId: get_reports_prep_vs_actual
      tags:
      - 20 — Reports
      summary: Prep vs actual (F&B)
      description: Generated from Postman — `Prep vs actual (F&B)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: branch_id
        in: query
        schema:
          type: string
        example: '1'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/recipe-drift:
    get:
      operationId: get_reports_recipe_drift
      tags:
      - 20 — Reports
      summary: Recipe drift
      description: Generated from Postman — `Recipe drift` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: format
        in: query
        description: Use `csv` to download a CSV export (recipe-drift only).
        schema:
          type: string
          enum:
          - json
          - csv
        example: json
      - name: from
        in: query
        schema:
          type: string
          format: date
      - name: to
        in: query
        schema:
          type: string
          format: date
      - name: branch_id
        in: query
        schema:
          type: string
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/sales/by-branch:
    get:
      operationId: get_reports_sales_by_branch
      tags:
      - 20 — Reports
      summary: Sales — by branch
      description: Generated from Postman — `Sales — by branch` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/sales/by-category:
    get:
      operationId: get_reports_sales_by_category
      tags:
      - 20 — Reports
      summary: Sales — by category
      description: Generated from Postman — `Sales — by category` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/sales/by-channel:
    get:
      operationId: get_reports_sales_by_channel
      tags:
      - 20 — Reports
      summary: Sales — by channel
      description: Generated from Postman — `Sales — by channel` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/sales/by-hour:
    get:
      operationId: get_reports_sales_by_hour
      tags:
      - 20 — Reports
      summary: Sales — by hour (heatmap)
      description: Generated from Postman — `Sales — by hour (heatmap)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: branch_id
        in: query
        schema:
          type: string
        example: '1'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/sales/by-product:
    get:
      operationId: get_reports_sales_by_product
      tags:
      - 20 — Reports
      summary: Sales — by product
      description: Generated from Postman — `Sales — by product` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: limit
        in: query
        schema:
          type: string
        example: '100'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/sales/by-staff:
    get:
      operationId: get_reports_sales_by_staff
      tags:
      - 20 — Reports
      summary: Sales — by staff
      description: Generated from Postman — `Sales — by staff` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/sales/daily:
    get:
      operationId: get_reports_sales_daily
      tags:
      - 20 — Reports
      summary: Sales — daily
      description: Generated from Postman — `Sales — daily` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: from
        in: query
        schema:
          type: string
        example: '2026-04-01'
      - name: to
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/sales/discounts:
    get:
      operationId: get_reports_sales_discounts
      tags:
      - 20 — Reports
      summary: Sales — discounts
      description: Generated from Postman — `Sales — discounts` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/sales/monthly:
    get:
      operationId: get_reports_sales_monthly
      tags:
      - 20 — Reports
      summary: Sales — monthly
      description: Generated from Postman — `Sales — monthly` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: from
        in: query
        schema:
          type: string
        example: 2026-01
      - name: to
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/sales/tenders:
    get:
      operationId: get_reports_sales_tenders
      tags:
      - 20 — Reports
      summary: Sales — tender mix
      description: Generated from Postman — `Sales — tender mix` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/sales/voids-returns:
    get:
      operationId: get_reports_sales_voids_returns
      tags:
      - 20 — Reports
      summary: Sales — voids & returns
      description: Generated from Postman — `Sales — voids & returns` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/sales/weekly:
    get:
      operationId: get_reports_sales_weekly
      tags:
      - 20 — Reports
      summary: Sales — weekly
      description: Generated from Postman — `Sales — weekly` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: from
        in: query
        schema:
          type: string
        example: '2026-01-01'
      - name: to
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/staff/attendance:
    get:
      operationId: get_reports_staff_attendance
      tags:
      - 20 — Reports
      summary: Staff — attendance
      description: Generated from Postman — `Staff — attendance` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/staff/commission:
    get:
      operationId: get_reports_staff_commission
      tags:
      - 20 — Reports
      summary: Staff — commission
      description: Generated from Postman — `Staff — commission` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/staff/productivity:
    get:
      operationId: get_reports_staff_productivity
      tags:
      - 20 — Reports
      summary: Staff — productivity
      description: Generated from Postman — `Staff — productivity` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/staff/saudization:
    get:
      operationId: get_reports_staff_saudization
      tags:
      - 20 — Reports
      summary: Staff — Saudization (Nitaqat band)
      description: Generated from Postman — `Staff — Saudization (Nitaqat band)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/staff/tips:
    get:
      operationId: get_reports_staff_tips
      tags:
      - 20 — Reports
      summary: Staff — tips
      description: Generated from Postman — `Staff — tips` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: branch_id
        in: query
        schema:
          type: string
        example: '1'
      - name: period
        in: query
        schema:
          type: string
        example: 2026-04
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/zero-friction/backfill-needed:
    get:
      operationId: get_reports_zero_friction_backfill_needed
      tags:
      - 20 — Reports
      summary: Zero‑Friction — backfill needed
      description: |
        **English:** Variants with frictionless gaps suggesting Scenario‑2 inventory backfill.
        **Arabic:** تقرير الحاجة لتعبئة مخزون رجعية.
        **Permission:** `reports.view`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reports/zero-friction/pending-approvals-aging:
    get:
      operationId: get_reports_zero_friction_pending_approvals_aging
      tags:
      - 20 — Reports
      summary: Zero‑Friction — pending approvals aging
      description: |
        **English:** Ageing buckets for pending unknown products awaiting manager approval.
        **Arabic:** أعمار الموافقات المعلقة للمنتجات غير المعروفة.
        **Permission:** `reports.view`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /reservations:
    get:
      operationId: get_reservations
      tags:
      - 12 — Dine / Tables & Reservations
      summary: List reservations
      description: Generated from Postman — `List reservations` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: date
        in: query
        schema:
          type: string
        example: '2026-04-26'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_reservations
      tags:
      - 12 — Dine / Tables & Reservations
      summary: Create reservation
      description: Generated from Postman — `Create reservation` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /rma:
    post:
      operationId: post_rma
      tags:
      - 06 — Returns / RMA
      summary: Open RMA
      description: Generated from Postman — `Open RMA` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /rma/{id}/approve:
    post:
      operationId: post_rma_id_approve
      tags:
      - 06 — Returns / RMA
      summary: Approve RMA
      description: Generated from Postman — `Approve RMA` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /rma/{id}/inspect:
    post:
      operationId: post_rma_id_inspect
      tags:
      - 06 — Returns / RMA
      summary: Inspect RMA
      description: Generated from Postman — `Inspect RMA` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /rma/{id}/receive:
    post:
      operationId: post_rma_id_receive
      tags:
      - 06 — Returns / RMA
      summary: Receive RMA
      description: Generated from Postman — `Receive RMA` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /rma/{id}/refund:
    post:
      operationId: post_rma_id_refund
      tags:
      - 06 — Returns / RMA
      summary: Refund RMA
      description: Generated from Postman — `Refund RMA` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /rma/{id}/reject:
    post:
      operationId: post_rma_id_reject
      tags:
      - 06 — Returns / RMA
      summary: Reject RMA
      description: Generated from Postman — `Reject RMA` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /sales:
    post:
      operationId: post_sales
      tags:
      - 05 — Sales / POS
      summary: Capture sale
      description: '`POST /sales` — Record a POS sale: lines (`product_id` as **ULID** string, `qty`, optional `discount`),
        `payments[]` with `tender` (seeded enum) and **`amount` in halalas (integer)**. Requires `Authorization`, `X-Branch-Id`,
        and `Idempotency-Key` (idempotent middleware). **201** on success. See **422** / **409** saved examples. On success, `data` includes **`zatca_status`** (nullable string):
        usually `null` at response time; after the async stub job runs it becomes **`pending_implementation`** until a real
        ZATCA API replaces the stub (`SubmitInvoiceClearanceJob`). Values: `null` \| `pending_implementation` \| `submitted` \| `cleared` \| `rejected`.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - $ref: '#/components/parameters/BranchId'
      responses:
        '201':
          description: Created (`data` payload per implementation; `meta` if present per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: 'Subscription / plan gate only when `error.code` is **`LIMIT_REACHED`**: (1) plan module — e.g. `fields.module_required` = `retail` if the plan excludes retail; (2) quota — `fields.limit_type` = `monthly_transactions` when the billing-period sale count would exceed the cap. **Other** HTTP **402** responses on inventory routes use **different** `error.code` values (never `LIMIT_REACHED`); clients must discriminate by `error.code` (`docs/current/BACKEND-CONVENTIONS.md`).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubscriptionLimitReachedResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
      x-current-state: 'Tier A (float money): docs/handoff/FLOAT-MONEY-API-AUDIT.md §1 #1 — `vat` in 201 response. Tier B1
        (envelope gap): same file §2 B1 — `total` and line totals until Track B.'
      x-target-state: 'Amended D2: monetary fields use components.schemas.Money after Track B.'
  /sales/{id}/receipt:
    get:
      operationId: get_sales_id_receipt
      tags:
      - 05 — Sales / POS
      summary: Receipt
      description: '`GET /sales/{id}/receipt` — HTML/PDF receipt for archive/share (D6 hybrid).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - name: format
        in: query
        schema:
          type: string
        example: html
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /sales/{id}/share:
    post:
      operationId: post_sales_id_share
      tags:
      - 05 — Sales / POS
      summary: Share receipt
      description: '`POST /sales/{id}/share` — Server-side share pipeline (D7: whatsapp, email in v1).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /sales/{id}/void:
    post:
      operationId: post_sales_id_void
      tags:
      - 05 — Sales / POS
      summary: Void sale
      description: |
        `POST /sales/{id}/void` — Void a captured sale per policy. Requires idempotency key.
        **Manager PIN (2.A-1 / G3):** **`manager_pin`** is **required** and must match **`config('retail_pos.manager_pin')`** (env **`RETAIL_POS_MANAGER_PIN`**, default **`0000`** in local templates).
        **Branch scoping:** `perm:sales.void,branch` — `X-Branch-Id` required for multi-branch users (422 if omitted).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/BranchId'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - reason
              - manager_pin
              properties:
                reason:
                  type: string
                  maxLength: 100
                manager_pin:
                  type: string
                  maxLength: 64
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed (includes incorrect **`manager_pin`**).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /setup/kyc:
    post:
      operationId: post_setup_kyc
      tags:
      - 02 — Tenancy & Onboarding
      summary: 'Tenant: KYC submit'
      description: 'Generated from Postman — `Tenant: KYC submit` (`docs/postman/DALSEEN.postman_collection.json`).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /shifts/close:
    post:
      operationId: post_shifts_close
      tags:
      - 05 — Sales / POS
      summary: Close shift
      description: '`POST /shifts/{id}/close` — Close shift; reconciles tenders per shift rules.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
      x-current-state: documented at docs/handoff/FLOAT-MONEY-API-AUDIT.md (Tier A — float or major-unit money in live JSON
        until Track B).
      x-target-state: 'Amended D2: monetary fields use components.schemas.Money after Track B.'
  /shifts/open:
    post:
      operationId: post_shifts_open
      tags:
      - 05 — Sales / POS
      summary: Open shift
      description: '`POST /shifts/open` — Open cashier shift for a register/branch.'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - $ref: '#/components/parameters/BranchId'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /signup:
    post:
      operationId: post_signup
      tags:
      - 02 — Tenancy & Onboarding
      summary: Public signup
      description: Generated from Postman — `Public signup` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security: []
  /spot-counts:
    post:
      operationId: post_spot_counts
      tags:
      - 04 — Inventory
      summary: Spot count
      description: Generated from Postman — `Spot count` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - $ref: '#/components/parameters/BranchId'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /stock-adjustments:
    post:
      operationId: post_stock_adjustments
      tags:
      - 04 — Inventory
      summary: Stock adjustment
      description: Generated from Postman — `Stock adjustment` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - $ref: '#/components/parameters/BranchId'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /stock-counts:
    post:
      operationId: post_stock_counts
      tags:
      - 04 — Inventory
      summary: Stock count (full)
      description: Generated from Postman — `Stock count (full)` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - $ref: '#/components/parameters/BranchId'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /stock-levels:
    get:
      operationId: get_stock_levels
      tags:
      - 04 — Inventory
      summary: Stock levels
      description: |
        Generated from Postman — `Stock levels` (`docs/postman/DALSEEN.postman_collection.json`).
        **Branch scoping:** requires `perm:inventory.stock_levels.view,branch` — send `X-Branch-Id` when the user belongs to more than one branch (422 `VALIDATION_FAILED` on `error.fields.X-Branch-Id` if omitted). Single-branch users may omit the header (server infers the branch).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/BranchId'
      - name: branch_id
        in: query
        schema:
          type: string
        example: '1'
      - name: product_id
        in: query
        schema:
          type: string
        example: '101'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Missing or invalid `X-Branch-Id` when required (multi-branch user).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /stock-movements:
    get:
      operationId: get_stock_movements
      tags:
      - 04 — Inventory
      summary: Stock movements
      description: |
        Generated from Postman — `Stock movements` (`docs/postman/DALSEEN.postman_collection.json`).
        **Branch scoping:** `perm:inventory.stock_movements.view,branch` — `X-Branch-Id` required for multi-branch users (422 if omitted); single-branch users may omit it.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/BranchId'
      - name: from
        in: query
        schema:
          type: string
        example: '2026-04-01'
      - name: product_id
        in: query
        schema:
          type: string
        example: '101'
      - name: to
        in: query
        schema:
          type: string
        example: '2026-04-30'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Missing or invalid `X-Branch-Id` when required (multi-branch user).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /supplier-invoices:
    post:
      operationId: post_supplier_invoices
      tags:
      - 08 — Suppliers & Purchasing
      summary: Supplier invoice
      description: Generated from Postman — `Supplier invoice` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /supplier-payments:
    post:
      operationId: post_supplier_payments
      tags:
      - 08 — Suppliers & Purchasing
      summary: Supplier payment
      description: Generated from Postman — `Supplier payment` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /suppliers:
    get:
      operationId: get_suppliers
      tags:
      - 08 — Suppliers & Purchasing
      summary: List suppliers
      description: Generated from Postman — `List suppliers` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_suppliers
      tags:
      - 08 — Suppliers & Purchasing
      summary: Create supplier
      description: Generated from Postman — `Create supplier` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /support/tickets:
    get:
      operationId: get_support_tickets
      tags:
      - 19 — Platform & Billing
      summary: Support tickets
      description: Generated from Postman — `Support tickets` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_support_tickets
      tags:
      - 19 — Platform & Billing
      summary: Create support ticket
      description: Generated from Postman — `Create support ticket` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /support/tickets/{ticket}:
    get:
      operationId: get_support_tickets_ticket
      tags:
      - 19 — Platform & Billing
      summary: Show support ticket (portal)
      description: |
        **Stage 6.A-4:** Returns a **`service_requests`** row scoped to the tenant with **`details.source = support_portal`**. Requires `support.tickets.read`.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: ticket
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Ticket not found or not a portal ticket
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /synthetic-grns:
    post:
      operationId: post_synthetic_grns
      tags:
      - 04 — Inventory
      summary: Synthetic GRN
      description: |
        Generated from Postman — `Synthetic GRN` (`docs/postman/DALSEEN.postman_collection.json`).
        **Branch scoping:** `perm:inventory.synthetic_grns.create,branch` — include `X-Branch-Id` when the user has multiple branches (422 if omitted).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/BranchId'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /tables:
    get:
      operationId: get_tables
      tags:
      - 12 — Dine / Tables & Reservations
      summary: List tables
      description: Generated from Postman — `List tables` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: branch_id
        in: query
        schema:
          type: string
        example: '1'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_tables
      tags:
      - 12 — Dine / Tables & Reservations
      summary: Create table
      description: Generated from Postman — `Create table` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /tables/{id}/move:
    post:
      operationId: post_tables_id_move
      tags:
      - 12 — Dine / Tables & Reservations
      summary: Move party
      description: Generated from Postman — `Move party` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /tables/{id}/seat:
    post:
      operationId: post_tables_id_seat
      tags:
      - 12 — Dine / Tables & Reservations
      summary: Seat party
      description: Generated from Postman — `Seat party` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /tenders:
    get:
      operationId: get_tenders
      tags:
      - 05 — Sales / POS
      summary: List tenders
      description: '`GET /tenders` — Allowed payment tenders for the branch (D5 closed set).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /transfers:
    post:
      operationId: post_transfers
      tags:
      - 04 — Inventory
      summary: Stock transfer
      description: |
        Generated from Postman — `Stock transfer` (`docs/postman/DALSEEN.postman_collection.json`).
        **Branch scoping:** `perm:inventory.transfers.create,branch` — `X-Branch-Id` required for multi-branch users (422 if omitted); denotes acting branch context.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/BranchId'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /users:
    get:
      operationId: get_users
      tags:
      - 02 — Tenancy & Onboarding
      summary: List tenant users
      description: Paginated users for the authenticated company (`permission:users.view`). Response `meta` uses `page`,
        `per_page`, `total` (not `PaginationMeta.current_page`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: q
        in: query
        description: Case-insensitive substring match on `name` or `email`.
        schema:
          type: string
          maxLength: 255
      - name: per_page
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 25
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantUserListResponse'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_users
      tags:
      - 02 — Tenancy & Onboarding
      summary: Create tenant user
      description: Creates a user with Spatie roles and `branch_user` rows (`permission:users.create`). Requires `Idempotency-Key`. After auth middleware, `limit:max_users` runs when **`LIMITS_ENFORCED`** / `config('limits.enforced')` is true; over cap → **402** `LIMIT_REACHED` (`SubscriptionLimitReachedResponse`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StoreTenantUserBody'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantUserEnvelope'
        '400':
          description: Missing or blank `Idempotency-Key` (`IDEMPOTENCY_KEY_REQUIRED`)
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: Subscription user cap (`error.code` = `LIMIT_REACHED`; typically `fields.limit_type` = `max_users` plus `current`, `limit`, `plan_code`, `upgrade_required`). Emitted only when limits enforcement is on; not inventory **402**.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubscriptionLimitReachedResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /users/{tenantUser}:
    get:
      operationId: get_users_tenantUser
      tags:
      - 02 — Tenancy & Onboarding
      summary: Show tenant user
      description: '`tenantUser` must belong to the caller''s company (`permission:users.view`).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/TenantUserId'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantUserEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    patch:
      operationId: patch_users_tenantUser
      tags:
      - 02 — Tenancy & Onboarding
      summary: Update tenant user
      description: Partial update; cannot set `is_active` to false for self (`permission:users.update`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/TenantUserId'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PatchTenantUserBody'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantUserEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    delete:
      operationId: delete_users_tenantUser
      tags:
      - 02 — Tenancy & Onboarding
      summary: Soft-delete tenant user
      description: Cannot delete own account (`permission:users.delete`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/TenantUserId'
      responses:
        '204':
          description: No content
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed (e.g. self-delete)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /users/{tenantUser}/roles:
    put:
      operationId: put_users_tenantUser_roles
      tags:
      - 02 — Tenancy & Onboarding
      summary: Sync Spatie roles for user
      description: Replaces role assignments (`syncRoles`); updates `branch_user.primary_role` from first role name (`permission:users.assign_roles`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - $ref: '#/components/parameters/TenantUserId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SyncUserRolesBody'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantUserEnvelope'
        '400':
          description: Missing or blank `Idempotency-Key`
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /permissions:
    get:
      operationId: get_permissions
      tags:
      - 02 — Tenancy & Onboarding
      summary: List Spatie permissions (sanctum guard)
      description: All permission names registered for `guard_name = sanctum` (`permission:permissions.view`). Use when building
        role permission pickers; permissions are **global** (not per-tenant).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantPermissionListEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /roles:
    get:
      operationId: get_roles
      tags:
      - 02 — Tenancy & Onboarding
      summary: List Spatie roles (sanctum guard)
      description: All roles for `guard_name = sanctum` with eager-loaded permission names (`permission:roles.view`). Roles are **global**
        (not per-tenant); use delete only when no user holds the role.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantRoleListEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    post:
      operationId: post_roles
      tags:
      - 02 — Tenancy & Onboarding
      summary: Create role with permissions
      description: Creates a `sanctum` role and syncs permissions that must already exist (`permission:roles.create`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StoreRoleBody'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantRoleEnvelope'
        '400':
          description: Missing or blank `Idempotency-Key`
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /roles/{role}:
    get:
      operationId: get_roles_role
      tags:
      - 02 — Tenancy & Onboarding
      summary: Show role
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/RoleId'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantRoleEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    patch:
      operationId: patch_roles_role
      tags:
      - 02 — Tenancy & Onboarding
      summary: Update role
      description: Optional rename and/or permission sync (`permission:roles.update`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/RoleId'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PatchRoleBody'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantRoleEnvelope'
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
    delete:
      operationId: delete_roles_role
      tags:
      - 02 — Tenancy & Onboarding
      summary: Delete role (only when unassigned)
      description: '`422` when any user still has this role (`permission:roles.delete`).'
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/RoleId'
      responses:
        '204':
          description: No content
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Role still assigned to users
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /users/invite:
    post:
      operationId: post_users_invite
      tags:
      - 02 — Tenancy & Onboarding
      summary: Invite user (inactive until activation flow)
      description: Creates an **inactive** user with random password, assigns roles/branches (`permission:users.invite`). Requires `Idempotency-Key`. Same **`limit:max_users`** / **`LIMITS_ENFORCED`** behavior as `POST /users`. Duplicate idempotency key with same body may return **200** with existing user.
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InviteTenantUserBody'
      responses:
        '200':
          description: Idempotent replay — same key + body as prior successful invite
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InviteTenantUserResponse'
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InviteTenantUserResponse'
        '400':
          description: Missing or blank `Idempotency-Key`
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: Same as `POST /users` — `LIMIT_REACHED` when active user count would exceed **`max_users`** under enforcement.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubscriptionLimitReachedResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /waitlist:
    post:
      operationId: post_waitlist
      tags:
      - 12 — Dine / Tables & Reservations
      summary: Add to waitlist
      description: Generated from Postman — `Add to waitlist` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /wastage:
    post:
      operationId: post_wastage
      tags:
      - 04 — Inventory
      summary: Wastage
      description: Generated from Postman — `Wastage` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - $ref: '#/components/parameters/IdempotencyKey'
      - $ref: '#/components/parameters/BranchId'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
  /webhooks/acquirers/{id}/chargebacks:
    post:
      operationId: post_webhooks_acquirers_id_chargebacks
      tags:
      - 16 — Pay (PSP)
      summary: Chargeback inbound
      description: Generated from Postman — `Chargeback inbound` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: id
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `id` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security: []
  /webhooks/aggregator/{partner}:
    post:
      operationId: post_webhooks_aggregator_partner
      tags:
      - 15 — Dine / Delivery & Aggregators
      summary: Aggregator webhook
      description: Generated from Postman — `Aggregator webhook` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: partner
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `partner` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security: []
  /webhooks/marketplaces/{partner}:
    post:
      operationId: post_webhooks_marketplaces_partner
      tags:
      - 10 — E-com & Marketplaces
      summary: Marketplace order webhook
      description: Generated from Postman — `Marketplace order webhook` (`docs/postman/DALSEEN.postman_collection.json`).
      parameters:
      - $ref: '#/components/parameters/AcceptLanguage'
      - name: partner
        in: path
        required: true
        schema:
          type: string
        description: Path parameter `partner` (see Laravel routes + Postman examples).
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Success (`data` / `meta` envelope per `docs/current/BACKEND-CONVENTIONS.md`).
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '422':
          description: Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security: []
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: Laravel Sanctum plain-text bearer token (not JWT). Obtain via `POST /auth/login` or `POST /platform/auth/login`.
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      description: State-mutating routes use the `idempotent` middleware (`docs/current/BACKEND-CONVENTIONS.md` § Idempotency). Send a
        fresh **UUIDv4** per new intent (Postman `{{$guid}}`); reuse only for safe retries of the **same** request body.
      schema:
        type: string
        format: uuid
        pattern: ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$
        example: 550e8400-e29b-41d4-a716-446655440000
    BranchId:
      name: X-Branch-Id
      in: header
      required: true
      description: Branch ULID for branch-scoped writes (DECISIONS D1 / `EnsureBranchContext`).
      schema:
        $ref: '#/components/schemas/ResourceId'
    AcceptLanguage:
      name: Accept-Language
      in: header
      required: false
      description: Drives `App::setLocale()` (`docs/current/BACKEND-CONVENTIONS.md` § Headers).
      schema:
        type: string
        enum:
        - ar
        - en
        default: ar
    TenantUserId:
      name: tenantUser
      in: path
      required: true
      description: Tenant user primary key; must belong to the authenticated company.
      schema:
        $ref: '#/components/schemas/GlobalIntegerId'
    RoleId:
      name: role
      in: path
      required: true
      description: Spatie `roles.id` for `guard_name = sanctum`.
      schema:
        $ref: '#/components/schemas/GlobalIntegerId'
  schemas:
    ErrorResponse:
      type: object
      required:
      - error
      properties:
        error:
          type: object
          required:
          - code
          - message_ar
          - message_en
          - fields
          properties:
            code:
              type: string
            message_ar:
              type: string
            message_en:
              type: string
            fields:
              type: object
              additionalProperties:
                type: array
                items:
                  type: string
    SubscriptionLimitReachedResponse:
      type: object
      required:
      - error
      description: 'HTTP **402** body when the subscription or plan gate fails with `error.code` = **`LIMIT_REACHED`** only. `error.fields` is a **mixed** object (quota keys such as `limit_type`, `current`, `limit`, `plan_code`, `upgrade_required`, `usage_percent`; module gate `module_required` with module code string, e.g. `retail` for `POST /sales`; or `module` + `company_module_inactive` when the plan allows the module but the tenant has toggled it off). Inventory and other prerequisite **402** responses use **different** `error.code` strings (e.g. `SYNTHETIC_GRN_REQUIRES_FRICTIONLESS_INVENTORY`); they are **not** this schema—clients must branch on `error.code` per `docs/current/BACKEND-CONVENTIONS.md`.'
      properties:
        error:
          type: object
          required:
          - code
          - message_ar
          - message_en
          - fields
          properties:
            code:
              type: string
              enum:
              - LIMIT_REACHED
            message_ar:
              type: string
            message_en:
              type: string
            fields:
              type: object
              additionalProperties: true
              description: 'Quota breach: `limit_type`, `current`, `limit`, `plan_code`, `upgrade_required`, optional `usage_percent`. Plan module gate: `module_required` (module code). Company module off: `module`, `company_module_inactive`.'
    PlatformTenantLimitOverrideStoreBody:
      type: object
      required:
      - limit_type
      - reason
      properties:
        limit_type:
          type: string
          description: One of `PlanLimitType` string values (e.g. `max_users`, `max_branches`, `max_products`, `monthly_transactions`, `daily_api_requests`, `storage_mb`).
        override_value:
          type: integer
          nullable: true
          minimum: 0
        reason:
          type: string
          maxLength: 500
        expires_at:
          type: string
          format: date
          nullable: true
    PlatformPlanStoreBody:
      type: object
      required:
      - code
      - name_ar
      - name_en
      - price_monthly_minor
      properties:
        code:
          type: string
          maxLength: 50
          pattern: '^[a-z0-9][a-z0-9_\\-]*$'
        name_ar:
          type: string
          maxLength: 255
        name_en:
          type: string
          maxLength: 255
        description_ar:
          type: string
          nullable: true
        description_en:
          type: string
          nullable: true
        price_monthly_minor:
          type: integer
          minimum: 0
        price_monthly_currency:
          type: string
          minLength: 3
          maxLength: 3
        price_yearly_minor:
          type: integer
          nullable: true
          minimum: 0
        price_yearly_currency:
          type: string
          minLength: 3
          maxLength: 3
        is_active:
          type: boolean
        sort_order:
          type: integer
          minimum: 0
        limits:
          type: array
          items:
            $ref: '#/components/schemas/PlatformPlanLimitRowInput'
        modules:
          type: array
          description: When supplied, must include every product module code (`retail`, `dine`, `pay`, `accounting`, `hr`).
          items:
            $ref: '#/components/schemas/PlatformPlanModuleRowInput'
        feature_access:
          type: array
          items:
            type: object
            required:
            - catalog_feature_id
            - is_included
            properties:
              catalog_feature_id:
                type: string
              is_included:
                type: boolean
    PlatformPlanPatchBody:
      type: object
      properties:
        name_ar:
          type: string
          maxLength: 255
        name_en:
          type: string
          maxLength: 255
        description_ar:
          type: string
          nullable: true
        description_en:
          type: string
          nullable: true
        price_monthly_minor:
          type: integer
          minimum: 0
        price_monthly_currency:
          type: string
          minLength: 3
          maxLength: 3
        price_yearly_minor:
          type: integer
          nullable: true
          minimum: 0
        price_yearly_currency:
          type: string
          minLength: 3
          maxLength: 3
        is_active:
          type: boolean
        sort_order:
          type: integer
          minimum: 0
    PlatformPlanLimitRowInput:
      type: object
      required:
      - limit_type
      properties:
        limit_type:
          type: string
        limit_value:
          type: integer
          nullable: true
          minimum: 0
        notes:
          type: string
          maxLength: 500
          nullable: true
    PlatformPlanModuleRowInput:
      type: object
      required:
      - module
      - is_included
      properties:
        module:
          type: string
        is_included:
          type: boolean
    PlatformPlanSyncLimitsBody:
      type: object
      required:
      - limits
      properties:
        limits:
          type: array
          items:
            $ref: '#/components/schemas/PlatformPlanLimitRowInput'
    PlatformPlanSyncModulesBody:
      type: object
      required:
      - modules
      properties:
        modules:
          type: array
          items:
            $ref: '#/components/schemas/PlatformPlanModuleRowInput'
    PlatformPlanSyncFeaturesBody:
      type: object
      required:
      - features
      properties:
        features:
          type: array
          items:
            type: object
            required:
            - catalog_feature_id
            - is_included
            properties:
              catalog_feature_id:
                type: string
              is_included:
                type: boolean
    PlatformDiscountCodeStoreBody:
      type: object
      required:
      - code
      - name_ar
      - name_en
      properties:
        code:
          type: string
          maxLength: 64
        name_ar:
          type: string
          maxLength: 255
        name_en:
          type: string
          maxLength: 255
        percent_off:
          type: integer
          nullable: true
          minimum: 0
          maximum: 100
        amount_off_minor:
          type: integer
          nullable: true
          minimum: 0
        currency_code:
          type: string
          nullable: true
          minLength: 3
          maxLength: 3
        valid_from:
          type: string
          format: date
          nullable: true
        valid_to:
          type: string
          format: date
          nullable: true
        max_uses:
          type: integer
          nullable: true
          minimum: 1
        notes:
          type: string
          nullable: true
        is_active:
          type: boolean
    PlatformDiscountCodeUpdateBody:
      type: object
      properties:
        name_ar:
          type: string
          maxLength: 255
        name_en:
          type: string
          maxLength: 255
        percent_off:
          type: integer
          nullable: true
        amount_off_minor:
          type: integer
          nullable: true
        currency_code:
          type: string
          nullable: true
        valid_from:
          type: string
          format: date
          nullable: true
        valid_to:
          type: string
          format: date
          nullable: true
        max_uses:
          type: integer
          nullable: true
        notes:
          type: string
          nullable: true
        is_active:
          type: boolean
    ActivePlanCatalogRow:
      type: object
      required:
      - code
      - name
      description: Slim row from `ListActivePlansService` for `GET /plans` (active, non-archived plans only).
      properties:
        code:
          type: string
        name:
          type: string
          description: Resolved display name (`name_en`, else `name_ar`, else `code`).
    PlatformTenantSubscriptionQuoteBody:
      type: object
      required:
      - plan_code
      properties:
        plan_code:
          type: string
          maxLength: 80
        addons:
          type: array
          items:
            type: object
            properties:
              code:
                type: string
                maxLength: 80
              qty:
                type: integer
                minimum: 0
                maximum: 10000
        discount_code:
          type: string
          nullable: true
          maxLength: 64
    PlatformTenantSubscriptionApplyBody:
      allOf:
      - $ref: '#/components/schemas/PlatformTenantSubscriptionQuoteBody'
    PlatformSubscriptionQuoteTotals:
      type: object
      required:
      - plan_code
      - currency_code
      - before_discount_subtotal_minor
      - discount_total_minor
      - subtotal_minor
      - vat_minor
      - total_minor
      properties:
        plan_code:
          type: string
        currency_code:
          type: string
        before_discount_subtotal_minor:
          type: integer
          format: int64
        discount_total_minor:
          type: integer
          format: int64
        subtotal_minor:
          type: integer
          format: int64
        vat_minor:
          type: integer
          format: int64
        total_minor:
          type: integer
          format: int64
    PlatformOpsTruth:
      type: object
      description: |
        **Platform internal-ops truth (Milestone 1.J + 1.F-1 + 1.F-2/3 + 1.F-4 + 1.G-1):** Nested as `data.platform_ops_truth`.
        See **`docs/current/PLATFORM-OPS-CONTRACT.md`**.

        - **`data_source: live`** + **`sla_status: non_sla`** — persisted or DB-backed reads (**health**, **incidents**, **incident metrics**).
        - **`data_source: live`** + **`sla_status: non_sla`** + **`scope: cross_tenant_subscription_rollups`** — **`GET /platform/analytics/revenue`**.
        - **`scope: cross_tenant_subscription_retention`** — **`GET /platform/analytics/retention`** (**1.G-2**).
        - **`scope: cross_tenant_signup_funnel`** — **`GET /platform/analytics/acquisition`** (**1.G-3**).
        - **`data_source: non_sla`** + **`implementation: stub`** — **release promote/rollback** (no CI/CD persistence); includes **`recommendation`** and **`documented_in`**.
        - **`data_source: stub`** + **`sla_status: non_sla`** — legacy generic stub merge until a route is upgraded.
      required:
      - data_source
      properties:
        data_source:
          type: string
          enum:
          - stub
          - live
          - non_sla
        sla_status:
          type: string
          nullable: true
          enum:
          - non_sla
        implementation:
          type: string
          nullable: true
          enum:
          - stub
        recommendation:
          type: string
          nullable: true
        documented_in:
          type: string
          nullable: true
        scope:
          type: string
          nullable: true
    PlatformSuccessEnvelopeStubOpsData:
      type: object
      description: |
        Success JSON for stub-backed platform internal-ops routes (Milestone 1.J). `data` always includes
        **`platform_ops_truth`** alongside domain fields (`services`, release fields, incident fields, etc.).
      required:
      - data
      additionalProperties: true
      properties:
        data:
          type: object
          required:
          - platform_ops_truth
          additionalProperties: true
          properties:
            platform_ops_truth:
              $ref: '#/components/schemas/PlatformOpsTruth'
    PlatformCutoverReadinessEnvelope:
      type: object
      required:
      - data
      properties:
        data:
          $ref: '#/components/schemas/PlatformCutoverReadinessData'
    PlatformCutoverReadinessData:
      type: object
      required:
      - checklist_version
      - rollup_status
      - checks
      - cutover_truth
      properties:
        checklist_version:
          type: integer
          description: Contract version for the readiness payload shape.
        rollup_status:
          type: string
          enum:
          - pass
          - warn
          - fail
          description: Worst severity across live checks (`pass` < `warn` < `fail`); static roadmap rows do not upgrade severity.
        checks:
          type: array
          items:
            $ref: '#/components/schemas/PlatformCutoverReadinessCheck'
        cutover_truth:
          type: object
          required:
          - data_source
          - sla_status
          - generated_at
          properties:
            data_source:
              type: string
              enum:
              - live_catalog
            sla_status:
              type: string
              enum:
              - non_sla
            generated_at:
              type: string
              format: date-time
    PlatformCutoverReadinessCheck:
      type: object
      required:
      - id
      - status
      - summary_en
      - summary_ar
      properties:
        id:
          type: string
        status:
          type: string
          description: Live checks use `pass`/`warn`/`fail`; static rows use `implemented`, `deferred`, `external_partner`, etc.
        summary_en:
          type: string
        summary_ar:
          type: string
        metrics:
          type: object
          additionalProperties: true
          description: Present on live checks; omitted on static roadmap rows.
    PlatformCutoverWriteFreezeEnvelope:
      type: object
      required:
      - data
      properties:
        data:
          type: object
          required:
          - global_freeze_writes
          - config_key
          - env_var
          - interpretation_en
          - interpretation_ar
          - cutover_truth
          properties:
            global_freeze_writes:
              type: boolean
            config_key:
              type: string
              example: cutover.global_freeze_writes
            env_var:
              type: string
              example: CUTOVER_GLOBAL_FREEZE_WRITES
            interpretation_en:
              type: string
            interpretation_ar:
              type: string
            cutover_truth:
              type: object
              required:
              - data_source
              - sla_status
              - generated_at
              properties:
                data_source:
                  type: string
                  enum:
                  - config
                sla_status:
                  type: string
                  enum:
                  - non_sla
                generated_at:
                  type: string
                  format: date-time
    AccountingTruth:
      type: object
      description: |
        Tenant accounting read-path contract. **`stub`** + **`non_sla`** + optional **`replacement_milestone=1.K`**: stub-backed (**1.K-a**).
        **`live`** + **`production`**: GL-backed from posted **`journal_lines`** (**1.K-b-1** trial-balance; **1.K-b-2** drill; **1.K-b-3** balance sheet; **1.K-b-4** P&L); **`replacement_milestone`** is omitted for live. **`POST /bank/reconcile`** (**1.K-c**) uses **`live`** / **`production`** with statement-line sums + GL book balance (variance JE posting deferred).         **`GET …/accounting/customers/{id}/ledger`** (**1.K-d-0**) and **`GET …/accounting/customers/{id}/statement`** JSON numbers (**1.K-d-1**, same **`BuildTenantCustomerArActivityService`**) use **`live`** / **`production`** for **operational AR** rows (**sales** / **AR receipts** / **credit notes** / **write-offs**), not necessarily GL-posted lines; statement PDF (**1.K-d-2**) is **live** HTML→PDF. **`POST …/accounting/opening-balances/import`** (**1.K-e**) posts via **`PostOpeningBalancesService`** (same **`journal_lines`** truth as manual **`POST …/opening-balances`**).
      required:
      - data_source
      - sla_status
      properties:
        data_source:
          type: string
          enum:
          - stub
          - live
        sla_status:
          type: string
          enum:
          - non_sla
          - production
        replacement_milestone:
          type: string
          enum:
          - '1.K'
          nullable: true
    AccountingSuccessEnvelopeDataWithTruth:
      type: object
      description: |
        Tenant JSON envelope where **`data`** includes **`accounting_truth`**. Stub reports (**1.K-a**) use **`stub`** / **`non_sla`**. **`trial-balance`**, **`drill`**, **`bs`**, **`pl`**, **`POST /bank/reconcile`**, **`GET …/accounting/customers/{id}/ledger`**, **`GET …/accounting/customers/{id}/statement`** (JSON + **1.K-d-2** PDF), and **`POST …/accounting/opening-balances/import`** use **`live`** / **`production`** (**1.K-b-1**–**1.K-b-4**, **1.K-c**, **1.K-d-0**, **1.K-d-1** + **1.K-d-2**, **1.K-e**).
      required:
      - data
      additionalProperties: true
      properties:
        data:
          type: object
          required:
          - accounting_truth
          additionalProperties: true
          properties:
            accounting_truth:
              $ref: '#/components/schemas/AccountingTruth'
    TenantFinanceDashboardStubEnvelope:
      type: object
      description: |
        **`GET /reports/finance/*`** stub envelope (**1.K-a**): `data` is a **paginated row array**; **`accounting_truth`** is at the **root**
        (not inside `data`) because `data` must remain a JSON array.
      required:
      - data
      - meta
      - accounting_truth
      additionalProperties: true
      properties:
        data:
          type: array
          items: {}
        meta:
          type: object
          additionalProperties: true
        accounting_truth:
          $ref: '#/components/schemas/AccountingTruth'
    PlatformInvoiceLineItem:
      type: object
      required:
      - id
      - description
      - quantity
      - unit_price_minor
      - currency_code
      - total_minor
      properties:
        id:
          type: string
        description:
          type: string
        quantity:
          type: string
          description: Decimal quantity as string (matches API JSON).
        unit_price_minor:
          type: integer
          format: int64
        currency_code:
          type: string
        total_minor:
          type: integer
          format: int64
    TenantPlatformInvoiceDetail:
      type: object
      required:
      - id
      - invoice_number
      - status
      - currency_code
      - before_discount_subtotal_minor
      - discount_total_minor
      - subtotal_minor
      - vat_minor
      - total_minor
      - paid_minor
      - lines
      properties:
        id:
          type: string
        invoice_number:
          type: string
        status:
          type: string
        issued_at:
          type: string
          format: date
          nullable: true
        due_at:
          type: string
          format: date
          nullable: true
        currency_code:
          type: string
        before_discount_subtotal_minor:
          type: integer
          format: int64
        discount_total_minor:
          type: integer
          format: int64
        subtotal_minor:
          type: integer
          format: int64
        vat_minor:
          type: integer
          format: int64
        total_minor:
          type: integer
          format: int64
        paid_minor:
          type: integer
          format: int64
        discount_code:
          type: string
          nullable: true
        lines:
          type: array
          items:
            $ref: '#/components/schemas/PlatformInvoiceLineItem'
    PlatformTenantInvoiceDetail:
      type: object
      required:
      - id
      - company_id
      - invoice_number
      - status
      - currency_code
      - before_discount_subtotal_minor
      - discount_total_minor
      - subtotal_minor
      - vat_minor
      - total_minor
      - paid_minor
      - lines
      properties:
        id:
          type: string
        company_id:
          type: string
        invoice_number:
          type: string
        status:
          type: string
        issued_at:
          type: string
          format: date
          nullable: true
        due_at:
          type: string
          format: date
          nullable: true
        currency_code:
          type: string
        before_discount_subtotal_minor:
          type: integer
          format: int64
        discount_total_minor:
          type: integer
          format: int64
        subtotal_minor:
          type: integer
          format: int64
        vat_minor:
          type: integer
          format: int64
        total_minor:
          type: integer
          format: int64
        paid_minor:
          type: integer
          format: int64
        applied_platform_discount_code_id:
          type: string
          nullable: true
        applied_discount_code:
          type: string
          nullable: true
        discount_code_name_en:
          type: string
          nullable: true
        lines:
          type: array
          items:
            $ref: '#/components/schemas/PlatformInvoiceLineItem'
    VarianceCheckCode:
      type: string
      description: 'EN: ZF variance code. AR: رمز فحص التباين (وضع بلا احتكاك).'
      enum:
      - FUTURE_INVOICE_DATE
      - INVALID_COST
      - INVALID_QUANTITY
      - QUANTITY_INSUFFICIENT
      - QUANTITY_UNUSUALLY_HIGH
      - COST_HIGHER_THAN_SALE_PRICE
      - DUPLICATE_BARCODE
      - NEGATIVE_STOCK_AFTER_BACKFILL
      - OLD_PENDING_PRODUCT
    VarianceEntry:
      type: object
      required:
      - code
      - severity
      - message_ar
      - message_en
      - details
      properties:
        code:
          $ref: '#/components/schemas/VarianceCheckCode'
        severity:
          type: string
          enum:
          - error
          - warning
        message_ar:
          type: string
        message_en:
          type: string
        details:
          type: object
          additionalProperties: true
        suggestion_ar:
          type: string
          description: 'AR: اقتراح للمستخدم (تحذيرات فقط). EN: Suggestion (warnings only).'
        suggestion_en:
          type: string
          description: 'EN: Suggestion (warnings only). AR: اقتراح (تحذيرات فقط).'
    VarianceErrorResponse:
      type: object
      required:
      - error
      properties:
        error:
          type: object
          required:
          - code
          - message_en
          - message_ar
          - errors
          properties:
            code:
              type: string
              enum:
              - VARIANCE_ERRORS
            message_en:
              type: string
              example: One or more variance checks failed.
            message_ar:
              type: string
            errors:
              type: array
              items:
                $ref: '#/components/schemas/VarianceEntry'
    VarianceWarningResponse:
      type: object
      required:
      - error
      properties:
        error:
          type: object
          required:
          - code
          - message_en
          - message_ar
          - warnings
          - hint
          properties:
            code:
              type: string
              enum:
              - VARIANCE_WARNINGS
            message_en:
              type: string
            message_ar:
              type: string
            warnings:
              type: array
              items:
                $ref: '#/components/schemas/VarianceEntry'
            hint:
              type: string
              description: 'EN: For approve, add `?force=true` to bypass warnings after review; for inventory backfill,
                same flag records despite warnings. AR: أضف `?force=true` للمتابعة بعد مراجعة التحذيرات.'
              example: Add ?force=true to approve despite warnings.
    Money:
      type: object
      required:
      - amount_minor
      - currency_code
      properties:
        amount_minor:
          type: integer
          format: int64
          example: 19320
        currency_code:
          type: string
          minLength: 3
          maxLength: 3
          example: SAR
    ResourceId:
      type: string
      pattern: ^[0-9A-HJKMNP-TV-Z]{26}$
      example: 01HQXBT7N8FK2WVMC9YE3DRPJ4
    GlobalIntegerId:
      type: integer
      format: int64
    BilingualText:
      type: object
      required:
      - name_ar
      - name_en
      properties:
        name_ar:
          type: string
        name_en:
          type: string
    BranchLoginRow:
      allOf:
      - $ref: '#/components/schemas/BilingualText'
      - type: object
        required:
        - id
        properties:
          id:
            $ref: '#/components/schemas/ResourceId'
          code:
            type: string
    PaginationMeta:
      type: object
      required:
      - current_page
      - per_page
      - total
      - total_pages
      properties:
        current_page:
          type: integer
          minimum: 1
        per_page:
          type: integer
          minimum: 1
        total:
          type: integer
          minimum: 0
        total_pages:
          type: integer
          minimum: 0
    PaginatedResponse:
      type: object
      required:
      - data
      - meta
      properties:
        data:
          type: array
          items: {}
        meta:
          $ref: '#/components/schemas/PaginationMeta'
      description: List success envelope (`data` + `meta`) per `docs/current/BACKEND-CONVENTIONS.md`. Specialize `data.items` on each list
        operation via `allOf` where needed.
    UserListMeta:
      type: object
      required:
      - page
      - per_page
      - total
      properties:
        page:
          type: integer
          minimum: 1
        per_page:
          type: integer
          minimum: 1
        total:
          type: integer
          minimum: 0
      description: Pagination for `GET /users` (page-based, not Laravel default `current_page`).
    TenantUserBranchRow:
      type: object
      required:
      - id
      - code
      - name
      properties:
        id:
          $ref: '#/components/schemas/ResourceId'
        code:
          type: string
        name:
          type: string
        primary_role:
          type: string
          nullable: true
    TenantUser:
      type: object
      required:
      - id
      - name
      - email
      - preferred_locale
      - is_active
      - mfa_enabled
      properties:
        id:
          $ref: '#/components/schemas/GlobalIntegerId'
        name:
          type: string
        email:
          type: string
          format: email
        phone:
          type: string
          nullable: true
        preferred_locale:
          type: string
          enum:
          - ar
          - en
        is_active:
          type: boolean
        mfa_enabled:
          type: boolean
        roles:
          type: array
          items:
            type: string
        branches:
          type: array
          items:
            $ref: '#/components/schemas/TenantUserBranchRow'
    TenantUserListResponse:
      type: object
      required:
      - data
      - meta
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/TenantUser'
        meta:
          $ref: '#/components/schemas/UserListMeta'
    TenantUserEnvelope:
      type: object
      required:
      - data
      properties:
        data:
          $ref: '#/components/schemas/TenantUser'
    TenantPermission:
      type: object
      required:
      - id
      - name
      - guard_name
      properties:
        id:
          $ref: '#/components/schemas/GlobalIntegerId'
        name:
          type: string
          example: users.view
        guard_name:
          type: string
          example: sanctum
    TenantPermissionListEnvelope:
      type: object
      required:
      - data
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/TenantPermission'
    TenantRole:
      type: object
      required:
      - id
      - name
      - guard_name
      properties:
        id:
          $ref: '#/components/schemas/GlobalIntegerId'
        name:
          type: string
        guard_name:
          type: string
          example: sanctum
        permissions:
          type: array
          items:
            type: string
    TenantRoleListEnvelope:
      type: object
      required:
      - data
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/TenantRole'
    TenantRoleEnvelope:
      type: object
      required:
      - data
      properties:
        data:
          $ref: '#/components/schemas/TenantRole'
    StoreTenantUserBody:
      type: object
      required:
      - name
      - email
      - roles
      - branches
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        email:
          type: string
          format: email
        password:
          type: string
          minLength: 8
          maxLength: 255
          writeOnly: true
          description: Optional; random password generated when omitted.
        is_active:
          type: boolean
          default: true
        roles:
          type: array
          minItems: 1
          items:
            type: string
            pattern: ^[a-z][a-z0-9_]*$
            maxLength: 100
        branches:
          type: array
          minItems: 1
          description: Branch ULIDs for `branch_user` attachment.
          items:
            $ref: '#/components/schemas/ResourceId'
    PatchTenantUserBody:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        phone:
          type: string
          nullable: true
          maxLength: 32
        preferred_locale:
          type: string
          enum:
          - ar
          - en
        is_active:
          type: boolean
      description: At least one field should be sent (validated server-side).
    SyncUserRolesBody:
      type: object
      required:
      - roles
      properties:
        roles:
          type: array
          minItems: 1
          description: Replaces all Spatie roles on the user (`syncRoles`); uses `findOrCreate` per name for `sanctum`.
          items:
            type: string
            pattern: ^[a-z][a-z0-9_]*$
            maxLength: 100
    StoreRoleBody:
      type: object
      required:
      - name
      - permissions
      properties:
        name:
          type: string
          pattern: ^[a-z][a-z0-9_]*$
          maxLength: 100
        permissions:
          type: array
          description: Permission names that already exist for `sanctum` guard.
          items:
            type: string
            maxLength: 150
    PatchRoleBody:
      type: object
      properties:
        name:
          type: string
          pattern: ^[a-z][a-z0-9_]*$
          maxLength: 100
        permissions:
          type: array
          items:
            type: string
            maxLength: 150
    InviteTenantUserBody:
      type: object
      required:
      - email
      - roles
      - branches
      properties:
        email:
          type: string
          format: email
        roles:
          type: array
          minItems: 1
          items:
            type: string
            pattern: ^[a-z][a-z0-9_]*$
            maxLength: 100
        branches:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/ResourceId'
    InviteTenantUserResponse:
      type: object
      required:
      - data
      properties:
        data:
          type: object
          required:
          - id
          - status
          properties:
            id:
              $ref: '#/components/schemas/GlobalIntegerId'
            status:
              type: string
              example: invited
security: []
