{
  "openapi": "3.0.0",
  "paths": {
    "/journal": {
      "get": {
        "operationId": "JournalController_list",
        "parameters": [],
        "responses": {
          "200": {
            "description": "List of journal entries"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all journal entries",
        "tags": [
          "journal"
        ]
      },
      "post": {
        "operationId": "JournalController_create",
        "parameters": [
          {
            "name": "idempotency-key",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateJournalDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Journal entry created"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Create a manual journal entry",
        "tags": [
          "journal"
        ]
      }
    },
    "/journal/totals": {
      "get": {
        "operationId": "JournalController_totals",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Aggregated journal totals"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get journal totals across the full filtered result set, independent of pagination",
        "tags": [
          "journal"
        ]
      }
    },
    "/journal/accounts": {
      "get": {
        "operationId": "JournalController_getAccounts",
        "parameters": [],
        "responses": {
          "200": {
            "description": "List of accounts"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all accounts for journal entry",
        "tags": [
          "journal"
        ]
      }
    },
    "/journal/{id}": {
      "get": {
        "operationId": "JournalController_getById",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get journal entry by ID",
        "tags": [
          "journal"
        ]
      }
    },
    "/journal/{id}/reverse": {
      "post": {
        "operationId": "JournalController_reverse",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReverseJournalDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Reversal entry created"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Reverse a journal entry (creates mirror entry)",
        "tags": [
          "journal"
        ]
      }
    },
    "/customers": {
      "get": {
        "operationId": "CustomersController_findAll",
        "parameters": [
          {
            "name": "page",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "ACTIVE",
                "ARCHIVED"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerListDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all customers",
        "tags": [
          "customers"
        ]
      },
      "post": {
        "operationId": "CustomersController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCustomerDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Customer created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Create a new customer",
        "tags": [
          "customers"
        ]
      }
    },
    "/customers/{id}": {
      "get": {
        "operationId": "CustomersController_findOne",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Customer ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerDto"
                }
              }
            }
          },
          "404": {
            "description": "Customer not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get customer by ID",
        "tags": [
          "customers"
        ]
      },
      "patch": {
        "operationId": "CustomersController_update",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Customer ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCustomerDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Customer updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Update customer",
        "tags": [
          "customers"
        ]
      },
      "delete": {
        "operationId": "CustomersController_remove",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Customer ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Customer deleted"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Permanently delete customer",
        "tags": [
          "customers"
        ]
      }
    },
    "/customers/{id}/payments": {
      "get": {
        "operationId": "CustomersController_getPayments",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Customer ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer payments"
          },
          "404": {
            "description": "Customer not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List a customer's payments",
        "tags": [
          "customers"
        ]
      }
    },
    "/customers/{id}/activity": {
      "get": {
        "operationId": "CustomersController_getActivity",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Customer ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer activity feed"
          },
          "404": {
            "description": "Customer not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get a customer's activity feed",
        "tags": [
          "customers"
        ]
      }
    },
    "/customers/{id}/archive": {
      "post": {
        "operationId": "CustomersController_archive",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Customer ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer archived",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Archive customer",
        "tags": [
          "customers"
        ]
      }
    },
    "/customers/{id}/restore": {
      "post": {
        "operationId": "CustomersController_restore",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Customer ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer restored",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Restore archived customer",
        "tags": [
          "customers"
        ]
      }
    },
    "/invoices": {
      "get": {
        "operationId": "InvoicesController_findAll",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Invoice list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceListDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all invoices",
        "tags": [
          "invoices"
        ]
      },
      "post": {
        "operationId": "InvoicesController_create",
        "parameters": [
          {
            "name": "idempotency-key",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInvoiceDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invoice created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Create a new invoice",
        "tags": [
          "invoices"
        ]
      }
    },
    "/invoices/{id}": {
      "get": {
        "operationId": "InvoicesController_findOne",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Invoice ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoice found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceDto"
                }
              }
            }
          },
          "404": {
            "description": "Invoice not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get invoice by ID",
        "tags": [
          "invoices"
        ]
      },
      "patch": {
        "operationId": "InvoicesController_update",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Invoice ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateInvoiceDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invoice updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Update invoice",
        "tags": [
          "invoices"
        ]
      }
    },
    "/invoices/{id}/journal": {
      "get": {
        "operationId": "InvoicesController_getJournalEntries",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Invoice ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Journal entries"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get journal entries for invoice",
        "tags": [
          "invoices"
        ]
      }
    },
    "/invoices/{id}/pdf": {
      "get": {
        "operationId": "InvoicesController_generatePdf",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Invoice ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PDF file"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Download invoice as PDF",
        "tags": [
          "invoices"
        ]
      }
    },
    "/invoices/customers/{customerId}/opening-balance": {
      "post": {
        "operationId": "InvoicesController_createOpeningBalance",
        "parameters": [
          {
            "name": "customerId",
            "required": true,
            "in": "path",
            "description": "Customer ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOpeningBalanceDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opening balance recorded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Record a customer's opening (migration/carry-forward) balance",
        "tags": [
          "invoices"
        ]
      }
    },
    "/invoices/bulk-import": {
      "post": {
        "operationId": "InvoicesController_bulkImport",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkImportInvoicesDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row import results"
          },
          "400": {
            "description": "Invalid payload"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Bulk import sales invoices from an external app. Up to 200 per request; rows are processed independently and a per-row result is returned (partial success). References are existing-IDs-only (customerId / itemId must already exist). Developer API: requires the invoices:write scope (also callable from a session).",
        "tags": [
          "invoices"
        ]
      }
    },
    "/invoices/{id}/send": {
      "post": {
        "operationId": "InvoicesController_send",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Invoice ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendInvoiceDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invoice sent",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Send invoice via email/WhatsApp",
        "tags": [
          "invoices"
        ]
      }
    },
    "/invoices/{id}/void": {
      "post": {
        "operationId": "InvoicesController_void",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Invoice ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoice voided",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Void an invoice",
        "tags": [
          "invoices"
        ]
      }
    },
    "/invoices/{id}/write-off": {
      "post": {
        "description": "Direct write-off: posts Dr 5950 Bad Debt Expense / Cr 1100 AR and clears the balance in one transaction. Unlike void, the original revenue is kept — the sale was real; only the loss is recognised. Supply `amount` for a partial write-off.",
        "operationId": "InvoicesController_writeOff",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Invoice ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WriteOffInvoiceDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invoice written off",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Write off an uncollectible invoice",
        "tags": [
          "invoices"
        ]
      }
    },
    "/payments/{id}/receipt-pdf": {
      "get": {
        "operationId": "PaymentsController_getReceiptPdf",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Download payment receipt as PDF (uses template)",
        "tags": [
          "payments"
        ]
      }
    },
    "/payments": {
      "get": {
        "operationId": "PaymentsController_findAll",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Payment list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentListDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all payments",
        "tags": [
          "payments"
        ]
      },
      "post": {
        "operationId": "PaymentsController_recordStandalonePayment",
        "parameters": [
          {
            "name": "idempotency-key",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateStandalonePaymentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Payment recorded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Record a standalone payment (with or without invoice)",
        "tags": [
          "payments"
        ]
      }
    },
    "/invoices/{invoiceId}/payments": {
      "get": {
        "operationId": "PaymentsController_getInvoicePayments",
        "parameters": [
          {
            "name": "invoiceId",
            "required": true,
            "in": "path",
            "description": "Invoice ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoice payments",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentListDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get payments for an invoice",
        "tags": [
          "payments"
        ]
      },
      "post": {
        "operationId": "PaymentsController_recordPayment",
        "parameters": [
          {
            "name": "invoiceId",
            "required": true,
            "in": "path",
            "description": "Invoice ID",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "idempotency-key",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePaymentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Payment recorded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Record a payment against an invoice",
        "tags": [
          "payments"
        ]
      }
    },
    "/payments/allocate": {
      "post": {
        "operationId": "PaymentsController_allocate",
        "parameters": [
          {
            "name": "idempotency-key",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AllocatePaymentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Payment recorded with allocations"
          },
          "400": {
            "description": "Validation error (totals, status, balances)"
          },
          "404": {
            "description": "Customer, invoice, or return not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Record a customer payment split across multiple invoices, optionally netted with sales-return credits",
        "tags": [
          "payments"
        ]
      }
    },
    "/payments/{id}": {
      "delete": {
        "operationId": "PaymentsController_deleteAllocated",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Payment deleted"
          },
          "404": {
            "description": "Payment not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Delete a multi-invoice customer payment and reverse its journal",
        "tags": [
          "payments"
        ]
      }
    },
    "/sales-returns/{id}/pdf": {
      "get": {
        "operationId": "SalesReturnsController_getPdf",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Download sales return as PDF (uses template)",
        "tags": [
          "sales-returns"
        ]
      }
    },
    "/sales-returns": {
      "get": {
        "operationId": "SalesReturnsController_findAll",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesReturnListDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all sales returns",
        "tags": [
          "sales-returns"
        ]
      },
      "post": {
        "operationId": "SalesReturnsController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSalesReturnDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesReturnDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Create a sales return",
        "tags": [
          "sales-returns"
        ]
      }
    },
    "/sales-returns/{id}": {
      "get": {
        "operationId": "SalesReturnsController_findOne",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesReturnDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get a sales return by ID",
        "tags": [
          "sales-returns"
        ]
      }
    },
    "/sales-returns/{id}/journal": {
      "get": {
        "operationId": "SalesReturnsController_getJournalEntries",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get journal entries for a sales return",
        "tags": [
          "sales-returns"
        ]
      }
    },
    "/sales-returns/{id}/confirm": {
      "post": {
        "operationId": "SalesReturnsController_confirm",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesReturnDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Confirm a draft sales return",
        "tags": [
          "sales-returns"
        ]
      }
    },
    "/sales-returns/{id}/void": {
      "post": {
        "operationId": "SalesReturnsController_void",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesReturnDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Void a sales return",
        "tags": [
          "sales-returns"
        ]
      }
    },
    "/sales-returns/{id}/refund": {
      "post": {
        "operationId": "SalesReturnsController_refund",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefundSalesReturnDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesReturnDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Disburse a refund against a confirmed sales return",
        "tags": [
          "sales-returns"
        ]
      }
    },
    "/purchase-returns/{id}/pdf": {
      "get": {
        "operationId": "PurchaseReturnsController_getPdf",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Download purchase return as PDF (uses template)",
        "tags": [
          "purchase-returns"
        ]
      }
    },
    "/purchase-returns": {
      "get": {
        "operationId": "PurchaseReturnsController_findAll",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PurchaseReturnListDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all purchase returns",
        "tags": [
          "purchase-returns"
        ]
      },
      "post": {
        "operationId": "PurchaseReturnsController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePurchaseReturnDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PurchaseReturnDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Create a purchase return",
        "tags": [
          "purchase-returns"
        ]
      }
    },
    "/purchase-returns/{id}": {
      "get": {
        "operationId": "PurchaseReturnsController_findOne",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PurchaseReturnDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get a purchase return by ID",
        "tags": [
          "purchase-returns"
        ]
      }
    },
    "/purchase-returns/{id}/journal": {
      "get": {
        "operationId": "PurchaseReturnsController_getJournalEntries",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get journal entries for a purchase return",
        "tags": [
          "purchase-returns"
        ]
      }
    },
    "/purchase-returns/{id}/confirm": {
      "post": {
        "operationId": "PurchaseReturnsController_confirm",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PurchaseReturnDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Confirm a draft purchase return",
        "tags": [
          "purchase-returns"
        ]
      }
    },
    "/purchase-returns/{id}/void": {
      "post": {
        "operationId": "PurchaseReturnsController_void",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PurchaseReturnDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Void a purchase return",
        "tags": [
          "purchase-returns"
        ]
      }
    },
    "/purchase-returns/{id}/refund": {
      "post": {
        "operationId": "PurchaseReturnsController_refund",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefundPurchaseReturnDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PurchaseReturnDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Record a supplier refund against a confirmed purchase return",
        "tags": [
          "purchase-returns"
        ]
      }
    },
    "/expenses": {
      "get": {
        "operationId": "ExpensesController_findAll",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Expense list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExpenseListDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List expenses",
        "tags": [
          "expenses"
        ]
      },
      "post": {
        "operationId": "ExpensesController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateExpenseDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Expense created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExpenseDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Create expense",
        "tags": [
          "expenses"
        ]
      }
    },
    "/expenses/accounts": {
      "get": {
        "operationId": "ExpensesController_getAccounts",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Expense accounts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ExpenseAccountDto"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get expense account categories",
        "tags": [
          "expenses"
        ]
      }
    },
    "/expenses/{id}/archive": {
      "post": {
        "operationId": "ExpensesController_archive",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Archive expense",
        "tags": [
          "expenses"
        ]
      }
    },
    "/expenses/{id}/restore": {
      "post": {
        "operationId": "ExpensesController_restore",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Restore archived expense",
        "tags": [
          "expenses"
        ]
      }
    },
    "/expenses/{id}": {
      "delete": {
        "operationId": "ExpensesController_delete",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Delete expense",
        "tags": [
          "expenses"
        ]
      }
    },
    "/reports/profit-loss": {
      "get": {
        "operationId": "ReportsController_getProfitLoss",
        "parameters": [
          {
            "name": "period",
            "required": false,
            "in": "query",
            "description": "Predefined period",
            "schema": {
              "type": "string",
              "enum": [
                "THIS_MONTH",
                "LAST_MONTH",
                "THIS_QUARTER",
                "LAST_QUARTER",
                "THIS_YEAR",
                "YTD",
                "CUSTOM"
              ]
            }
          },
          {
            "name": "startDate",
            "required": false,
            "in": "query",
            "description": "Start date (required if period = CUSTOM)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "required": false,
            "in": "query",
            "description": "End date (required if period = CUSTOM)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "P&L report",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfitLossDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get Profit & Loss report",
        "tags": [
          "reports"
        ]
      }
    },
    "/reports/balance-sheet": {
      "get": {
        "operationId": "ReportsController_getBalanceSheet",
        "parameters": [
          {
            "name": "asOfDate",
            "required": false,
            "in": "query",
            "description": "As of date (defaults to today)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Balance Sheet report",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceSheetDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get Balance Sheet report",
        "tags": [
          "reports"
        ]
      }
    },
    "/reports/cash-flow": {
      "get": {
        "operationId": "ReportsController_getCashFlow",
        "parameters": [
          {
            "name": "period",
            "required": false,
            "in": "query",
            "description": "Predefined period",
            "schema": {
              "type": "string",
              "enum": [
                "THIS_MONTH",
                "LAST_MONTH",
                "THIS_QUARTER",
                "LAST_QUARTER",
                "THIS_YEAR",
                "YTD",
                "CUSTOM"
              ]
            }
          },
          {
            "name": "startDate",
            "required": false,
            "in": "query",
            "description": "Start date (required if period = CUSTOM)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "required": false,
            "in": "query",
            "description": "End date (required if period = CUSTOM)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cash Flow Statement",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CashFlowDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get Cash Flow Statement",
        "tags": [
          "reports"
        ]
      }
    },
    "/reports/tax-report": {
      "get": {
        "operationId": "ReportsController_getTaxReport",
        "parameters": [
          {
            "name": "period",
            "required": false,
            "in": "query",
            "description": "Predefined period",
            "schema": {
              "type": "string",
              "enum": [
                "THIS_MONTH",
                "LAST_MONTH",
                "THIS_QUARTER",
                "LAST_QUARTER",
                "THIS_YEAR",
                "YTD",
                "CUSTOM"
              ]
            }
          },
          {
            "name": "startDate",
            "required": false,
            "in": "query",
            "description": "Start date (required if period = CUSTOM)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "required": false,
            "in": "query",
            "description": "End date (required if period = CUSTOM)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tax report with transaction details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxReportDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get Tax / VAT / GST Report",
        "tags": [
          "reports"
        ]
      }
    },
    "/reports/tax-summary": {
      "get": {
        "operationId": "ReportsController_getTaxSummary",
        "parameters": [
          {
            "name": "period",
            "required": false,
            "in": "query",
            "description": "Predefined period",
            "schema": {
              "type": "string",
              "enum": [
                "THIS_MONTH",
                "LAST_MONTH",
                "THIS_QUARTER",
                "LAST_QUARTER",
                "THIS_YEAR",
                "YTD",
                "CUSTOM"
              ]
            }
          },
          {
            "name": "startDate",
            "required": false,
            "in": "query",
            "description": "Start date (required if period = CUSTOM)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "required": false,
            "in": "query",
            "description": "End date (required if period = CUSTOM)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tax summary with quarterly breakdown",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxSummaryDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get Tax Summary",
        "tags": [
          "reports"
        ]
      }
    },
    "/reports/trial-balance": {
      "get": {
        "operationId": "ReportsController_getTrialBalance",
        "parameters": [
          {
            "name": "asOfDate",
            "required": false,
            "in": "query",
            "description": "As of date (defaults to today)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Trial Balance report",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrialBalanceDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get Trial Balance report",
        "tags": [
          "reports"
        ]
      }
    },
    "/reports/general-ledger": {
      "get": {
        "operationId": "ReportsController_getGeneralLedger",
        "parameters": [
          {
            "name": "startDate",
            "required": true,
            "in": "query",
            "description": "Start date (inclusive), YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "required": true,
            "in": "query",
            "description": "End date (inclusive), YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "accountId",
            "required": false,
            "in": "query",
            "description": "Restrict to a single account. Omit for an all-accounts General Ledger.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "General Ledger report",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeneralLedgerDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get General Ledger report (all accounts or a single account)",
        "tags": [
          "reports"
        ]
      }
    },
    "/reports/opening-balance-equity": {
      "get": {
        "operationId": "ReportsController_getOpeningBalanceEquity",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Opening Balance Equity reconciliation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpeningBalanceEquityDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get Opening Balance Equity reconciliation (account 3050)",
        "tags": [
          "reports"
        ]
      }
    },
    "/reports/profit-loss/export": {
      "get": {
        "operationId": "ReportsController_exportProfitLoss",
        "parameters": [
          {
            "name": "period",
            "required": false,
            "in": "query",
            "description": "Predefined period",
            "schema": {
              "type": "string",
              "enum": [
                "THIS_MONTH",
                "LAST_MONTH",
                "THIS_QUARTER",
                "LAST_QUARTER",
                "THIS_YEAR",
                "YTD",
                "CUSTOM"
              ]
            }
          },
          {
            "name": "startDate",
            "required": false,
            "in": "query",
            "description": "Start date (required if period = CUSTOM)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "required": false,
            "in": "query",
            "description": "End date (required if period = CUSTOM)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Export Profit & Loss as Excel",
        "tags": [
          "reports"
        ]
      }
    },
    "/reports/balance-sheet/export": {
      "get": {
        "operationId": "ReportsController_exportBalanceSheet",
        "parameters": [
          {
            "name": "asOfDate",
            "required": false,
            "in": "query",
            "description": "As of date (defaults to today)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Export Balance Sheet as Excel",
        "tags": [
          "reports"
        ]
      }
    },
    "/reports/cash-flow/export": {
      "get": {
        "operationId": "ReportsController_exportCashFlow",
        "parameters": [
          {
            "name": "period",
            "required": false,
            "in": "query",
            "description": "Predefined period",
            "schema": {
              "type": "string",
              "enum": [
                "THIS_MONTH",
                "LAST_MONTH",
                "THIS_QUARTER",
                "LAST_QUARTER",
                "THIS_YEAR",
                "YTD",
                "CUSTOM"
              ]
            }
          },
          {
            "name": "startDate",
            "required": false,
            "in": "query",
            "description": "Start date (required if period = CUSTOM)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "required": false,
            "in": "query",
            "description": "End date (required if period = CUSTOM)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Export Cash Flow Statement as Excel",
        "tags": [
          "reports"
        ]
      }
    },
    "/reports/trial-balance/export": {
      "get": {
        "operationId": "ReportsController_exportTrialBalance",
        "parameters": [
          {
            "name": "asOfDate",
            "required": false,
            "in": "query",
            "description": "As of date (defaults to today)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Export Trial Balance as Excel",
        "tags": [
          "reports"
        ]
      }
    },
    "/accounts": {
      "get": {
        "operationId": "AccountsController_findAll",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all accounts",
        "tags": [
          "accounts"
        ]
      },
      "post": {
        "operationId": "AccountsController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAccountDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Create a new account",
        "tags": [
          "accounts"
        ]
      }
    },
    "/accounts/cash-bank": {
      "get": {
        "operationId": "AccountsController_getCashBankAccounts",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List Cash/Bank accounts for payment-account selection",
        "tags": [
          "accounts"
        ]
      }
    },
    "/accounts/{id}": {
      "get": {
        "operationId": "AccountsController_findOne",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "asOfDate",
            "required": false,
            "in": "query",
            "description": "Calculate balance as of this date",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get account details with balance",
        "tags": [
          "accounts"
        ]
      },
      "patch": {
        "operationId": "AccountsController_update",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Update account name or description",
        "tags": [
          "accounts"
        ]
      },
      "delete": {
        "operationId": "AccountsController_delete",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Delete an account (only if unused)",
        "tags": [
          "accounts"
        ]
      }
    },
    "/accounts/{id}/archive": {
      "post": {
        "operationId": "AccountsController_archive",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Retire an account from new postings (used accounts can't be deleted — this is how they get retired)",
        "tags": [
          "accounts"
        ]
      }
    },
    "/accounts/{id}/restore": {
      "post": {
        "operationId": "AccountsController_restore",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Restore an archived account so it can receive postings again",
        "tags": [
          "accounts"
        ]
      }
    },
    "/quotes/{id}/pdf": {
      "get": {
        "operationId": "QuotesController_getPdf",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Download quote as PDF (uses template)",
        "tags": [
          "quotes"
        ]
      }
    },
    "/quotes": {
      "get": {
        "operationId": "QuotesController_findAll",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Quote list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuoteListDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all quotes",
        "tags": [
          "quotes"
        ]
      },
      "post": {
        "operationId": "QuotesController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateQuoteDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Quote created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuoteDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Create a new quote",
        "tags": [
          "quotes"
        ]
      }
    },
    "/quotes/{id}": {
      "get": {
        "operationId": "QuotesController_findOne",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Quote ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Quote found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuoteDto"
                }
              }
            }
          },
          "404": {
            "description": "Quote not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get quote by ID",
        "tags": [
          "quotes"
        ]
      },
      "patch": {
        "operationId": "QuotesController_update",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Quote ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateQuoteDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuoteDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Update quote",
        "tags": [
          "quotes"
        ]
      },
      "delete": {
        "operationId": "QuotesController_delete",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Quote ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Quote deleted"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Delete quote",
        "tags": [
          "quotes"
        ]
      }
    },
    "/quotes/{id}/send": {
      "post": {
        "operationId": "QuotesController_send",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Quote ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendQuoteDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quote sent",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuoteDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Send quote via email/WhatsApp",
        "tags": [
          "quotes"
        ]
      }
    },
    "/quotes/{id}/accept": {
      "post": {
        "operationId": "QuotesController_accept",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Quote ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Quote accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuoteDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Mark quote as accepted",
        "tags": [
          "quotes"
        ]
      }
    },
    "/quotes/{id}/reject": {
      "post": {
        "operationId": "QuotesController_reject",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Quote ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Quote rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuoteDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Mark quote as rejected",
        "tags": [
          "quotes"
        ]
      }
    },
    "/quotes/{id}/convert": {
      "post": {
        "operationId": "QuotesController_convertToInvoice",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Quote ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Quote converted to invoice"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Convert quote to invoice",
        "tags": [
          "quotes"
        ]
      }
    },
    "/suppliers": {
      "get": {
        "operationId": "SuppliersController_findAll",
        "parameters": [
          {
            "name": "page",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "ACTIVE",
                "ARCHIVED"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Supplier list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupplierListDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all suppliers",
        "tags": [
          "suppliers"
        ]
      },
      "post": {
        "operationId": "SuppliersController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSupplierDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Supplier created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupplierDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Create a new supplier",
        "tags": [
          "suppliers"
        ]
      }
    },
    "/suppliers/{id}": {
      "get": {
        "operationId": "SuppliersController_findOne",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Supplier ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Supplier found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupplierDto"
                }
              }
            }
          },
          "404": {
            "description": "Supplier not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get supplier by ID",
        "tags": [
          "suppliers"
        ]
      },
      "patch": {
        "operationId": "SuppliersController_update",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Supplier ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSupplierDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Supplier updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupplierDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Update supplier",
        "tags": [
          "suppliers"
        ]
      },
      "delete": {
        "operationId": "SuppliersController_remove",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Supplier ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Supplier deleted"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Permanently delete supplier",
        "tags": [
          "suppliers"
        ]
      }
    },
    "/suppliers/{id}/payments": {
      "get": {
        "operationId": "SuppliersController_getPayments",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Supplier ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Supplier payments"
          },
          "404": {
            "description": "Supplier not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List a supplier's payments",
        "tags": [
          "suppliers"
        ]
      }
    },
    "/suppliers/{id}/activity": {
      "get": {
        "operationId": "SuppliersController_getActivity",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Supplier ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Supplier activity feed"
          },
          "404": {
            "description": "Supplier not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get a supplier's activity feed",
        "tags": [
          "suppliers"
        ]
      }
    },
    "/suppliers/{id}/archive": {
      "post": {
        "operationId": "SuppliersController_archive",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Supplier ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Supplier archived",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupplierDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Archive supplier",
        "tags": [
          "suppliers"
        ]
      }
    },
    "/suppliers/{id}/restore": {
      "post": {
        "operationId": "SuppliersController_restore",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Supplier ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Supplier restored",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupplierDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Restore archived supplier",
        "tags": [
          "suppliers"
        ]
      }
    },
    "/purchases": {
      "get": {
        "operationId": "PurchasesController_findAll",
        "parameters": [
          {
            "name": "page",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "supplierId",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "DRAFT",
                "PARTIALLY_PAID",
                "PAID",
                "VOID",
                "RECEIVED"
              ]
            }
          },
          {
            "name": "sortBy",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns paginated list of purchases"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all purchases",
        "tags": [
          "purchases"
        ]
      },
      "post": {
        "operationId": "PurchasesController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePurchaseDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Purchase created successfully"
          },
          "400": {
            "description": "Invalid input"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Create a new purchase",
        "tags": [
          "purchases"
        ]
      }
    },
    "/purchases/{id}": {
      "get": {
        "operationId": "PurchasesController_findOne",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns the purchase"
          },
          "404": {
            "description": "Purchase not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get a purchase by ID",
        "tags": [
          "purchases"
        ]
      },
      "patch": {
        "operationId": "PurchasesController_update",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePurchaseDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Purchase updated successfully"
          },
          "400": {
            "description": "Cannot update non-draft purchase"
          },
          "404": {
            "description": "Purchase not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Update a purchase",
        "tags": [
          "purchases"
        ]
      }
    },
    "/purchases/suppliers/{supplierId}/opening-balance": {
      "post": {
        "operationId": "PurchasesController_createOpeningBalance",
        "parameters": [
          {
            "name": "supplierId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOpeningBalanceDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Opening balance recorded"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Record a supplier's opening (migration/carry-forward) balance",
        "tags": [
          "purchases"
        ]
      }
    },
    "/purchases/{id}/finalize": {
      "post": {
        "operationId": "PurchasesController_finalize",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Purchase finalized successfully"
          },
          "400": {
            "description": "Purchase is not in draft status"
          },
          "404": {
            "description": "Purchase not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Finalize a draft purchase",
        "tags": [
          "purchases"
        ]
      }
    },
    "/purchases/{id}/void": {
      "post": {
        "operationId": "PurchasesController_void",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Purchase voided successfully"
          },
          "400": {
            "description": "Cannot void this purchase"
          },
          "404": {
            "description": "Purchase not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Void a purchase",
        "tags": [
          "purchases"
        ]
      }
    },
    "/purchases/{id}/journal": {
      "get": {
        "operationId": "PurchasesController_getJournalEntries",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns journal entries"
          },
          "404": {
            "description": "Purchase not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get journal entries for a purchase",
        "tags": [
          "purchases"
        ]
      }
    },
    "/supplier-payments/{id}/receipt-pdf": {
      "get": {
        "operationId": "SupplierPaymentsController_getReceiptPdf",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Download supplier payment receipt as PDF (uses template)",
        "tags": [
          "purchases"
        ]
      }
    },
    "/supplier-payments": {
      "get": {
        "operationId": "SupplierPaymentsController_findAll",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Supplier payment list"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all supplier payments",
        "tags": [
          "purchases"
        ]
      },
      "post": {
        "operationId": "SupplierPaymentsController_createStandalone",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateStandaloneSupplierPaymentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Payment recorded"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Record a standalone supplier payment (with or without purchase)",
        "tags": [
          "purchases"
        ]
      }
    },
    "/supplier-payments/allocate": {
      "post": {
        "operationId": "SupplierPaymentsController_allocate",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AllocateSupplierPaymentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Payment recorded with allocations"
          },
          "400": {
            "description": "Validation error (totals, status, balances)"
          },
          "404": {
            "description": "Supplier, bill, or return not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Record a supplier payment split across multiple bills, optionally netted with purchase-return credits",
        "tags": [
          "purchases"
        ]
      }
    },
    "/supplier-payments/{id}": {
      "delete": {
        "operationId": "SupplierPaymentsController_deleteAllocated",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Payment deleted"
          },
          "404": {
            "description": "Payment not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Delete a multi-bill supplier payment and reverse its journal",
        "tags": [
          "purchases"
        ]
      }
    },
    "/purchases/{purchaseId}/payments": {
      "get": {
        "operationId": "SupplierPaymentsController_findByPurchase",
        "parameters": [
          {
            "name": "purchaseId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns list of payments"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all payments for a purchase",
        "tags": [
          "purchases"
        ]
      },
      "post": {
        "operationId": "SupplierPaymentsController_create",
        "parameters": [
          {
            "name": "purchaseId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSupplierPaymentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Payment recorded successfully"
          },
          "400": {
            "description": "Invalid payment amount or purchase status"
          },
          "404": {
            "description": "Purchase not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Record a payment for a purchase",
        "tags": [
          "purchases"
        ]
      }
    },
    "/purchases/{purchaseId}/payments/{paymentId}": {
      "delete": {
        "operationId": "SupplierPaymentsController_delete",
        "parameters": [
          {
            "name": "purchaseId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "paymentId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Payment deleted successfully"
          },
          "404": {
            "description": "Payment or purchase not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Delete a payment",
        "tags": [
          "purchases"
        ]
      }
    },
    "/items": {
      "get": {
        "operationId": "ItemsController_findAll",
        "parameters": [
          {
            "name": "purchasable",
            "required": false,
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "salable",
            "required": false,
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {
              "enum": [
                "ACTIVE",
                "ARCHIVED"
              ],
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Item list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ItemListDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all items",
        "tags": [
          "items"
        ]
      },
      "post": {
        "operationId": "ItemsController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateItemDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Item created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ItemDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Create a new item",
        "tags": [
          "items"
        ]
      }
    },
    "/items/{id}": {
      "get": {
        "operationId": "ItemsController_findOne",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Item ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Item found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ItemDto"
                }
              }
            }
          },
          "404": {
            "description": "Item not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get item by ID",
        "tags": [
          "items"
        ]
      },
      "patch": {
        "operationId": "ItemsController_update",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Item ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateItemDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Item updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ItemDto"
                }
              }
            }
          },
          "404": {
            "description": "Item not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Update an item",
        "tags": [
          "items"
        ]
      },
      "delete": {
        "operationId": "ItemsController_delete",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Item ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Item deleted"
          },
          "400": {
            "description": "Item cannot be deleted"
          },
          "404": {
            "description": "Item not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Delete an item (only if never used)",
        "tags": [
          "items"
        ]
      }
    },
    "/items/bulk-import": {
      "post": {
        "operationId": "ItemsController_bulkImport",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkImportItemsDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row import results"
          },
          "400": {
            "description": "Invalid payload"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Bulk import / sync items from an external app. Upserts by itemCode; rows are processed independently and a per-row result is returned. Developer API: requires the items:write scope (also callable from a session).",
        "tags": [
          "items"
        ]
      }
    },
    "/items/{id}/archive": {
      "post": {
        "operationId": "ItemsController_archive",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Item ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Item archived",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ItemDto"
                }
              }
            }
          },
          "404": {
            "description": "Item not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Archive an item",
        "tags": [
          "items"
        ]
      }
    },
    "/items/{id}/restore": {
      "post": {
        "operationId": "ItemsController_restore",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Item ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Item restored",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ItemDto"
                }
              }
            }
          },
          "404": {
            "description": "Item not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Restore an archived item",
        "tags": [
          "items"
        ]
      }
    },
    "/oauth/token": {
      "post": {
        "operationId": "OAuthController_token",
        "parameters": [
          {
            "name": "authorization",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequestDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "summary": "Exchange auth code or refresh token for access token",
        "tags": [
          "oauth"
        ]
      }
    },
    "/oauth/revoke": {
      "post": {
        "operationId": "OAuthController_revoke",
        "parameters": [
          {
            "name": "authorization",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RevokeTokenDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "summary": "Revoke an access or refresh token",
        "tags": [
          "oauth"
        ]
      }
    },
    "/oauth/introspect": {
      "post": {
        "operationId": "OAuthController_introspect",
        "parameters": [
          {
            "name": "authorization",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IntrospectDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "summary": "Introspect a token (RFC 7662)",
        "tags": [
          "oauth"
        ]
      }
    },
    "/gstr/readiness": {
      "get": {
        "operationId": "GstrController_checkReadiness",
        "parameters": [
          {
            "name": "from",
            "required": true,
            "in": "query",
            "description": "Start date (inclusive) YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "description": "End date (inclusive) YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Pre-flight check for GSTR filing readiness",
        "tags": [
          "gstr"
        ]
      }
    },
    "/gstr/1/preview": {
      "get": {
        "operationId": "GstrController_previewGstr1",
        "parameters": [
          {
            "name": "from",
            "required": true,
            "in": "query",
            "description": "Start date (inclusive) YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "description": "End date (inclusive) YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GSTR-1 preview (JSON)",
        "tags": [
          "gstr"
        ]
      }
    },
    "/gstr/1/export": {
      "get": {
        "operationId": "GstrController_exportGstr1",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GSTR-1 export (Excel or JSON)",
        "tags": [
          "gstr"
        ]
      }
    },
    "/gstr/3b/preview": {
      "get": {
        "operationId": "GstrController_previewGstr3b",
        "parameters": [
          {
            "name": "from",
            "required": true,
            "in": "query",
            "description": "Start date (inclusive) YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "description": "End date (inclusive) YYYY-MM-DD",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GSTR-3B preview (JSON)",
        "tags": [
          "gstr"
        ]
      }
    },
    "/gstr/3b/export": {
      "get": {
        "operationId": "GstrController_exportGstr3b",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GSTR-3B export (Excel or JSON)",
        "tags": [
          "gstr"
        ]
      }
    },
    "/bank-recon/accounts": {
      "get": {
        "operationId": "BankReconController_listAccounts",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List bank/cash accounts with reconciliation status",
        "tags": [
          "bank-recon"
        ]
      }
    },
    "/bank-recon/statements/upload": {
      "post": {
        "operationId": "BankReconController_upload",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Upload statement file and get parsed preview + suggested mapping",
        "tags": [
          "bank-recon"
        ]
      }
    },
    "/bank-recon/statements/remap": {
      "post": {
        "operationId": "BankReconController_remap",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Re-parse a cached upload with a different column mapping",
        "tags": [
          "bank-recon"
        ]
      }
    },
    "/bank-recon/statements": {
      "post": {
        "operationId": "BankReconController_confirm",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfirmStatementDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Confirm parsed statement and save to DB",
        "tags": [
          "bank-recon"
        ]
      },
      "get": {
        "operationId": "BankReconController_list",
        "parameters": [
          {
            "name": "accountId",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List statements (optionally filter by account)",
        "tags": [
          "bank-recon"
        ]
      }
    },
    "/bank-recon/statements/{id}": {
      "get": {
        "operationId": "BankReconController_get",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get statement with lines + match info",
        "tags": [
          "bank-recon"
        ]
      },
      "delete": {
        "operationId": "BankReconController_delete",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Delete a draft statement",
        "tags": [
          "bank-recon"
        ]
      }
    },
    "/bank-recon/statements/{id}/suggestions": {
      "get": {
        "operationId": "BankReconController_suggestions",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get match suggestions for unmatched lines",
        "tags": [
          "bank-recon"
        ]
      }
    },
    "/bank-recon/lines/{id}/match": {
      "patch": {
        "operationId": "BankReconController_match",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MatchLineDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Match a line to an existing transaction",
        "tags": [
          "bank-recon"
        ]
      }
    },
    "/bank-recon/lines/{id}/ignore": {
      "patch": {
        "operationId": "BankReconController_ignore",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Mark a line as ignored",
        "tags": [
          "bank-recon"
        ]
      }
    },
    "/bank-recon/lines/{id}/unmatch": {
      "patch": {
        "operationId": "BankReconController_unmatch",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Revert a line to unmatched",
        "tags": [
          "bank-recon"
        ]
      }
    },
    "/bank-recon/lines/{id}/create-journal": {
      "post": {
        "operationId": "BankReconController_createFromLine",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePaymentFromLineDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Create a journal entry from a line and auto-link",
        "tags": [
          "bank-recon"
        ]
      }
    },
    "/bank-recon/statements/{id}/reconcile": {
      "post": {
        "operationId": "BankReconController_reconcile",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Reconcile and lock a statement",
        "tags": [
          "bank-recon"
        ]
      }
    },
    "/bank-recon/statements/{id}/unreconcile": {
      "post": {
        "operationId": "BankReconController_unreconcile",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Unreconcile (unlock) a statement",
        "tags": [
          "bank-recon"
        ]
      }
    },
    "/contra/accounts": {
      "get": {
        "operationId": "ContraController_accounts",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List Bank/Cash accounts eligible for contra entries",
        "tags": [
          "contra"
        ]
      }
    },
    "/contra": {
      "get": {
        "operationId": "ContraController_list",
        "parameters": [
          {
            "name": "from",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List contra vouchers",
        "tags": [
          "contra"
        ]
      },
      "post": {
        "operationId": "ContraController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateContraDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Create contra voucher",
        "tags": [
          "contra"
        ]
      }
    },
    "/contra/{id}": {
      "get": {
        "operationId": "ContraController_get",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Get contra voucher",
        "tags": [
          "contra"
        ]
      }
    },
    "/contra/{id}/void": {
      "post": {
        "operationId": "ContraController_void",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Void (reverse) a contra voucher",
        "tags": [
          "contra"
        ]
      }
    },
    "/fiscal-years": {
      "get": {
        "operationId": "FiscalYearController_list",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "List all fiscal years",
        "tags": [
          "fiscal-years"
        ]
      }
    },
    "/fiscal-years/current": {
      "get": {
        "operationId": "FiscalYearController_current",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Current open fiscal year (auto-creates if missing)",
        "tags": [
          "fiscal-years"
        ]
      }
    },
    "/fiscal-years/{id}/lock": {
      "post": {
        "operationId": "FiscalYearController_lock",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Soft close (lock) — blocks backdated entries to this period",
        "tags": [
          "fiscal-years"
        ]
      }
    },
    "/fiscal-years/{id}/unlock": {
      "post": {
        "operationId": "FiscalYearController_unlock",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Undo a soft close (revert LOCKED → OPEN)",
        "tags": [
          "fiscal-years"
        ]
      }
    },
    "/fiscal-years/{id}/preview-close": {
      "get": {
        "operationId": "FiscalYearController_preview",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Preview the closing journal entry before posting",
        "tags": [
          "fiscal-years"
        ]
      }
    },
    "/.well-known/oauth-authorization-server": {
      "get": {
        "description": "Discovery document describing all OAuth endpoints. Fetch this once at app startup to avoid hard-coding URLs. Includes a non-standard `api_base_url` field pointing to the API root.",
        "operationId": "WellKnownController_getAuthorizationServerMetadata",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthorizationServerMetadataDto"
                }
              }
            }
          }
        },
        "summary": "OAuth 2.0 Authorization Server Metadata (RFC 8414)",
        "tags": [
          "well-known"
        ]
      }
    }
  },
  "info": {
    "title": "OneBooks Partner API",
    "description": "OAuth-scoped API surface for third-party integrations (POS, e-commerce, ERP). Every route documented here requires an OAuth 2.0 access token (Authorization Code + PKCE) or a bearer token obtained from it — the tenant is implicit in the token, never a request parameter. See the Authentication and Scopes guides for the full authorization-code walkthrough and the scope catalog.",
    "version": "1.1",
    "contact": {
      "name": "OneBooks",
      "url": "https://getonebooks.com",
      "email": "dev@lithospos.com"
    }
  },
  "tags": [
    {
      "name": "customers",
      "description": "Customer CRUD, archive/restore"
    },
    {
      "name": "quotes",
      "description": "Quotes: create, send, accept/reject, convert to invoice, PDF"
    },
    {
      "name": "invoices",
      "description": "Invoices: create, send, void, PDF, journal entries"
    },
    {
      "name": "sales-returns",
      "description": "Credit notes against invoices"
    },
    {
      "name": "payments",
      "description": "Customer payment recording + receipt PDFs"
    },
    {
      "name": "suppliers",
      "description": "Supplier CRUD, archive/restore"
    },
    {
      "name": "purchases",
      "description": "Purchase orders / bills + supplier-payments"
    },
    {
      "name": "purchase-returns",
      "description": "Debit notes against purchases"
    },
    {
      "name": "journal",
      "description": "Journal entries (manual double-entry postings)"
    },
    {
      "name": "accounts",
      "description": "Chart of accounts"
    },
    {
      "name": "contra",
      "description": "Cash/bank contra transfers"
    },
    {
      "name": "bank-recon",
      "description": "Bank statement upload + match + reconciliation"
    },
    {
      "name": "fiscal-years",
      "description": "Fiscal year lock/close/reopen + period guard"
    },
    {
      "name": "expenses",
      "description": "Expense recording with category accounts"
    },
    {
      "name": "items",
      "description": "Product / service catalog"
    },
    {
      "name": "reports",
      "description": "P&L, Balance Sheet, Cash Flow, Trial Balance (PDF + Excel export)"
    },
    {
      "name": "gstr",
      "description": "India GSTR-1 / GSTR-3B preview and export"
    },
    {
      "name": "oauth",
      "description": "OAuth 2.0 protocol endpoints (token exchange, revoke, introspect). Authorize and app management happen in the developer console, not this API."
    },
    {
      "name": "well-known",
      "description": "OAuth 2.0 Authorization Server Metadata (RFC 8414) — discovery endpoint"
    }
  ],
  "servers": [
    {
      "url": "https://api.getonebooks.com"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "type": "http",
        "description": "A scoped access token obtained from POST /oauth/token. Required scopes are documented on each route."
      },
      "oauth2": {
        "type": "oauth2",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://app.getonebooks.com/oauth/authorize",
            "tokenUrl": "https://api.getonebooks.com/oauth/token",
            "refreshUrl": "https://api.getonebooks.com/oauth/token",
            "scopes": {
              "profile:read": "View your profile information",
              "invoices:read": "View invoices",
              "invoices:write": "Create and modify invoices",
              "customers:read": "View customers",
              "customers:write": "Create and modify customers",
              "quotes:read": "View quotes",
              "quotes:write": "Create and modify quotes",
              "sales-returns:read": "View sales returns (credit notes)",
              "sales-returns:write": "Create and modify sales returns",
              "payments:read": "View customer payments",
              "payments:write": "Record customer payments",
              "suppliers:read": "View suppliers",
              "suppliers:write": "Create and modify suppliers",
              "purchases:read": "View purchase orders / bills",
              "purchases:write": "Create and modify purchases",
              "purchase-returns:read": "View purchase returns (debit notes)",
              "purchase-returns:write": "Create and modify purchase returns",
              "supplier-payments:read": "View supplier payments",
              "supplier-payments:write": "Record supplier payments",
              "expenses:read": "View expenses",
              "expenses:write": "Record expenses",
              "journal:read": "View journal entries",
              "journal:write": "Create journal entries",
              "accounts:read": "View chart of accounts",
              "accounts:write": "Create and modify accounts",
              "contra:read": "View contra vouchers (cash/bank transfers)",
              "contra:write": "Create contra vouchers",
              "bank-recon:read": "View bank statements and reconciliations",
              "bank-recon:write": "Upload statements and match transactions",
              "fiscal-year:read": "View fiscal year and close status",
              "fiscal-year:write": "Lock or unlock fiscal years",
              "items:read": "View items catalog",
              "items:write": "Create and modify items",
              "reports:read": "View financial reports (P&L, Balance Sheet, etc.)",
              "gstr:read": "View and export GSTR-1 / GSTR-3B (India)"
            }
          }
        },
        "description": "Authorization Code + PKCE — see the Authentication guide for the full flow."
      }
    },
    "schemas": {
      "JournalLineDto": {
        "type": "object",
        "properties": {
          "accountCode": {
            "type": "string",
            "description": "Chart-of-accounts code (e.g. \"1100\" for Accounts Receivable).",
            "example": "1210"
          },
          "debit": {
            "type": "number",
            "minimum": 0,
            "description": "Debit amount for this line. Use either debit OR credit, not both.",
            "example": 50000
          },
          "credit": {
            "type": "number",
            "minimum": 0,
            "description": "Credit amount for this line. Use either debit OR credit, not both.",
            "example": 0
          }
        },
        "required": [
          "accountCode"
        ]
      },
      "CreateJournalDto": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "description": "Entry posting date (ISO 8601). Must not fall in a locked/closed fiscal year.",
            "example": "2026-04-14",
            "format": "date"
          },
          "description": {
            "type": "string",
            "description": "Description of the journal entry. Shown in the ledger.",
            "example": "Owner capital injection"
          },
          "reference": {
            "type": "string",
            "description": "Optional reference number (cheque #, document ID, etc.).",
            "example": "CAP-001"
          },
          "lines": {
            "minItems": 2,
            "description": "Journal lines. Must have at least 2 and total debits must equal total credits.",
            "example": [
              {
                "accountCode": "1210",
                "debit": 50000
              },
              {
                "accountCode": "3000",
                "credit": 50000
              }
            ],
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JournalLineDto"
            }
          }
        },
        "required": [
          "date",
          "description",
          "lines"
        ]
      },
      "ReverseJournalDto": {
        "type": "object",
        "properties": {
          "reversalDate": {
            "type": "string"
          },
          "reason": {
            "type": "string",
            "maxLength": 500
          }
        }
      },
      "CustomerDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "address": {
            "type": "string",
            "nullable": true
          },
          "taxId": {
            "type": "string",
            "nullable": true
          },
          "customerCode": {
            "type": "string"
          },
          "status": {
            "enum": [
              "ACTIVE",
              "ARCHIVED"
            ],
            "type": "string"
          },
          "createdAt": {
            "format": "date-time",
            "type": "string"
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string"
          },
          "vatRegistrationNumber": {
            "type": "string",
            "nullable": true
          },
          "nameArabic": {
            "type": "string",
            "nullable": true
          },
          "streetName": {
            "type": "string",
            "nullable": true
          },
          "additionalStreetName": {
            "type": "string",
            "nullable": true
          },
          "buildingNumber": {
            "type": "string",
            "nullable": true
          },
          "plotIdentification": {
            "type": "string",
            "nullable": true
          },
          "citySubdivisionName": {
            "type": "string",
            "nullable": true
          },
          "cityName": {
            "type": "string",
            "nullable": true
          },
          "postalZone": {
            "type": "string",
            "nullable": true
          },
          "countrySubentity": {
            "type": "string",
            "nullable": true
          },
          "otherSellerIdScheme": {
            "type": "string",
            "nullable": true
          },
          "otherSellerIdValue": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "id",
          "name",
          "email",
          "phone",
          "address",
          "taxId",
          "customerCode",
          "status",
          "createdAt",
          "updatedAt",
          "vatRegistrationNumber",
          "nameArabic",
          "streetName",
          "additionalStreetName",
          "buildingNumber",
          "plotIdentification",
          "citySubdivisionName",
          "cityName",
          "postalZone",
          "countrySubentity",
          "otherSellerIdScheme",
          "otherSellerIdValue"
        ]
      },
      "CustomerListDto": {
        "type": "object",
        "properties": {
          "customers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerDto"
            }
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "customers",
          "total"
        ]
      },
      "CreateCustomerDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Customer display name.",
            "example": "Acme Corp"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Billing email address.",
            "example": "billing@acme.com"
          },
          "phone": {
            "type": "string",
            "maxLength": 50,
            "description": "Phone number (free-form).",
            "example": "+971 50 123 4567"
          },
          "address": {
            "type": "string",
            "maxLength": 500,
            "description": "Billing address (free-form, multi-line).",
            "example": "Level 4, Emirates Tower\nDubai, UAE"
          },
          "taxId": {
            "type": "string",
            "maxLength": 50,
            "description": "Tax identifier (GSTIN in India, TRN in UAE, VAT number in EU).",
            "example": "27ABCDE1234F1Z5"
          },
          "vatRegistrationNumber": {
            "type": "string",
            "maxLength": 15,
            "description": "KSA buyer VAT — 15 digits, prefix/suffix 3. Required for Standard invoices."
          },
          "nameArabic": {
            "type": "string",
            "maxLength": 255,
            "description": "Buyer name in Arabic."
          },
          "streetName": {
            "type": "string",
            "maxLength": 255
          },
          "additionalStreetName": {
            "type": "string",
            "maxLength": 255
          },
          "buildingNumber": {
            "type": "string",
            "maxLength": 4
          },
          "plotIdentification": {
            "type": "string",
            "maxLength": 64
          },
          "citySubdivisionName": {
            "type": "string",
            "maxLength": 255
          },
          "cityName": {
            "type": "string",
            "maxLength": 255
          },
          "postalZone": {
            "type": "string",
            "maxLength": 5
          },
          "countrySubentity": {
            "type": "string",
            "maxLength": 255
          },
          "otherSellerIdScheme": {
            "type": "string",
            "maxLength": 16
          },
          "otherSellerIdValue": {
            "type": "string",
            "maxLength": 64
          }
        },
        "required": [
          "name"
        ]
      },
      "UpdateCustomerDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string",
            "maxLength": 50
          },
          "address": {
            "type": "string",
            "maxLength": 500
          },
          "taxId": {
            "type": "string",
            "maxLength": 50
          },
          "vatRegistrationNumber": {
            "type": "string",
            "maxLength": 15
          },
          "nameArabic": {
            "type": "string",
            "maxLength": 255
          },
          "streetName": {
            "type": "string",
            "maxLength": 255
          },
          "additionalStreetName": {
            "type": "string",
            "maxLength": 255
          },
          "buildingNumber": {
            "type": "string",
            "maxLength": 4
          },
          "plotIdentification": {
            "type": "string",
            "maxLength": 64
          },
          "citySubdivisionName": {
            "type": "string",
            "maxLength": 255
          },
          "cityName": {
            "type": "string",
            "maxLength": 255
          },
          "postalZone": {
            "type": "string",
            "maxLength": 5
          },
          "countrySubentity": {
            "type": "string",
            "maxLength": 255
          },
          "otherSellerIdScheme": {
            "type": "string",
            "maxLength": 16
          },
          "otherSellerIdValue": {
            "type": "string",
            "maxLength": 64
          }
        }
      },
      "ZatcaIssueDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Machine-readable ZATCA issue code.",
            "example": "BR-KSA-42"
          },
          "message": {
            "type": "string",
            "description": "Human-readable description of the warning/error.",
            "example": "Invoice line 3: tax category code does not match the standard rate."
          }
        },
        "required": [
          "code",
          "message"
        ]
      },
      "LineItemDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "itemId": {
            "type": "string",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "nullable": true
          },
          "itemCode": {
            "type": "string",
            "nullable": true
          },
          "hsnCode": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string"
          },
          "quantity": {
            "type": "number"
          },
          "unitPrice": {
            "type": "number"
          },
          "grossSubtotal": {
            "type": "number"
          },
          "discountAllocation": {
            "type": "number"
          },
          "subtotal": {
            "type": "number"
          },
          "taxRate": {
            "type": "number"
          },
          "taxAmount": {
            "type": "number"
          },
          "total": {
            "type": "number"
          },
          "sortOrder": {
            "type": "number"
          }
        },
        "required": [
          "id",
          "itemId",
          "itemName",
          "itemCode",
          "hsnCode",
          "description",
          "quantity",
          "unitPrice",
          "grossSubtotal",
          "discountAllocation",
          "subtotal",
          "taxRate",
          "taxAmount",
          "total",
          "sortOrder"
        ]
      },
      "InvoiceDto": {
        "type": "object",
        "properties": {
          "zatcaWarnings": {
            "nullable": true,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ZatcaIssueDto"
            }
          },
          "zatcaErrors": {
            "nullable": true,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ZatcaIssueDto"
            }
          },
          "id": {
            "type": "string"
          },
          "invoiceNumber": {
            "type": "string"
          },
          "customerId": {
            "type": "string"
          },
          "customerName": {
            "type": "string"
          },
          "issueDate": {
            "format": "date-time",
            "type": "string"
          },
          "dueDate": {
            "format": "date-time",
            "type": "string"
          },
          "subtotal": {
            "type": "number"
          },
          "discountType": {
            "enum": [
              "NONE",
              "PERCENT",
              "AMOUNT"
            ],
            "type": "string"
          },
          "discountValue": {
            "type": "number"
          },
          "discountAmount": {
            "type": "number"
          },
          "taxAmount": {
            "type": "number"
          },
          "total": {
            "type": "number"
          },
          "amountPaid": {
            "type": "number"
          },
          "balanceDue": {
            "type": "number"
          },
          "status": {
            "enum": [
              "DRAFT",
              "SENT",
              "PARTIALLY_PAID",
              "PAID",
              "VOID",
              "WRITTEN_OFF"
            ],
            "type": "string"
          },
          "isOpeningBalance": {
            "type": "boolean"
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "terms": {
            "type": "string",
            "nullable": true
          },
          "placeOfSupply": {
            "type": "string",
            "nullable": true
          },
          "reverseCharge": {
            "type": "boolean"
          },
          "invoiceType": {
            "enum": [
              "DE",
              "R",
              "SEZWP",
              "SEZWOP",
              "CBW"
            ],
            "type": "string"
          },
          "lastSentAt": {
            "format": "date-time",
            "type": "string",
            "nullable": true
          },
          "lastSentVia": {
            "type": "string",
            "nullable": true
          },
          "lineItems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineItemDto"
            }
          },
          "createdAt": {
            "format": "date-time",
            "type": "string"
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string"
          },
          "uuid": {
            "type": "string",
            "nullable": true
          },
          "icv": {
            "type": "string",
            "nullable": true
          },
          "pih": {
            "type": "string",
            "nullable": true
          },
          "issueTime": {
            "format": "date-time",
            "type": "string",
            "nullable": true
          },
          "ksaInvoiceSubtype": {
            "nullable": true,
            "enum": [
              "STANDARD",
              "SIMPLIFIED"
            ],
            "type": "string"
          },
          "ksaDocumentType": {
            "nullable": true,
            "enum": [
              "INVOICE",
              "CREDIT_NOTE",
              "DEBIT_NOTE"
            ],
            "type": "string"
          },
          "qrTlvBase64": {
            "type": "string",
            "nullable": true
          },
          "zatcaPhase": {
            "type": "number"
          },
          "issuedAt": {
            "format": "date-time",
            "type": "string",
            "nullable": true
          },
          "zatcaStatus": {
            "enum": [
              "FAILED",
              "REJECTED",
              "PENDING",
              "NOT_SUBMITTED",
              "SUBMITTING",
              "CLEARED",
              "REPORTED",
              "WARNINGS"
            ],
            "type": "string"
          },
          "zatcaClearedAt": {
            "format": "date-time",
            "type": "string",
            "nullable": true
          },
          "zatcaReportedAt": {
            "format": "date-time",
            "type": "string",
            "nullable": true
          },
          "zatcaAttemptCount": {
            "type": "number"
          },
          "zatcaLastAttemptAt": {
            "format": "date-time",
            "type": "string",
            "nullable": true
          },
          "zatcaResubmittableUntil": {
            "format": "date-time",
            "type": "string",
            "nullable": true
          },
          "zatcaParentSubmissionUuid": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "zatcaWarnings",
          "zatcaErrors",
          "id",
          "invoiceNumber",
          "customerId",
          "customerName",
          "issueDate",
          "dueDate",
          "subtotal",
          "discountType",
          "discountValue",
          "discountAmount",
          "taxAmount",
          "total",
          "amountPaid",
          "balanceDue",
          "status",
          "isOpeningBalance",
          "notes",
          "terms",
          "placeOfSupply",
          "reverseCharge",
          "invoiceType",
          "lastSentAt",
          "lastSentVia",
          "lineItems",
          "createdAt",
          "updatedAt",
          "uuid",
          "icv",
          "pih",
          "issueTime",
          "ksaInvoiceSubtype",
          "ksaDocumentType",
          "qrTlvBase64",
          "zatcaPhase",
          "issuedAt",
          "zatcaStatus",
          "zatcaClearedAt",
          "zatcaReportedAt",
          "zatcaAttemptCount",
          "zatcaLastAttemptAt",
          "zatcaResubmittableUntil",
          "zatcaParentSubmissionUuid"
        ]
      },
      "InvoiceListDto": {
        "type": "object",
        "properties": {
          "invoices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceDto"
            }
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "invoices",
          "total"
        ]
      },
      "CreateLineItemDto": {
        "type": "object",
        "properties": {
          "itemId": {
            "type": "string",
            "description": "Link the line to a catalog item (optional — freehand lines are allowed).",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "description": {
            "type": "string",
            "description": "Line description shown on the invoice.",
            "example": "Consulting — April"
          },
          "quantity": {
            "type": "number",
            "minimum": 0.01,
            "description": "Quantity sold (supports 2 decimal places).",
            "example": 10
          },
          "unitPrice": {
            "type": "number",
            "minimum": 0,
            "description": "Unit price in the business currency (tax-inclusive if business is configured tax-inclusive).",
            "example": 150
          },
          "taxRate": {
            "type": "number",
            "minimum": 0,
            "description": "Tax rate as a percentage (e.g. 18 = 18%). Falls back to the business default tax rate if omitted.",
            "example": 18
          },
          "sortOrder": {
            "type": "number",
            "minimum": 0,
            "description": "Display order on the invoice (ascending). Defaults to array index.",
            "example": 0
          }
        },
        "required": [
          "description",
          "quantity",
          "unitPrice"
        ]
      },
      "CreateInvoiceDto": {
        "type": "object",
        "properties": {
          "customerId": {
            "type": "string",
            "description": "Customer ID the invoice is billed to.",
            "example": "clxk7j2p900012a3b4c5d6e7f"
          },
          "issueDate": {
            "type": "string",
            "description": "Invoice issue date (ISO 8601). Defaults to today.",
            "example": "2026-04-14",
            "format": "date"
          },
          "dueDate": {
            "type": "string",
            "description": "Due date (ISO 8601). Defaults to issueDate + business payment terms.",
            "example": "2026-05-14",
            "format": "date"
          },
          "notes": {
            "type": "string",
            "description": "Free-form notes shown on the invoice.",
            "example": "Payment terms: Net 30"
          },
          "terms": {
            "type": "string",
            "description": "Terms & conditions text shown at the bottom of the invoice.",
            "example": "Late payments incur 1.5% monthly interest."
          },
          "placeOfSupply": {
            "type": "string",
            "description": "India GST only — 2-digit state code for place of supply (e.g. '27' for Maharashtra).",
            "example": "27",
            "maxLength": 2
          },
          "reverseCharge": {
            "type": "boolean",
            "description": "India GST only — set true when this outward supply is reportable under reverse charge (recipient pays GST). Default false. Audit C4.",
            "example": false
          },
          "invoiceType": {
            "enum": [
              "R",
              "SEZWP",
              "SEZWOP",
              "DE",
              "CBW"
            ],
            "type": "string",
            "description": "India GST only — GSTR-1 invoiceType. R=Regular, SEZWP/SEZWOP=SEZ with/without payment, DE=Deemed Export, CBW=Customs Bonded Warehouse. Default R. Audit C4.",
            "example": "R"
          },
          "discountType": {
            "enum": [
              "NONE",
              "PERCENT",
              "AMOUNT"
            ],
            "type": "string",
            "description": "Invoice-level discount type (applied pre-tax). Omit or use NONE for no discount.",
            "example": "PERCENT"
          },
          "discountValue": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Discount value: percentage (if discountType=PERCENT, 0-100) or flat amount (if AMOUNT).",
            "example": 10
          },
          "lineItems": {
            "minItems": 1,
            "description": "Line items on the invoice. At least one required.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateLineItemDto"
            }
          }
        },
        "required": [
          "customerId",
          "lineItems"
        ]
      },
      "CreateOpeningBalanceDto": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "minimum": 0.01,
            "description": "Amount owed to the supplier as of the opening-balance date.",
            "example": 500
          },
          "date": {
            "type": "string",
            "description": "As-of date (ISO 8601). Defaults to the day before the current fiscal year starts."
          },
          "reference": {
            "type": "string",
            "description": "Free-form reference (e.g. \"Migrated from legacy system\")."
          }
        },
        "required": [
          "amount"
        ]
      },
      "CreatePaymentDto": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "minimum": 0.01,
            "description": "Amount received, in business currency.",
            "example": 1500
          },
          "paymentDate": {
            "type": "string",
            "description": "Date payment was received (ISO 8601). Defaults to today.",
            "example": "2026-04-14",
            "format": "date"
          },
          "paymentMethod": {
            "enum": [
              "CASH",
              "BANK_TRANSFER",
              "CARD",
              "OTHER"
            ],
            "type": "string",
            "description": "How the customer paid. See the Payment Methods reference.",
            "example": "BANK_TRANSFER"
          },
          "reference": {
            "type": "string",
            "description": "Bank reference / cheque # / transaction ID.",
            "example": "TXN-12345"
          },
          "notes": {
            "type": "string",
            "description": "Free-form notes.",
            "example": "Partial payment — balance by month-end"
          },
          "cashAccountId": {
            "type": "string",
            "description": "Cash/Bank account to post the cash side of the payment to. Must be within the Cash (1200) / Bank (1210) subtree. When omitted, defaults by payment method.",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          }
        },
        "required": [
          "amount",
          "paymentMethod"
        ]
      },
      "BulkInvoiceInput": {
        "type": "object",
        "properties": {
          "customerId": {
            "type": "string",
            "description": "Customer ID the invoice is billed to.",
            "example": "clxk7j2p900012a3b4c5d6e7f"
          },
          "issueDate": {
            "type": "string",
            "description": "Invoice issue date (ISO 8601). Defaults to today.",
            "example": "2026-04-14",
            "format": "date"
          },
          "dueDate": {
            "type": "string",
            "description": "Due date (ISO 8601). Defaults to issueDate + business payment terms.",
            "example": "2026-05-14",
            "format": "date"
          },
          "notes": {
            "type": "string",
            "description": "Free-form notes shown on the invoice.",
            "example": "Payment terms: Net 30"
          },
          "terms": {
            "type": "string",
            "description": "Terms & conditions text shown at the bottom of the invoice.",
            "example": "Late payments incur 1.5% monthly interest."
          },
          "placeOfSupply": {
            "type": "string",
            "description": "India GST only — 2-digit state code for place of supply (e.g. '27' for Maharashtra).",
            "example": "27",
            "maxLength": 2
          },
          "reverseCharge": {
            "type": "boolean",
            "description": "India GST only — set true when this outward supply is reportable under reverse charge (recipient pays GST). Default false. Audit C4.",
            "example": false
          },
          "invoiceType": {
            "enum": [
              "R",
              "SEZWP",
              "SEZWOP",
              "DE",
              "CBW"
            ],
            "type": "string",
            "description": "India GST only — GSTR-1 invoiceType. R=Regular, SEZWP/SEZWOP=SEZ with/without payment, DE=Deemed Export, CBW=Customs Bonded Warehouse. Default R. Audit C4.",
            "example": "R"
          },
          "discountType": {
            "enum": [
              "NONE",
              "PERCENT",
              "AMOUNT"
            ],
            "type": "string",
            "description": "Invoice-level discount type (applied pre-tax). Omit or use NONE for no discount.",
            "example": "PERCENT"
          },
          "discountValue": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Discount value: percentage (if discountType=PERCENT, 0-100) or flat amount (if AMOUNT).",
            "example": 10
          },
          "lineItems": {
            "minItems": 1,
            "description": "Line items on the invoice. At least one required.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateLineItemDto"
            }
          },
          "clientRef": {
            "type": "string",
            "maxLength": 100,
            "description": "Caller-supplied correlation reference, echoed back in the matching per-row result so you can map results to your source records. Not persisted.",
            "example": "order-1001"
          },
          "idempotencyKey": {
            "type": "string",
            "maxLength": 100,
            "description": "Idempotency key for safe retries. If a previous request already created an invoice with this key, the existing invoice is returned (status `duplicate`) instead of creating a second one. Keys are namespaced per calling app. Use a stable unique value from your system (e.g. your order ID).",
            "example": "order-1001"
          },
          "payment": {
            "description": "Optional payment to record against the invoice (for already-paid sales). When present, the invoice is marked as sent and the payment is posted. Use the full invoice total to mark it fully paid, or a smaller amount for a partial payment. The payment outcome is reported per row via paymentId / paymentError.",
            "allOf": [
              {
                "$ref": "#/components/schemas/CreatePaymentDto"
              }
            ]
          }
        },
        "required": [
          "customerId",
          "lineItems"
        ]
      },
      "BulkImportInvoicesDto": {
        "type": "object",
        "properties": {
          "invoices": {
            "minItems": 1,
            "maxItems": 200,
            "description": "Invoices to create (1–200 per request). Rows are processed independently: a bad row is reported in the result without aborting the batch.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BulkInvoiceInput"
            }
          }
        },
        "required": [
          "invoices"
        ]
      },
      "UpdateInvoiceDto": {
        "type": "object",
        "properties": {
          "customerId": {
            "type": "string"
          },
          "issueDate": {
            "type": "string"
          },
          "dueDate": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "terms": {
            "type": "string"
          },
          "placeOfSupply": {
            "type": "string"
          },
          "reverseCharge": {
            "type": "boolean"
          },
          "invoiceType": {
            "type": "string",
            "enum": [
              "DE",
              "R",
              "SEZWP",
              "SEZWOP",
              "CBW"
            ]
          },
          "discountType": {
            "type": "string",
            "enum": [
              "NONE",
              "PERCENT",
              "AMOUNT"
            ]
          },
          "discountValue": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "lineItems": {
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateLineItemDto"
            }
          }
        }
      },
      "SendInvoiceDto": {
        "type": "object",
        "properties": {
          "via": {
            "type": "string",
            "enum": [
              "whatsapp",
              "email",
              "download"
            ]
          }
        },
        "required": [
          "via"
        ]
      },
      "WriteOffInvoiceDto": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "minimum": 0.01,
            "description": "Amount to write off, in business currency. Defaults to the full outstanding balance. Supply a smaller value for a partial write-off — the invoice stays payable for the remainder.",
            "example": 250
          },
          "writeOffDate": {
            "type": "string",
            "description": "Date the debt was judged uncollectible (ISO 8601). Defaults to today. Period-locked like any other posting.",
            "example": "2026-08-11",
            "format": "date"
          },
          "reason": {
            "type": "string",
            "description": "Why the debt is uncollectible — recorded on the journal entry description.",
            "example": "Customer entered liquidation"
          }
        }
      },
      "PaymentDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "paymentDate": {
            "format": "date-time",
            "type": "string"
          },
          "paymentMethod": {
            "enum": [
              "CASH",
              "BANK_TRANSFER",
              "CARD",
              "OTHER"
            ],
            "type": "string"
          },
          "reference": {
            "type": "string",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "invoiceId": {
            "type": "string",
            "nullable": true
          },
          "invoiceNumber": {
            "type": "string",
            "nullable": true
          },
          "customerId": {
            "type": "string",
            "nullable": true
          },
          "customerName": {
            "type": "string"
          },
          "cashAccountId": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "amount",
          "paymentDate",
          "paymentMethod",
          "reference",
          "notes",
          "invoiceId",
          "invoiceNumber",
          "customerId",
          "customerName",
          "cashAccountId",
          "createdAt"
        ]
      },
      "PaymentListDto": {
        "type": "object",
        "properties": {
          "payments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentDto"
            }
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "payments",
          "total"
        ]
      },
      "CreateStandalonePaymentDto": {
        "type": "object",
        "properties": {
          "customerId": {
            "type": "string",
            "description": "Customer receiving credit for the payment.",
            "example": "clxk7j2p900012a3b4c5d6e7f"
          },
          "invoiceId": {
            "type": "string",
            "description": "Optionally apply to a specific invoice. Omit for on-account credit.",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "amount": {
            "type": "number",
            "minimum": 0.01,
            "description": "Amount received, in business currency.",
            "example": 1500
          },
          "paymentDate": {
            "type": "string",
            "description": "Date payment was received (ISO 8601). Defaults to today.",
            "example": "2026-04-14",
            "format": "date"
          },
          "paymentMethod": {
            "enum": [
              "CASH",
              "BANK_TRANSFER",
              "CARD",
              "OTHER"
            ],
            "type": "string",
            "description": "How the customer paid. See the Payment Methods reference.",
            "example": "CASH"
          },
          "reference": {
            "type": "string",
            "description": "Bank reference / cheque # / transaction ID.",
            "example": "RCPT-001"
          },
          "notes": {
            "type": "string",
            "description": "Free-form notes.",
            "example": "Walk-in customer"
          },
          "cashAccountId": {
            "type": "string",
            "description": "Cash/Bank account to post the cash side of the payment to. Must be within the Cash (1200) / Bank (1210) subtree. When omitted, defaults by payment method.",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          }
        },
        "required": [
          "customerId",
          "amount",
          "paymentMethod"
        ]
      },
      "PaymentAllocationInputDto": {
        "type": "object",
        "properties": {
          "invoiceId": {
            "type": "string",
            "description": "Outstanding invoice to apply this allocation to.",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "amount": {
            "type": "number",
            "minimum": 0.01,
            "description": "Amount of this payment to apply to the invoice.",
            "example": 600
          }
        },
        "required": [
          "invoiceId",
          "amount"
        ]
      },
      "PaymentReturnApplicationInputDto": {
        "type": "object",
        "properties": {
          "salesReturnId": {
            "type": "string",
            "description": "Open sales return (credit note) whose credit is applied against the invoices.",
            "example": "clxkpr8bc00011a2b3c4d5e6f7"
          },
          "amount": {
            "type": "number",
            "minimum": 0.01,
            "description": "Amount of the return credit to apply.",
            "example": 200
          }
        },
        "required": [
          "salesReturnId",
          "amount"
        ]
      },
      "AllocatePaymentDto": {
        "type": "object",
        "properties": {
          "customerId": {
            "type": "string",
            "description": "Customer the payment is received from.",
            "example": "clxk7j2p900012a3b4c5d6e7f"
          },
          "cashAmount": {
            "type": "number",
            "minimum": 0,
            "description": "Cash actually received, in business currency. Must equal sum(allocations) - sum(returnApplications). May be 0 for pure netting.",
            "example": 800
          },
          "paymentDate": {
            "type": "string",
            "description": "Date received (ISO 8601). Defaults to today.",
            "example": "2026-05-18",
            "format": "date"
          },
          "paymentMethod": {
            "enum": [
              "CASH",
              "BANK_TRANSFER",
              "CARD",
              "OTHER"
            ],
            "type": "string",
            "description": "How the cash portion was received.",
            "example": "BANK_TRANSFER"
          },
          "reference": {
            "type": "string",
            "maxLength": 100,
            "description": "Bank reference / cheque # / transaction ID.",
            "example": "NEFT-9982311"
          },
          "notes": {
            "type": "string",
            "maxLength": 500,
            "description": "Free-form notes.",
            "example": "Settling Apr invoices"
          },
          "cashAccountId": {
            "type": "string",
            "description": "Cash/Bank account to post the cash side of the payment to. Must be within the Cash (1200) / Bank (1210) subtree. When omitted, defaults by payment method.",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "allocations": {
            "minItems": 1,
            "description": "Invoices this payment is applied against. At least one is required.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentAllocationInputDto"
            }
          },
          "returnApplications": {
            "description": "Open sales-return credits to apply against the invoices. Empty array if no credits used.",
            "default": [],
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentReturnApplicationInputDto"
            }
          }
        },
        "required": [
          "customerId",
          "cashAmount",
          "paymentMethod",
          "allocations"
        ]
      },
      "SalesReturnLineItemDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "itemId": {
            "type": "string",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "nullable": true
          },
          "itemCode": {
            "type": "string",
            "nullable": true
          },
          "hsnCode": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string"
          },
          "quantity": {
            "type": "number"
          },
          "unitPrice": {
            "type": "number"
          },
          "subtotal": {
            "type": "number"
          },
          "taxRate": {
            "type": "number"
          },
          "taxAmount": {
            "type": "number"
          },
          "total": {
            "type": "number"
          },
          "sortOrder": {
            "type": "number"
          }
        },
        "required": [
          "id",
          "itemId",
          "itemName",
          "itemCode",
          "hsnCode",
          "description",
          "quantity",
          "unitPrice",
          "subtotal",
          "taxRate",
          "taxAmount",
          "total",
          "sortOrder"
        ]
      },
      "SalesReturnDto": {
        "type": "object",
        "properties": {
          "zatcaWarnings": {
            "nullable": true,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ZatcaIssueDto"
            }
          },
          "zatcaErrors": {
            "nullable": true,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ZatcaIssueDto"
            }
          },
          "id": {
            "type": "string"
          },
          "returnNumber": {
            "type": "string"
          },
          "customerId": {
            "type": "string"
          },
          "customerName": {
            "type": "string"
          },
          "invoiceId": {
            "type": "string",
            "nullable": true
          },
          "invoiceNumber": {
            "type": "string",
            "nullable": true
          },
          "returnDate": {
            "format": "date-time",
            "type": "string"
          },
          "subtotal": {
            "type": "number"
          },
          "taxAmount": {
            "type": "number"
          },
          "total": {
            "type": "number"
          },
          "amountRefunded": {
            "type": "number"
          },
          "balanceDue": {
            "type": "number"
          },
          "status": {
            "enum": [
              "DRAFT",
              "VOID",
              "CONFIRMED",
              "PARTIALLY_REFUNDED",
              "REFUNDED"
            ],
            "type": "string"
          },
          "reason": {
            "type": "string",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "lineItems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SalesReturnLineItemDto"
            }
          },
          "createdAt": {
            "format": "date-time",
            "type": "string"
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string"
          },
          "uuid": {
            "type": "string",
            "nullable": true
          },
          "icv": {
            "type": "string",
            "nullable": true
          },
          "pih": {
            "type": "string",
            "nullable": true
          },
          "issueTime": {
            "format": "date-time",
            "type": "string",
            "nullable": true
          },
          "ksaInvoiceSubtype": {
            "nullable": true,
            "enum": [
              "STANDARD",
              "SIMPLIFIED"
            ],
            "type": "string"
          },
          "ksaDocumentType": {
            "nullable": true,
            "enum": [
              "INVOICE",
              "CREDIT_NOTE",
              "DEBIT_NOTE"
            ],
            "type": "string"
          },
          "qrTlvBase64": {
            "type": "string",
            "nullable": true
          },
          "zatcaPhase": {
            "type": "number"
          },
          "issuedAt": {
            "format": "date-time",
            "type": "string",
            "nullable": true
          },
          "zatcaStatus": {
            "enum": [
              "FAILED",
              "REJECTED",
              "PENDING",
              "NOT_SUBMITTED",
              "SUBMITTING",
              "CLEARED",
              "REPORTED",
              "WARNINGS"
            ],
            "type": "string"
          },
          "zatcaClearedAt": {
            "format": "date-time",
            "type": "string",
            "nullable": true
          },
          "zatcaReportedAt": {
            "format": "date-time",
            "type": "string",
            "nullable": true
          },
          "zatcaAttemptCount": {
            "type": "number"
          },
          "zatcaLastAttemptAt": {
            "format": "date-time",
            "type": "string",
            "nullable": true
          },
          "zatcaResubmittableUntil": {
            "format": "date-time",
            "type": "string",
            "nullable": true
          },
          "zatcaParentSubmissionUuid": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "zatcaWarnings",
          "zatcaErrors",
          "id",
          "returnNumber",
          "customerId",
          "customerName",
          "invoiceId",
          "invoiceNumber",
          "returnDate",
          "subtotal",
          "taxAmount",
          "total",
          "amountRefunded",
          "balanceDue",
          "status",
          "reason",
          "notes",
          "lineItems",
          "createdAt",
          "updatedAt",
          "uuid",
          "icv",
          "pih",
          "issueTime",
          "ksaInvoiceSubtype",
          "ksaDocumentType",
          "qrTlvBase64",
          "zatcaPhase",
          "issuedAt",
          "zatcaStatus",
          "zatcaClearedAt",
          "zatcaReportedAt",
          "zatcaAttemptCount",
          "zatcaLastAttemptAt",
          "zatcaResubmittableUntil",
          "zatcaParentSubmissionUuid"
        ]
      },
      "SalesReturnListDto": {
        "type": "object",
        "properties": {
          "salesReturns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SalesReturnDto"
            }
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "salesReturns",
          "total"
        ]
      },
      "CreateSalesReturnLineItemDto": {
        "type": "object",
        "properties": {
          "itemId": {
            "type": "string",
            "description": "Catalog item being returned (optional).",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "originalLineItemId": {
            "type": "string",
            "description": "LineItem id on the original invoice being returned (BL-CRIT-2). When supplied, the server caps return qty at (invoiced qty − prior returns for this line) and verifies unitPrice matches the invoice line. Strongly recommended — will become required in a future release.",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "description": {
            "type": "string",
            "description": "Line description.",
            "example": "Widget v2 — defective batch"
          },
          "quantity": {
            "type": "number",
            "minimum": 0.01,
            "description": "Quantity being returned.",
            "example": 2
          },
          "unitPrice": {
            "type": "number",
            "minimum": 0,
            "description": "Unit price being credited.",
            "example": 150
          },
          "taxRate": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Tax rate percent (must match the original invoice line for linked returns).",
            "example": 18
          },
          "sortOrder": {
            "type": "number",
            "minimum": 0,
            "description": "Display order.",
            "example": 0
          }
        },
        "required": [
          "description",
          "quantity",
          "unitPrice"
        ]
      },
      "CreateSalesReturnDto": {
        "type": "object",
        "properties": {
          "customerId": {
            "type": "string",
            "description": "Customer the return is issued to (credit note recipient).",
            "example": "clxk7j2p900012a3b4c5d6e7f"
          },
          "invoiceId": {
            "type": "string",
            "description": "Original invoice this return applies to. Omit for standalone credit note.",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "returnDate": {
            "type": "string",
            "description": "Return date (ISO 8601). Defaults to today.",
            "example": "2026-04-14",
            "format": "date"
          },
          "reason": {
            "type": "string",
            "description": "Reason for return (shown on the credit note).",
            "example": "Damaged on arrival"
          },
          "notes": {
            "type": "string",
            "description": "Free-form internal notes.",
            "example": "Customer confirmed by email"
          },
          "lineItems": {
            "minItems": 1,
            "description": "Return line items — goods/services being returned. At least one required.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateSalesReturnLineItemDto"
            }
          }
        },
        "required": [
          "customerId",
          "lineItems"
        ]
      },
      "RefundSalesReturnDto": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "minimum": 0.0001,
            "description": "Amount being refunded to the customer.",
            "example": 125.5
          },
          "paymentMethod": {
            "enum": [
              "CASH",
              "BANK_TRANSFER",
              "CARD",
              "OTHER"
            ],
            "type": "string",
            "description": "How the refund was disbursed.",
            "example": "BANK_TRANSFER"
          },
          "refundDate": {
            "type": "string",
            "description": "Refund disbursement date. Defaults to today if omitted.",
            "example": "2026-04-28"
          },
          "reference": {
            "type": "string",
            "description": "External reference such as UTR, cheque number, or card reference.",
            "example": "UTR-998877"
          },
          "notes": {
            "type": "string",
            "description": "Internal note for the refund disbursement.",
            "example": "Customer refunded via bank transfer"
          },
          "cashAccountId": {
            "type": "string",
            "description": "Optional Cash/Bank account id to credit for the refund. Must be a Cash/Bank account. Falls back to the default account for the payment method when omitted."
          }
        },
        "required": [
          "amount",
          "paymentMethod"
        ]
      },
      "PurchaseReturnLineItemDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "itemId": {
            "type": "string",
            "nullable": true
          },
          "itemName": {
            "type": "string",
            "nullable": true
          },
          "itemCode": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string"
          },
          "quantity": {
            "type": "number"
          },
          "unitPrice": {
            "type": "number"
          },
          "subtotal": {
            "type": "number"
          },
          "taxRate": {
            "type": "number"
          },
          "taxAmount": {
            "type": "number"
          },
          "total": {
            "type": "number"
          },
          "sortOrder": {
            "type": "number"
          }
        },
        "required": [
          "id",
          "itemId",
          "itemName",
          "itemCode",
          "description",
          "quantity",
          "unitPrice",
          "subtotal",
          "taxRate",
          "taxAmount",
          "total",
          "sortOrder"
        ]
      },
      "PurchaseReturnDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "returnNumber": {
            "type": "string"
          },
          "supplierId": {
            "type": "string"
          },
          "supplierName": {
            "type": "string"
          },
          "purchaseId": {
            "type": "string",
            "nullable": true
          },
          "purchaseNumber": {
            "type": "string",
            "nullable": true
          },
          "returnDate": {
            "format": "date-time",
            "type": "string"
          },
          "subtotal": {
            "type": "number"
          },
          "taxAmount": {
            "type": "number"
          },
          "total": {
            "type": "number"
          },
          "amountRefunded": {
            "type": "number"
          },
          "balanceDue": {
            "type": "number"
          },
          "status": {
            "enum": [
              "DRAFT",
              "VOID",
              "CONFIRMED",
              "PARTIALLY_REFUNDED",
              "REFUNDED"
            ],
            "type": "string"
          },
          "reason": {
            "type": "string",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "lineItems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PurchaseReturnLineItemDto"
            }
          },
          "createdAt": {
            "format": "date-time",
            "type": "string"
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "returnNumber",
          "supplierId",
          "supplierName",
          "purchaseId",
          "purchaseNumber",
          "returnDate",
          "subtotal",
          "taxAmount",
          "total",
          "amountRefunded",
          "balanceDue",
          "status",
          "reason",
          "notes",
          "lineItems",
          "createdAt",
          "updatedAt"
        ]
      },
      "PurchaseReturnListDto": {
        "type": "object",
        "properties": {
          "purchaseReturns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PurchaseReturnDto"
            }
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "purchaseReturns",
          "total"
        ]
      },
      "CreatePurchaseReturnLineItemDto": {
        "type": "object",
        "properties": {
          "itemId": {
            "type": "string",
            "description": "Catalog item being returned (optional).",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "originalLineItemId": {
            "type": "string",
            "description": "PurchaseLineItem id on the original purchase being returned (BL-CRIT-2). When supplied, the server caps return qty at (purchased qty − prior returns for this line) and verifies unitPrice matches. Strongly recommended — will become required in a future release.",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "description": {
            "type": "string",
            "description": "Line description.",
            "example": "Office chair — wrong color"
          },
          "quantity": {
            "type": "number",
            "minimum": 0.01,
            "description": "Quantity being returned.",
            "example": 1
          },
          "unitPrice": {
            "type": "number",
            "minimum": 0,
            "description": "Unit price being debited.",
            "example": 450
          },
          "taxRate": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Tax rate percent (must match the original purchase line for linked returns).",
            "example": 18
          },
          "sortOrder": {
            "type": "number",
            "minimum": 0,
            "description": "Display order.",
            "example": 0
          }
        },
        "required": [
          "description",
          "quantity",
          "unitPrice"
        ]
      },
      "CreatePurchaseReturnDto": {
        "type": "object",
        "properties": {
          "supplierId": {
            "type": "string",
            "description": "Supplier the return is issued to (debit note recipient).",
            "example": "clxk7j2p900012a3b4c5d6e7f"
          },
          "purchaseId": {
            "type": "string",
            "description": "Original purchase bill this return applies to.",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "returnDate": {
            "type": "string",
            "description": "Return date (ISO 8601). Defaults to today.",
            "example": "2026-04-14",
            "format": "date"
          },
          "reason": {
            "type": "string",
            "description": "Reason for return.",
            "example": "Wrong item shipped"
          },
          "notes": {
            "type": "string",
            "description": "Free-form internal notes.",
            "example": "RMA #R-1023"
          },
          "lineItems": {
            "minItems": 1,
            "description": "Line items being returned to the supplier. At least one required.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreatePurchaseReturnLineItemDto"
            }
          }
        },
        "required": [
          "supplierId",
          "lineItems"
        ]
      },
      "RefundPurchaseReturnDto": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "minimum": 0.0001,
            "description": "Amount being refunded by the supplier.",
            "example": 125.5
          },
          "paymentMethod": {
            "enum": [
              "CASH",
              "BANK_TRANSFER",
              "CARD",
              "OTHER"
            ],
            "type": "string",
            "description": "How the refund was received.",
            "example": "BANK_TRANSFER"
          },
          "refundDate": {
            "type": "string",
            "description": "Refund receipt date. Defaults to today if omitted.",
            "example": "2026-04-28"
          },
          "reference": {
            "type": "string",
            "description": "External reference such as UTR, cheque number, or transfer reference.",
            "example": "UTR-998877"
          },
          "notes": {
            "type": "string",
            "description": "Internal note for the refund receipt.",
            "example": "Supplier refunded via bank transfer"
          },
          "cashAccountId": {
            "type": "string",
            "description": "Optional Cash/Bank account id to debit for the refund. Must be a Cash/Bank account. Falls back to the default account for the payment method when omitted."
          }
        },
        "required": [
          "amount",
          "paymentMethod"
        ]
      },
      "ExpenseDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "date": {
            "format": "date-time",
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "accountCode": {
            "type": "string"
          },
          "accountName": {
            "type": "string"
          },
          "paymentMethod": {
            "enum": [
              "CASH",
              "BANK_TRANSFER"
            ],
            "type": "string"
          },
          "reference": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "date",
          "description",
          "amount",
          "accountCode",
          "accountName",
          "paymentMethod",
          "createdAt"
        ]
      },
      "ExpenseListDto": {
        "type": "object",
        "properties": {
          "expenses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExpenseDto"
            }
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "expenses",
          "total"
        ]
      },
      "CreateExpenseDto": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "description": "Date of the expense (ISO 8601). Defaults to today.",
            "example": "2026-04-14",
            "format": "date"
          },
          "description": {
            "type": "string",
            "description": "Short description of the expense.",
            "example": "Office supplies — ream of paper & pens"
          },
          "amount": {
            "type": "number",
            "minimum": 0.01,
            "description": "Expense amount in business currency.",
            "example": 125.5
          },
          "accountCode": {
            "type": "string",
            "description": "Expense account code (5xxx series in the default chart of accounts).",
            "example": "5400"
          },
          "paymentMethod": {
            "enum": [
              "CASH",
              "BANK_TRANSFER"
            ],
            "type": "string",
            "description": "How it was paid. Only CASH and BANK_TRANSFER are accepted here.",
            "example": "CASH"
          },
          "reference": {
            "type": "string",
            "description": "Receipt number or any external reference.",
            "example": "RCPT-20260414-001"
          },
          "cashAccountId": {
            "type": "string",
            "description": "Optional Cash/Bank account id to credit. Must be a Cash/Bank account. Falls back to the default account for the payment method when omitted."
          }
        },
        "required": [
          "description",
          "amount",
          "accountCode",
          "paymentMethod"
        ]
      },
      "ExpenseAccountDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "id",
          "code",
          "name"
        ]
      },
      "AccountLineDto": {
        "type": "object",
        "properties": {
          "accountCode": {
            "type": "string"
          },
          "accountName": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          }
        },
        "required": [
          "accountCode",
          "accountName",
          "amount"
        ]
      },
      "ProfitLossDto": {
        "type": "object",
        "properties": {
          "startDate": {
            "format": "date-time",
            "type": "string"
          },
          "endDate": {
            "format": "date-time",
            "type": "string"
          },
          "period": {
            "type": "string"
          },
          "totalRevenue": {
            "type": "number",
            "description": "Total revenue for the period"
          },
          "totalExpenses": {
            "type": "number",
            "description": "Total expenses for the period"
          },
          "netProfit": {
            "type": "number",
            "description": "Net profit (revenue - expenses)"
          },
          "salesReturns": {
            "type": "number",
            "description": "Total sales returns for the period"
          },
          "purchaseReturns": {
            "type": "number",
            "description": "Total purchase returns for the period"
          },
          "revenueAccounts": {
            "description": "Revenue by account",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountLineDto"
            }
          },
          "expenseAccounts": {
            "description": "Expenses by account",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountLineDto"
            }
          }
        },
        "required": [
          "startDate",
          "endDate",
          "period",
          "totalRevenue",
          "totalExpenses",
          "netProfit",
          "salesReturns",
          "purchaseReturns",
          "revenueAccounts",
          "expenseAccounts"
        ]
      },
      "AccountBalanceDto": {
        "type": "object",
        "properties": {
          "accountCode": {
            "type": "string"
          },
          "accountName": {
            "type": "string"
          },
          "balance": {
            "type": "number"
          }
        },
        "required": [
          "accountCode",
          "accountName",
          "balance"
        ]
      },
      "BalanceSheetSectionDto": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountBalanceDto"
            }
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "items",
          "total"
        ]
      },
      "EquitySectionDto": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountBalanceDto"
            }
          },
          "retainedEarnings": {
            "type": "number",
            "description": "Calculated retained earnings (cumulative net income)"
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "items",
          "retainedEarnings",
          "total"
        ]
      },
      "BalanceSheetDto": {
        "type": "object",
        "properties": {
          "asOfDate": {
            "format": "date-time",
            "type": "string"
          },
          "assets": {
            "$ref": "#/components/schemas/BalanceSheetSectionDto"
          },
          "liabilities": {
            "$ref": "#/components/schemas/BalanceSheetSectionDto"
          },
          "equity": {
            "$ref": "#/components/schemas/EquitySectionDto"
          },
          "isBalanced": {
            "type": "boolean",
            "description": "Total assets should equal liabilities + equity"
          }
        },
        "required": [
          "asOfDate",
          "assets",
          "liabilities",
          "equity",
          "isBalanced"
        ]
      },
      "CashFlowItemDto": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "sourceType": {
            "type": "string",
            "description": "Source type: INVOICE, PAYMENT, EXPENSE, MANUAL"
          }
        },
        "required": [
          "description",
          "amount",
          "sourceType"
        ]
      },
      "CashFlowCategoryDto": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CashFlowItemDto"
            }
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "items",
          "total"
        ]
      },
      "CashFlowDto": {
        "type": "object",
        "properties": {
          "startDate": {
            "format": "date-time",
            "type": "string"
          },
          "endDate": {
            "format": "date-time",
            "type": "string"
          },
          "period": {
            "type": "string"
          },
          "openingBalance": {
            "type": "number",
            "description": "Cash + Bank balance at start of period"
          },
          "operating": {
            "description": "Operating activities (customer payments, expenses)",
            "allOf": [
              {
                "$ref": "#/components/schemas/CashFlowCategoryDto"
              }
            ]
          },
          "investing": {
            "description": "Investing activities",
            "allOf": [
              {
                "$ref": "#/components/schemas/CashFlowCategoryDto"
              }
            ]
          },
          "financing": {
            "description": "Financing activities",
            "allOf": [
              {
                "$ref": "#/components/schemas/CashFlowCategoryDto"
              }
            ]
          },
          "totalInflows": {
            "type": "number",
            "description": "Total cash inflows for the period"
          },
          "totalOutflows": {
            "type": "number",
            "description": "Total cash outflows for the period"
          },
          "netChange": {
            "type": "number",
            "description": "Net change in cash (inflows - outflows)"
          },
          "closingBalance": {
            "type": "number",
            "description": "Cash + Bank balance at end of period"
          }
        },
        "required": [
          "startDate",
          "endDate",
          "period",
          "openingBalance",
          "operating",
          "investing",
          "financing",
          "totalInflows",
          "totalOutflows",
          "netChange",
          "closingBalance"
        ]
      },
      "TaxRateBreakdownDto": {
        "type": "object",
        "properties": {
          "rateName": {
            "type": "string"
          },
          "rate": {
            "type": "number"
          },
          "taxableAmount": {
            "type": "number"
          },
          "taxAmount": {
            "type": "number"
          },
          "transactionCount": {
            "type": "number"
          }
        },
        "required": [
          "rateName",
          "rate",
          "taxableAmount",
          "taxAmount",
          "transactionCount"
        ]
      },
      "TaxTransactionDto": {
        "type": "object",
        "properties": {
          "invoiceNumber": {
            "type": "string"
          },
          "date": {
            "type": "string"
          },
          "customerOrSupplier": {
            "type": "string"
          },
          "type": {
            "enum": [
              "PURCHASE",
              "PURCHASE_RETURN",
              "SALE",
              "RETURN",
              "ADJUSTMENT"
            ],
            "type": "string"
          },
          "subtotal": {
            "type": "number"
          },
          "taxRate": {
            "type": "number"
          },
          "taxAmount": {
            "type": "number"
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "invoiceNumber",
          "date",
          "customerOrSupplier",
          "type",
          "subtotal",
          "taxRate",
          "taxAmount",
          "total"
        ]
      },
      "TaxReportDto": {
        "type": "object",
        "properties": {
          "startDate": {
            "format": "date-time",
            "type": "string"
          },
          "endDate": {
            "format": "date-time",
            "type": "string"
          },
          "period": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "countryName": {
            "type": "string"
          },
          "taxName": {
            "type": "string"
          },
          "currency": {
            "type": "string"
          },
          "currencySymbol": {
            "type": "string"
          },
          "totalSalesExclTax": {
            "type": "number"
          },
          "totalOutputTax": {
            "type": "number"
          },
          "outputTaxBreakdown": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaxRateBreakdownDto"
            }
          },
          "totalPurchasesExclTax": {
            "type": "number"
          },
          "totalInputTax": {
            "type": "number"
          },
          "inputTaxBreakdown": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaxRateBreakdownDto"
            }
          },
          "netTaxPayable": {
            "type": "number"
          },
          "transactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaxTransactionDto"
            }
          }
        },
        "required": [
          "startDate",
          "endDate",
          "period",
          "country",
          "countryName",
          "taxName",
          "currency",
          "currencySymbol",
          "totalSalesExclTax",
          "totalOutputTax",
          "outputTaxBreakdown",
          "totalPurchasesExclTax",
          "totalInputTax",
          "inputTaxBreakdown",
          "netTaxPayable",
          "transactions"
        ]
      },
      "TaxQuarterDto": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string"
          },
          "startDate": {
            "format": "date-time",
            "type": "string"
          },
          "endDate": {
            "format": "date-time",
            "type": "string"
          },
          "outputTax": {
            "type": "number"
          },
          "inputTax": {
            "type": "number"
          },
          "netTax": {
            "type": "number"
          },
          "salesCount": {
            "type": "number"
          },
          "purchaseCount": {
            "type": "number"
          }
        },
        "required": [
          "label",
          "startDate",
          "endDate",
          "outputTax",
          "inputTax",
          "netTax",
          "salesCount",
          "purchaseCount"
        ]
      },
      "TaxSummaryDto": {
        "type": "object",
        "properties": {
          "startDate": {
            "format": "date-time",
            "type": "string"
          },
          "endDate": {
            "format": "date-time",
            "type": "string"
          },
          "period": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "countryName": {
            "type": "string"
          },
          "taxName": {
            "type": "string"
          },
          "currency": {
            "type": "string"
          },
          "currencySymbol": {
            "type": "string"
          },
          "registrationNumber": {
            "type": "string"
          },
          "totalOutputTax": {
            "type": "number"
          },
          "totalInputTax": {
            "type": "number"
          },
          "netTaxPayable": {
            "type": "number"
          },
          "quarters": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaxQuarterDto"
            }
          },
          "outputBreakdown": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaxRateBreakdownDto"
            }
          },
          "inputBreakdown": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaxRateBreakdownDto"
            }
          }
        },
        "required": [
          "startDate",
          "endDate",
          "period",
          "country",
          "countryName",
          "taxName",
          "currency",
          "currencySymbol",
          "totalOutputTax",
          "totalInputTax",
          "netTaxPayable",
          "quarters",
          "outputBreakdown",
          "inputBreakdown"
        ]
      },
      "TrialBalanceLineDto": {
        "type": "object",
        "properties": {
          "accountCode": {
            "type": "string"
          },
          "accountName": {
            "type": "string"
          },
          "accountType": {
            "type": "string"
          },
          "debit": {
            "type": "number"
          },
          "credit": {
            "type": "number"
          }
        },
        "required": [
          "accountCode",
          "accountName",
          "accountType",
          "debit",
          "credit"
        ]
      },
      "TrialBalanceDto": {
        "type": "object",
        "properties": {
          "asOfDate": {
            "format": "date-time",
            "type": "string"
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrialBalanceLineDto"
            }
          },
          "totalDebit": {
            "type": "number"
          },
          "totalCredit": {
            "type": "number"
          },
          "isBalanced": {
            "type": "boolean",
            "description": "Total debits should equal total credits"
          }
        },
        "required": [
          "asOfDate",
          "lines",
          "totalDebit",
          "totalCredit",
          "isBalanced"
        ]
      },
      "GeneralLedgerLineDto": {
        "type": "object",
        "properties": {
          "date": {
            "format": "date-time",
            "type": "string"
          },
          "journalNumber": {
            "type": "string"
          },
          "journalEntryId": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "sourceType": {
            "type": "string",
            "description": "The journal entry's source, e.g. INVOICE, PAYMENT, CONTRA, MANUAL"
          },
          "debit": {
            "type": "number"
          },
          "credit": {
            "type": "number"
          },
          "balance": {
            "type": "number",
            "description": "Running balance after this line (signed to normal side)"
          }
        },
        "required": [
          "date",
          "journalNumber",
          "journalEntryId",
          "description",
          "sourceType",
          "debit",
          "credit",
          "balance"
        ]
      },
      "GeneralLedgerAccountDto": {
        "type": "object",
        "properties": {
          "accountId": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "openingBalance": {
            "type": "number",
            "description": "Signed balance of all activity before startDate"
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GeneralLedgerLineDto"
            }
          },
          "totalDebit": {
            "type": "number"
          },
          "totalCredit": {
            "type": "number"
          },
          "closingBalance": {
            "type": "number"
          }
        },
        "required": [
          "accountId",
          "code",
          "name",
          "type",
          "openingBalance",
          "lines",
          "totalDebit",
          "totalCredit",
          "closingBalance"
        ]
      },
      "GeneralLedgerDto": {
        "type": "object",
        "properties": {
          "startDate": {
            "format": "date-time",
            "type": "string"
          },
          "endDate": {
            "format": "date-time",
            "type": "string"
          },
          "accounts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GeneralLedgerAccountDto"
            }
          }
        },
        "required": [
          "startDate",
          "endDate",
          "accounts"
        ]
      },
      "OpeningBalanceEquityEntryDto": {
        "type": "object",
        "properties": {
          "accountId": {
            "type": "string",
            "description": "Account that received the opening balance (non-3050 side)"
          },
          "code": {
            "type": "string",
            "description": "Account code"
          },
          "name": {
            "type": "string",
            "description": "Account name"
          },
          "amount": {
            "type": "number",
            "description": "Opening balance amount posted to the account"
          },
          "side": {
            "enum": [
              "debit",
              "credit"
            ],
            "type": "string",
            "description": "Side the opening balance hit on the account"
          }
        },
        "required": [
          "accountId",
          "code",
          "name",
          "amount",
          "side"
        ]
      },
      "OpeningBalanceEquityDto": {
        "type": "object",
        "properties": {
          "balance": {
            "type": "number",
            "description": "Current balance of Opening Balance Equity (account 3050), credit-normal (credit - debit). Should net to zero once all opening balances are offset."
          },
          "isBalanced": {
            "type": "boolean",
            "description": "Whether the Opening Balance Equity account nets to zero"
          },
          "openingDate": {
            "type": "string",
            "nullable": true,
            "description": "ISO date of the opening-balance entries, or null when none exist"
          },
          "entries": {
            "description": "Per-account opening-balance lines (non-3050 side)",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OpeningBalanceEquityEntryDto"
            }
          }
        },
        "required": [
          "balance",
          "isBalanced",
          "openingDate",
          "entries"
        ]
      },
      "CreateAccountDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "pattern": "^\\d{4}$",
            "description": "Account code (4 digits). When omitted, the next available code for the account type is generated automatically.",
            "example": "5100"
          },
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 100,
            "description": "Account name",
            "example": "Utilities Expense"
          },
          "type": {
            "enum": [
              "ASSET",
              "LIABILITY",
              "EQUITY",
              "REVENUE",
              "EXPENSE"
            ],
            "type": "string",
            "description": "Account type (ASSET / LIABILITY / EQUITY / REVENUE / EXPENSE).",
            "example": "EXPENSE"
          },
          "description": {
            "type": "string",
            "maxLength": 255,
            "description": "Freeform description shown in Accountant mode.",
            "example": "Electricity, water, internet"
          },
          "openingBalance": {
            "type": "number",
            "minimum": 0,
            "description": "Opening balance for the account",
            "example": 1000
          },
          "parentId": {
            "type": "string",
            "description": "Parent (header) account id. When set, this account is nested under the parent in the chart-of-accounts hierarchy. The parent must be the same account type."
          }
        },
        "required": [
          "name",
          "type"
        ]
      },
      "QuoteLineItemDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "quantity": {
            "type": "number"
          },
          "unitPrice": {
            "type": "number"
          },
          "subtotal": {
            "type": "number"
          },
          "taxRate": {
            "type": "number"
          },
          "taxAmount": {
            "type": "number"
          },
          "total": {
            "type": "number"
          },
          "sortOrder": {
            "type": "number"
          }
        },
        "required": [
          "id",
          "description",
          "quantity",
          "unitPrice",
          "subtotal",
          "taxRate",
          "taxAmount",
          "total",
          "sortOrder"
        ]
      },
      "QuoteDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "quoteNumber": {
            "type": "string"
          },
          "customerId": {
            "type": "string"
          },
          "customerName": {
            "type": "string"
          },
          "issueDate": {
            "format": "date-time",
            "type": "string"
          },
          "validUntil": {
            "format": "date-time",
            "type": "string"
          },
          "subtotal": {
            "type": "number"
          },
          "discountType": {
            "enum": [
              "NONE",
              "PERCENT",
              "AMOUNT"
            ],
            "type": "string"
          },
          "discountValue": {
            "type": "number"
          },
          "discountAmount": {
            "type": "number"
          },
          "taxAmount": {
            "type": "number"
          },
          "total": {
            "type": "number"
          },
          "status": {
            "enum": [
              "DRAFT",
              "REJECTED",
              "SENT",
              "ACCEPTED",
              "EXPIRED",
              "CONVERTED"
            ],
            "type": "string"
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "terms": {
            "type": "string",
            "nullable": true
          },
          "lastSentAt": {
            "format": "date-time",
            "type": "string",
            "nullable": true
          },
          "lastSentVia": {
            "type": "string",
            "nullable": true
          },
          "convertedToInvoiceId": {
            "type": "string",
            "nullable": true
          },
          "lineItems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/QuoteLineItemDto"
            }
          },
          "createdAt": {
            "format": "date-time",
            "type": "string"
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "quoteNumber",
          "customerId",
          "customerName",
          "issueDate",
          "validUntil",
          "subtotal",
          "discountType",
          "discountValue",
          "discountAmount",
          "taxAmount",
          "total",
          "status",
          "notes",
          "terms",
          "lastSentAt",
          "lastSentVia",
          "convertedToInvoiceId",
          "lineItems",
          "createdAt",
          "updatedAt"
        ]
      },
      "QuoteListDto": {
        "type": "object",
        "properties": {
          "quotes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/QuoteDto"
            }
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "quotes",
          "total"
        ]
      },
      "CreateQuoteLineItemDto": {
        "type": "object",
        "properties": {
          "itemId": {
            "type": "string",
            "description": "Link the line to a catalog item (optional — freehand lines are allowed).",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "description": {
            "type": "string",
            "description": "Line description.",
            "example": "Custom website design"
          },
          "quantity": {
            "type": "number",
            "minimum": 0.01,
            "description": "Quantity.",
            "example": 1
          },
          "unitPrice": {
            "type": "number",
            "minimum": 0,
            "description": "Unit price in business currency.",
            "example": 5000
          },
          "taxRate": {
            "type": "number",
            "minimum": 0,
            "description": "Tax rate percent. Falls back to business default.",
            "example": 18
          },
          "sortOrder": {
            "type": "number",
            "minimum": 0,
            "description": "Display order on the quote.",
            "example": 0
          }
        },
        "required": [
          "description",
          "quantity",
          "unitPrice"
        ]
      },
      "CreateQuoteDto": {
        "type": "object",
        "properties": {
          "customerId": {
            "type": "string",
            "description": "Customer the quote is addressed to.",
            "example": "clxk7j2p900012a3b4c5d6e7f"
          },
          "issueDate": {
            "type": "string",
            "description": "Quote issue date (ISO 8601). Defaults to today.",
            "example": "2026-04-14",
            "format": "date"
          },
          "validUntil": {
            "type": "string",
            "description": "Quote validity / expiry date. Defaults to issueDate + 30 days.",
            "example": "2026-05-14",
            "format": "date"
          },
          "notes": {
            "type": "string",
            "description": "Free-form notes shown on the quote.",
            "example": "Prices valid for 30 days."
          },
          "terms": {
            "type": "string",
            "description": "Terms & conditions shown at the bottom of the quote.",
            "example": "50% advance on acceptance."
          },
          "discountType": {
            "enum": [
              "NONE",
              "PERCENT",
              "AMOUNT"
            ],
            "type": "string",
            "description": "Quote-level discount type (applied pre-tax).",
            "example": "PERCENT"
          },
          "discountValue": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Discount value: percentage (0-100 if PERCENT) or flat amount (if AMOUNT).",
            "example": 10
          },
          "lineItems": {
            "minItems": 1,
            "description": "Line items on the quote. At least one required.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateQuoteLineItemDto"
            }
          }
        },
        "required": [
          "customerId",
          "lineItems"
        ]
      },
      "UpdateQuoteDto": {
        "type": "object",
        "properties": {
          "validUntil": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "terms": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "DRAFT",
              "REJECTED",
              "SENT",
              "ACCEPTED",
              "EXPIRED",
              "CONVERTED"
            ]
          },
          "discountType": {
            "type": "string",
            "enum": [
              "NONE",
              "PERCENT",
              "AMOUNT"
            ]
          },
          "discountValue": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "lineItems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateQuoteLineItemDto"
            }
          }
        }
      },
      "SendQuoteDto": {
        "type": "object",
        "properties": {
          "via": {
            "type": "string",
            "enum": [
              "whatsapp",
              "email",
              "download"
            ]
          }
        },
        "required": [
          "via"
        ]
      },
      "SupplierDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "address": {
            "type": "string",
            "nullable": true
          },
          "taxId": {
            "type": "string",
            "nullable": true
          },
          "bankName": {
            "type": "string",
            "nullable": true
          },
          "bankAccount": {
            "type": "string",
            "nullable": true
          },
          "supplierCode": {
            "type": "string"
          },
          "defaultPaymentTerms": {
            "type": "number",
            "nullable": true
          },
          "status": {
            "enum": [
              "ACTIVE",
              "ARCHIVED"
            ],
            "type": "string"
          },
          "createdAt": {
            "format": "date-time",
            "type": "string"
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "email",
          "phone",
          "address",
          "taxId",
          "bankName",
          "bankAccount",
          "supplierCode",
          "defaultPaymentTerms",
          "status",
          "createdAt",
          "updatedAt"
        ]
      },
      "SupplierListDto": {
        "type": "object",
        "properties": {
          "suppliers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SupplierDto"
            }
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "suppliers",
          "total"
        ]
      },
      "CreateSupplierDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Supplier display name.",
            "example": "Office Depot"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Contact email.",
            "example": "ap@officedepot.com"
          },
          "phone": {
            "type": "string",
            "maxLength": 50,
            "description": "Phone number.",
            "example": "+1 555 0123"
          },
          "address": {
            "type": "string",
            "maxLength": 500,
            "description": "Billing address.",
            "example": "123 Supplier St\nAustin, TX 78701"
          },
          "taxId": {
            "type": "string",
            "maxLength": 50,
            "description": "Tax identifier (GSTIN, VAT number, etc.).",
            "example": "27ABCDE1234F1Z5"
          },
          "bankName": {
            "type": "string",
            "maxLength": 255,
            "description": "Supplier bank name (for payment reference).",
            "example": "HDFC Bank"
          },
          "bankAccount": {
            "type": "string",
            "maxLength": 100,
            "description": "Supplier bank account number / IBAN.",
            "example": "50100123456789"
          },
          "defaultPaymentTerms": {
            "type": "number",
            "minimum": 0,
            "description": "Default payment terms in days (used for purchase due-date calculation).",
            "example": 30
          }
        },
        "required": [
          "name"
        ]
      },
      "UpdateSupplierDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string",
            "maxLength": 50
          },
          "address": {
            "type": "string",
            "maxLength": 500
          },
          "taxId": {
            "type": "string",
            "maxLength": 50
          },
          "bankName": {
            "type": "string",
            "maxLength": 255
          },
          "bankAccount": {
            "type": "string",
            "maxLength": 100
          },
          "defaultPaymentTerms": {
            "type": "number",
            "minimum": 0
          }
        }
      },
      "CreatePurchaseLineItemDto": {
        "type": "object",
        "properties": {
          "itemId": {
            "type": "string",
            "description": "Link to a catalog item (optional).",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "description": {
            "type": "string",
            "maxLength": 500,
            "description": "Line description.",
            "example": "Office chairs — 10 units"
          },
          "quantity": {
            "type": "number",
            "minimum": 0,
            "description": "Quantity purchased.",
            "example": 10
          },
          "unitPrice": {
            "type": "number",
            "minimum": 0,
            "description": "Unit price in business currency.",
            "example": 450
          },
          "taxRate": {
            "type": "number",
            "minimum": 0,
            "description": "Tax rate percent (e.g. 18 = 18%). Falls back to business default.",
            "example": 18
          },
          "sortOrder": {
            "type": "number",
            "minimum": 0,
            "description": "Display order on the purchase bill.",
            "example": 0
          }
        },
        "required": [
          "description",
          "quantity",
          "unitPrice"
        ]
      },
      "CreatePurchaseDto": {
        "type": "object",
        "properties": {
          "supplierId": {
            "type": "string",
            "description": "Supplier the bill is from.",
            "example": "clxk7j2p900012a3b4c5d6e7f"
          },
          "issueDate": {
            "type": "string",
            "description": "Bill date (ISO 8601). Defaults to today.",
            "example": "2026-04-14",
            "format": "date"
          },
          "dueDate": {
            "type": "string",
            "description": "Due date (ISO 8601). Defaults to issueDate + supplier/business payment terms.",
            "example": "2026-05-14",
            "format": "date"
          },
          "notes": {
            "type": "string",
            "maxLength": 500,
            "description": "Free-form notes.",
            "example": "Partial delivery expected"
          },
          "reference": {
            "type": "string",
            "maxLength": 100,
            "description": "Supplier's invoice / bill reference number.",
            "example": "SUPP-INV-99182"
          },
          "placeOfSupply": {
            "type": "string",
            "maxLength": 10,
            "description": "India GST only — 2-digit state code for place of supply.",
            "example": "27"
          },
          "reverseCharge": {
            "type": "boolean",
            "description": "India GST — set true if this purchase is under reverse charge (recipient pays GST directly).",
            "example": false
          },
          "supplierGstin": {
            "type": "string",
            "maxLength": 20,
            "description": "India GST — supplier's GSTIN at the time of purchase (may differ from supplier master).",
            "example": "27ABCDE1234F1Z5"
          },
          "discountType": {
            "enum": [
              "NONE",
              "PERCENT",
              "AMOUNT"
            ],
            "type": "string",
            "description": "Purchase-level discount received from supplier (pre-tax).",
            "example": "PERCENT"
          },
          "discountValue": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Discount value: percentage (0-100 if PERCENT) or flat amount (if AMOUNT).",
            "example": 5
          },
          "lineItems": {
            "description": "Line items on the purchase bill.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreatePurchaseLineItemDto"
            }
          }
        },
        "required": [
          "supplierId",
          "lineItems"
        ]
      },
      "UpdatePurchaseDto": {
        "type": "object",
        "properties": {
          "dueDate": {
            "type": "string"
          },
          "notes": {
            "type": "string",
            "maxLength": 500
          },
          "reference": {
            "type": "string",
            "maxLength": 100
          },
          "placeOfSupply": {
            "type": "string",
            "maxLength": 10
          },
          "reverseCharge": {
            "type": "boolean"
          },
          "supplierGstin": {
            "type": "string",
            "maxLength": 20
          },
          "discountType": {
            "type": "string",
            "enum": [
              "NONE",
              "PERCENT",
              "AMOUNT"
            ]
          },
          "discountValue": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "lineItems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreatePurchaseLineItemDto"
            }
          }
        }
      },
      "CreateStandaloneSupplierPaymentDto": {
        "type": "object",
        "properties": {
          "supplierId": {
            "type": "string",
            "description": "Supplier to pay.",
            "example": "clxk7j2p900012a3b4c5d6e7f"
          },
          "purchaseId": {
            "type": "string",
            "description": "Optionally apply to a specific purchase bill. Omit for on-account credit.",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "amount": {
            "type": "number",
            "minimum": 0.01,
            "description": "Amount paid, in business currency.",
            "example": 2500
          },
          "paymentDate": {
            "type": "string",
            "description": "Date paid (ISO 8601). Defaults to today.",
            "example": "2026-04-14",
            "format": "date"
          },
          "paymentMethod": {
            "enum": [
              "CASH",
              "BANK_TRANSFER",
              "CARD",
              "OTHER"
            ],
            "type": "string",
            "description": "How the payment was made.",
            "example": "BANK_TRANSFER"
          },
          "reference": {
            "type": "string",
            "description": "Bank reference / cheque # / transaction ID.",
            "example": "NEFT-9982311"
          },
          "notes": {
            "type": "string",
            "description": "Free-form notes.",
            "example": "Advance for next order"
          },
          "cashAccountId": {
            "type": "string",
            "description": "Cash/Bank account to post the cash side of the payment from. Must be within the Cash (1200) / Bank (1210) subtree. When omitted, defaults by payment method.",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          }
        },
        "required": [
          "supplierId",
          "amount",
          "paymentMethod"
        ]
      },
      "SupplierPaymentAllocationInputDto": {
        "type": "object",
        "properties": {
          "purchaseId": {
            "type": "string",
            "description": "Purchase bill to apply this allocation to.",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "amount": {
            "type": "number",
            "minimum": 0.01,
            "description": "Amount of this payment to apply to the bill.",
            "example": 600
          }
        },
        "required": [
          "purchaseId",
          "amount"
        ]
      },
      "SupplierPaymentReturnApplicationInputDto": {
        "type": "object",
        "properties": {
          "purchaseReturnId": {
            "type": "string",
            "description": "Open purchase return whose credit is applied against the bills.",
            "example": "clxkpr8bc00011a2b3c4d5e6f7"
          },
          "amount": {
            "type": "number",
            "minimum": 0.01,
            "description": "Amount of the return credit to apply.",
            "example": 200
          }
        },
        "required": [
          "purchaseReturnId",
          "amount"
        ]
      },
      "AllocateSupplierPaymentDto": {
        "type": "object",
        "properties": {
          "supplierId": {
            "type": "string",
            "description": "Supplier the payment is made to.",
            "example": "clxk7j2p900012a3b4c5d6e7f"
          },
          "cashAmount": {
            "type": "number",
            "minimum": 0,
            "description": "Cash actually paid (bank/cash/card), in business currency. Must equal sum(allocations) - sum(returnApplications). May be 0 for pure netting.",
            "example": 800
          },
          "paymentDate": {
            "type": "string",
            "description": "Date paid (ISO 8601). Defaults to today.",
            "example": "2026-05-18",
            "format": "date"
          },
          "paymentMethod": {
            "enum": [
              "CASH",
              "BANK_TRANSFER",
              "CARD",
              "OTHER"
            ],
            "type": "string",
            "description": "How the cash portion was paid.",
            "example": "BANK_TRANSFER"
          },
          "reference": {
            "type": "string",
            "maxLength": 100,
            "description": "Bank reference / cheque # / transaction ID.",
            "example": "NEFT-9982311"
          },
          "notes": {
            "type": "string",
            "maxLength": 500,
            "description": "Free-form notes.",
            "example": "Settling Apr bills"
          },
          "cashAccountId": {
            "type": "string",
            "description": "Cash/Bank account to post the cash side of the payment from. Must be within the Cash (1200) / Bank (1210) subtree. When omitted, defaults by payment method.",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          },
          "allocations": {
            "minItems": 1,
            "description": "Bills this payment is applied against. At least one is required.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SupplierPaymentAllocationInputDto"
            }
          },
          "returnApplications": {
            "description": "Open purchase-return credits to apply against the bills. Empty array if no credits used.",
            "default": [],
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SupplierPaymentReturnApplicationInputDto"
            }
          }
        },
        "required": [
          "supplierId",
          "cashAmount",
          "paymentMethod",
          "allocations"
        ]
      },
      "CreateSupplierPaymentDto": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "minimum": 0.01,
            "description": "Amount paid to supplier, in business currency.",
            "example": 2500
          },
          "paymentDate": {
            "type": "string",
            "description": "Date paid (ISO 8601). Defaults to today.",
            "example": "2026-04-14",
            "format": "date"
          },
          "paymentMethod": {
            "enum": [
              "CASH",
              "BANK_TRANSFER",
              "CARD",
              "OTHER"
            ],
            "type": "string",
            "description": "How the payment was made. See the Payment Methods reference.",
            "example": "BANK_TRANSFER"
          },
          "reference": {
            "type": "string",
            "maxLength": 100,
            "description": "Bank reference / cheque # / transaction ID.",
            "example": "NEFT-9982311"
          },
          "notes": {
            "type": "string",
            "maxLength": 500,
            "description": "Free-form notes.",
            "example": "Final payment for PO-0042"
          },
          "cashAccountId": {
            "type": "string",
            "description": "Cash/Bank account to post the cash side of the payment from. Must be within the Cash (1200) / Bank (1210) subtree. When omitted, defaults by payment method.",
            "example": "clxk9a8bc00011a2b3c4d5e6f7"
          }
        },
        "required": [
          "amount",
          "paymentMethod"
        ]
      },
      "ItemDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "businessId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "unit": {
            "type": "string",
            "nullable": true
          },
          "itemCode": {
            "type": "string"
          },
          "salable": {
            "type": "boolean"
          },
          "salePrice": {
            "type": "number",
            "nullable": true
          },
          "salesAccountId": {
            "type": "string",
            "nullable": true
          },
          "salesAccountName": {
            "type": "string",
            "nullable": true
          },
          "purchasable": {
            "type": "boolean"
          },
          "costPrice": {
            "type": "number",
            "nullable": true
          },
          "purchaseAccountId": {
            "type": "string",
            "nullable": true
          },
          "purchaseAccountName": {
            "type": "string",
            "nullable": true
          },
          "preferredSupplierId": {
            "type": "string",
            "nullable": true
          },
          "preferredSupplierName": {
            "type": "string",
            "nullable": true
          },
          "defaultTaxRate": {
            "type": "number",
            "nullable": true
          },
          "trackInventory": {
            "type": "boolean"
          },
          "currentStock": {
            "type": "number",
            "nullable": true
          },
          "reorderLevel": {
            "type": "number",
            "nullable": true
          },
          "hsnCode": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "enum": [
              "ACTIVE",
              "ARCHIVED"
            ],
            "type": "string"
          },
          "createdAt": {
            "format": "date-time",
            "type": "string"
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "businessId",
          "name",
          "description",
          "unit",
          "itemCode",
          "salable",
          "salePrice",
          "salesAccountId",
          "salesAccountName",
          "purchasable",
          "costPrice",
          "purchaseAccountId",
          "purchaseAccountName",
          "preferredSupplierId",
          "preferredSupplierName",
          "defaultTaxRate",
          "trackInventory",
          "currentStock",
          "reorderLevel",
          "hsnCode",
          "status",
          "createdAt",
          "updatedAt"
        ]
      },
      "ItemListDto": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ItemDto"
            }
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "items",
          "total"
        ]
      },
      "CreateItemDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200,
            "description": "Item name displayed on invoices and pickers.",
            "example": "Professional Consulting"
          },
          "description": {
            "type": "string",
            "description": "Long description prefilled on invoice lines.",
            "example": "Monthly retainer for advisory services"
          },
          "unit": {
            "type": "string",
            "maxLength": 50,
            "description": "Unit of measure (hr, kg, pcs, box, etc.).",
            "example": "hr"
          },
          "salable": {
            "type": "boolean",
            "description": "Whether this item appears in sales (invoice/quote) pickers.",
            "example": true
          },
          "salePrice": {
            "type": "number",
            "minimum": 0,
            "description": "Default sale price (per unit) used when added to an invoice.",
            "example": 150
          },
          "salesAccountId": {
            "type": "string",
            "description": "Override the default revenue account for this item.",
            "example": "acct_clxk..."
          },
          "purchasable": {
            "type": "boolean",
            "description": "Whether this item appears in purchase (bill) pickers.",
            "example": true
          },
          "costPrice": {
            "type": "number",
            "minimum": 0,
            "description": "Default cost price (per unit) used when added to a purchase bill.",
            "example": 90
          },
          "purchaseAccountId": {
            "type": "string",
            "description": "Override the default expense/COGS account for this item.",
            "example": "acct_clxk..."
          },
          "preferredSupplierId": {
            "type": "string",
            "description": "Default supplier for purchase auto-fill.",
            "example": "supplier_clxk..."
          },
          "defaultTaxRate": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Default tax rate percent applied when added to a line (e.g. 18 = 18%).",
            "example": 18
          },
          "trackInventory": {
            "type": "boolean",
            "description": "Track stock levels for this item.",
            "example": false
          },
          "currentStock": {
            "type": "number",
            "minimum": 0,
            "description": "Current on-hand quantity (if trackInventory is on).",
            "example": 25
          },
          "reorderLevel": {
            "type": "number",
            "minimum": 0,
            "description": "Low-stock threshold for reorder alerts.",
            "example": 5
          },
          "hsnCode": {
            "type": "string",
            "maxLength": 10,
            "description": "India-specific HSN / SAC code for GST filings.",
            "example": "998314"
          }
        },
        "required": [
          "name"
        ]
      },
      "BulkItemInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200,
            "description": "Item name.",
            "example": "Consulting hour"
          },
          "type": {
            "enum": [
              "GOODS",
              "SERVICE"
            ],
            "type": "string",
            "example": "SERVICE"
          },
          "itemCode": {
            "type": "string",
            "maxLength": 50,
            "description": "External SKU / code. Used as the UPSERT key: a matching existing item is updated, otherwise a new item is created. Omit to auto-generate a code.",
            "example": "SKU-1001"
          },
          "description": {
            "type": "string",
            "example": "Senior advisory, billed hourly"
          },
          "unit": {
            "type": "string",
            "maxLength": 50,
            "example": "hr"
          },
          "salable": {
            "type": "boolean",
            "description": "Appears in sales pickers. Default true.",
            "example": true
          },
          "salePrice": {
            "type": "number",
            "minimum": 0,
            "example": 150
          },
          "purchasable": {
            "type": "boolean",
            "description": "Appears in purchase pickers. Default true.",
            "example": true
          },
          "costPrice": {
            "type": "number",
            "minimum": 0,
            "example": 90
          },
          "defaultTaxRate": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "example": 15
          },
          "salesAccountCode": {
            "type": "string",
            "description": "Revenue account code. Default 4000.",
            "example": "4000"
          },
          "purchaseAccountCode": {
            "type": "string",
            "description": "Expense / COGS account code. Default 5000.",
            "example": "5000"
          },
          "hsnCode": {
            "type": "string",
            "maxLength": 10,
            "description": "India HSN / SAC code.",
            "example": "998314"
          }
        },
        "required": [
          "name",
          "type"
        ]
      },
      "BulkImportItemsDto": {
        "type": "object",
        "properties": {
          "items": {
            "minItems": 1,
            "maxItems": 500,
            "description": "Items to import (1–500 per request).",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BulkItemInput"
            }
          },
          "upsert": {
            "type": "boolean",
            "description": "When true (default), an existing item with the same itemCode is UPDATED. When false, such rows are SKIPPED (insert-only).",
            "example": true
          }
        },
        "required": [
          "items"
        ]
      },
      "UpdateItemDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200
          },
          "description": {
            "type": "string"
          },
          "unit": {
            "type": "string",
            "maxLength": 50
          },
          "salable": {
            "type": "boolean"
          },
          "salePrice": {
            "type": "number",
            "minimum": 0
          },
          "salesAccountId": {
            "type": "string"
          },
          "purchasable": {
            "type": "boolean"
          },
          "costPrice": {
            "type": "number",
            "minimum": 0
          },
          "purchaseAccountId": {
            "type": "string"
          },
          "preferredSupplierId": {
            "type": "string"
          },
          "defaultTaxRate": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "trackInventory": {
            "type": "boolean"
          },
          "currentStock": {
            "type": "number",
            "minimum": 0
          },
          "reorderLevel": {
            "type": "number",
            "minimum": 0
          },
          "hsnCode": {
            "type": "string",
            "maxLength": 10
          }
        }
      },
      "AuthorizeConsentDto": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string"
          },
          "approved": {
            "type": "boolean"
          }
        },
        "required": [
          "request_id",
          "approved"
        ]
      },
      "TokenRequestDto": {
        "type": "object",
        "properties": {
          "grant_type": {
            "type": "string",
            "enum": [
              "authorization_code",
              "refresh_token"
            ]
          },
          "code": {
            "type": "string"
          },
          "redirect_uri": {
            "type": "string"
          },
          "code_verifier": {
            "type": "string"
          },
          "refresh_token": {
            "type": "string"
          },
          "client_id": {
            "type": "string"
          },
          "client_secret": {
            "type": "string"
          }
        },
        "required": [
          "grant_type"
        ]
      },
      "RevokeTokenDto": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          },
          "token_type_hint": {
            "type": "string",
            "enum": [
              "access_token",
              "refresh_token"
            ]
          },
          "client_id": {
            "type": "string"
          },
          "client_secret": {
            "type": "string"
          }
        },
        "required": [
          "token"
        ]
      },
      "IntrospectDto": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          }
        },
        "required": [
          "token"
        ]
      },
      "CreateClientDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "redirectUris": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "scopes": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "clientType": {
            "type": "string",
            "enum": [
              "PUBLIC",
              "CONFIDENTIAL"
            ]
          }
        },
        "required": [
          "name",
          "redirectUris",
          "scopes"
        ]
      },
      "UpdateClientDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "redirectUris": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "ColumnMappingDto": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "reference": {
            "type": "string"
          },
          "debit": {
            "type": "string"
          },
          "credit": {
            "type": "string"
          },
          "amount": {
            "type": "string"
          },
          "balance": {
            "type": "string"
          }
        }
      },
      "ConfirmStatementDto": {
        "type": "object",
        "properties": {
          "fileToken": {
            "type": "string"
          },
          "accountId": {
            "type": "string"
          },
          "statementDate": {
            "type": "string"
          },
          "periodStart": {
            "type": "string"
          },
          "periodEnd": {
            "type": "string"
          },
          "openingBalance": {
            "type": "number"
          },
          "closingBalance": {
            "type": "number"
          },
          "mapping": {
            "$ref": "#/components/schemas/ColumnMappingDto"
          }
        },
        "required": [
          "fileToken",
          "accountId",
          "statementDate",
          "periodStart",
          "periodEnd",
          "openingBalance",
          "closingBalance"
        ]
      },
      "MatchLineDto": {
        "type": "object",
        "properties": {
          "targetType": {
            "type": "string",
            "enum": [
              "payment",
              "journalEntry",
              "supplierPayment"
            ]
          },
          "targetId": {
            "type": "string"
          }
        },
        "required": [
          "targetType",
          "targetId"
        ]
      },
      "CreatePaymentFromLineDto": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "payment",
              "journalEntry",
              "supplierPayment"
            ]
          },
          "customerId": {
            "type": "string"
          },
          "invoiceId": {
            "type": "string"
          },
          "supplierId": {
            "type": "string"
          },
          "purchaseId": {
            "type": "string"
          },
          "counterpartAccountId": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "amount": {
            "type": "number",
            "minimum": 0
          }
        },
        "required": [
          "kind"
        ]
      },
      "CreateContraDto": {
        "type": "object",
        "properties": {
          "fromAccountId": {
            "type": "string"
          },
          "toAccountId": {
            "type": "string"
          },
          "amount": {
            "type": "number",
            "minimum": 0.01
          },
          "date": {
            "type": "string"
          },
          "reference": {
            "type": "string",
            "maxLength": 100
          },
          "notes": {
            "type": "string",
            "maxLength": 500
          }
        },
        "required": [
          "fromAccountId",
          "toAccountId",
          "amount"
        ]
      },
      "CloseFiscalYearDto": {
        "type": "object",
        "properties": {
          "note": {
            "type": "string",
            "maxLength": 500
          }
        }
      },
      "ReopenFiscalYearDto": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "maxLength": 500
          }
        },
        "required": [
          "reason"
        ]
      },
      "AuthorizationServerMetadataDto": {
        "type": "object",
        "properties": {
          "issuer": {
            "type": "string",
            "example": "http://192.168.1.28:3001"
          },
          "authorization_endpoint": {
            "type": "string",
            "example": "http://192.168.1.28:5173/oauth/authorize"
          },
          "token_endpoint": {
            "type": "string",
            "example": "http://192.168.1.28:3001/oauth/token"
          },
          "revocation_endpoint": {
            "type": "string",
            "example": "http://192.168.1.28:3001/oauth/revoke"
          },
          "introspection_endpoint": {
            "type": "string",
            "example": "http://192.168.1.28:3001/oauth/introspect"
          },
          "api_base_url": {
            "type": "string",
            "description": "Base URL for API calls (non-standard extension). Use with `Authorization: Bearer <access_token>`.",
            "example": "http://192.168.1.28:3001"
          },
          "scopes_supported": {
            "description": "All OAuth scopes this server supports.",
            "example": [
              "profile:read",
              "invoices:read",
              "invoices:write"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "response_types_supported": {
            "example": [
              "code"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "grant_types_supported": {
            "example": [
              "authorization_code",
              "refresh_token"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "code_challenge_methods_supported": {
            "example": [
              "S256",
              "plain"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "token_endpoint_auth_methods_supported": {
            "example": [
              "client_secret_basic",
              "client_secret_post",
              "none"
            ],
            "description": "`none` is used for public clients with PKCE.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "issuer",
          "authorization_endpoint",
          "token_endpoint",
          "revocation_endpoint",
          "introspection_endpoint",
          "api_base_url",
          "scopes_supported",
          "response_types_supported",
          "grant_types_supported",
          "code_challenge_methods_supported",
          "token_endpoint_auth_methods_supported"
        ]
      }
    }
  }
}
