{
  "openapi": "3.0.0",
  "servers": [
    {
      "description": "Hosted Platform",
      "url": "https://billing.pracbill.com.au/api"
    },
    {
      "description": "Dev Platform",
      "url": "https://dev.pracbill.com.au/api"
    }
  ],
  "info": {
    "description": "Developer Access to the Pracbill API Platform, most tasks can be performed through this.\n\nPlease ensure that you read the schema items and descriptions for each request, as some items are variable and descriptions are provided there.\n\n\nPlease note this documentation is a work in progress, there is also an existing documentation for the api at: \n[https://pracbill.atlassian.net/wiki/spaces/UGX1/pages/8880079/API+Developer+Documentation](url)",
    "version": "4.3.0",
    "title": "Pracbill API",
    "contact": {
      "email": "support@pracbill.com.au"
    },
    "license": {
      "name": "Apache 2.0",
      "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
    }
  },
  "tags": [
    {
      "name": "sales",
      "description": "Sales Related Options"
    },
    {
      "name": "customers",
      "description": "Items relating to existing customers"
    },
    {
      "name": "leads",
      "description": "Items relating to leads"
    },
    {
      "name": "products",
      "description": "Product related endpoints"
    },
    {
      "name": "services",
      "description": "Service related services"
    },
    {
      "name": "invoices",
      "description": "Invoice management and retrieval"
    },
    {
      "name": "cdr",
      "description": "Call Detail Records (CDR) management"
    },
    {
      "name": "reporting",
      "description": "Report generation and analytics"
    },
    {
      "name": "service_types",
      "description": "Service type management (engineering service types/products)"
    },
    {
      "name": "timeline",
      "description": "Timeline and activity tracking across modules"
    },
    {
      "name": "price_books",
      "description": "Customer-specific pricing and price book management"
    },
    {
      "name": "service_bundles",
      "description": "Service bundle management"
    },
    {
      "name": "customer_contacts",
      "description": "Customer contact management"
    },
    {
      "name": "payment_methods",
      "description": "Customer payment method management"
    },
    {
      "name": "authentication",
      "description": "Authentication and password reset endpoints"
    },
    {
      "name": "billruns",
      "description": "Bill run management and approval"
    },
    {
      "name": "customer_bulk_email",
      "description": "Bulk customer email campaigns (filters, preview, queue, status, cancel)"
    }
  ],
  "paths": {
    "/password-reset/request": {
      "post": {
        "tags": [
          "authentication"
        ],
        "summary": "Request a password reset",
        "description": "Initiates the internal-user password reset flow. Unauthenticated (no API key). Accepts a username or email address and always returns a generic success response so account existence is never revealed. When the account exists and is active, a reset token is created and emailed. Tokens and passwords are never written to API request logs.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "username"
                ],
                "properties": {
                  "username": {
                    "type": "string",
                    "description": "The username or email address of the account to reset.",
                    "example": "user@example.com"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Generic success response (returned for valid, invalid, unknown and malformed usernames).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string",
                      "example": "If an account exists with that username or email, a password reset link has been sent."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/password-reset/confirm": {
      "post": {
        "tags": [
          "authentication"
        ],
        "summary": "Complete a password reset",
        "description": "Completes the internal-user password reset flow using a token issued by /password-reset/request. Unauthenticated (no API key). Validates that the token is a 64-character lowercase hex string, that the password is at least 8 characters, and that password and password_confirm match, before resetting the password and consuming the token. Used, expired, malformed or unknown tokens return a generic invalid/expired response. Tokens and passwords are never written to API request logs.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token",
                  "password",
                  "password_confirm"
                ],
                "properties": {
                  "token": {
                    "type": "string",
                    "description": "The 64-character lowercase hex reset token from the emailed reset link.",
                    "example": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
                  },
                  "password": {
                    "type": "string",
                    "description": "The new password (minimum 8 characters).",
                    "example": "newSecurePass123"
                  },
                  "password_confirm": {
                    "type": "string",
                    "description": "Must match password.",
                    "example": "newSecurePass123"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reset result. success is true when the password was reset; otherwise false with a validation or generic invalid/expired error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "message": {
                      "type": "string",
                      "example": "Your password has been reset successfully."
                    },
                    "error": {
                      "type": "string",
                      "description": "Present when success is false.",
                      "example": "This password reset link is invalid or has expired. Please request a new one."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/services/qualify": {
      "post": {
        "tags": [
          "sales"
        ],
        "parameters": [
          {
            "in": "query",
            "name": "address",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "avcid",
            "required": false,
            "description": "AVC ID for transfer verification. When provided, the response will include avc_match, avc_target, and avc_current_epid fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "service_type",
            "required": false,
            "description": "Service type for qualification (e.g. FTTP, HFC, FTTC). Used with avcid to qualify for Primary or Original Technology.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The qualification response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/QualificationItem"
                  }
                }
              }
            }
          }
        }
      },
      "parameters": [
        {
          "schema": {
            "type": "string"
          },
          "name": "api_key",
          "description": "The API Token",
          "in": "path",
          "required": true
        }
      ]
    },
    "/{api_key}/services/qualify/ndf": {
      "post": {
        "tags": [
          "sales"
        ],
        "parameters": [
          {
            "in": "query",
            "name": "address",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The qualification response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/QualificationItem"
                  }
                }
              }
            }
          }
        }
      },
      "parameters": [
        {
          "schema": {
            "type": "string"
          },
          "name": "api_key",
          "description": "The API Token",
          "in": "path",
          "required": true
        }
      ]
    },
    "/{api_key}/services/qualify/avc-check": {
      "post": {
        "tags": [
          "services"
        ],
        "summary": "AVC Transfer Qualification Check",
        "description": "Verify that an AVC ID matches a given location before submitting a transfer order. Returns the AVC match result, target identifier (CopperPairID or PortID), and the current provider EPID.",
        "parameters": [
          {
            "in": "query",
            "name": "location_id",
            "required": true,
            "description": "The LOC ID / DirectoryID from a previous address lookup",
            "schema": {
              "type": "string",
              "example": "LOC000340636851"
            }
          },
          {
            "in": "query",
            "name": "avcid",
            "required": true,
            "description": "The AVC ID to verify against the location",
            "schema": {
              "type": "string",
              "example": "AVC000340636851"
            }
          },
          {
            "in": "query",
            "name": "service_type",
            "required": false,
            "description": "Technology type (e.g. FTTP, HFC, FTTC, FTTN, FTTB, WIRELESS)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "AVC check result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AVCCheckResponse"
                }
              }
            }
          }
        }
      },
      "parameters": [
        {
          "schema": {
            "type": "string"
          },
          "name": "api_key",
          "description": "The API Token",
          "in": "path",
          "required": true
        }
      ]
    },
    "/{api_key}/orders/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "sales"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "integer",
                      "format": "int32",
                      "description": "the order id of the successful order",
                      "example": 44
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "customers"
        ],
        "description": "Create a customer",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerUpdateItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiCreateItemBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/update/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "required": true,
          "description": "the customer id, can be either the customer id, account_id or crm_id",
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "customers"
        ],
        "description": "Update a customers details",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerUpdateItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiCreateItemBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/payment/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "required": true,
          "description": "the customer id, can be either the customer id, account_id or crm_id",
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "customers"
        ],
        "description": "Perform a payment on a customer's account.\n For the request body either a payment_token or all the card fields are required.  The payment_token is not available on all payment gateways, **Payment Token is currently only supported on: Till Payments** ",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PaymentItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/external-payment/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "required": true,
          "description": "the customer id, can be either the customer id, account_id or crm_id",
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "customers"
        ],
        "summary": "Log external payment",
        "description": "Log a payment transaction that was processed by an external party or ecommerce solution. Bypasses all credit card validation and authorization since the payment was already processed externally. Requires a transaction_id for refund tracking.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExternalPaymentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment logged successfully or duplicate detected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalPaymentResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/balance/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "required": true,
          "description": "the customer id, can be either the customer id, account_id or crm_id",
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customers"
        ],
        "description": "Returns the current customer balance.",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerBalanceResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/paymentDetails/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "required": true,
          "description": "the customer id, can be either the customer id, account_id or crm_id",
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customers"
        ],
        "description": "Get the Customer's Current Payment Details",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerPaymentDetailsResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/item/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "customers"
        ],
        "description": "Add a charge item directly to a customer",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerItemAdd"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiCreateItemBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/item/update/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "required": true,
          "description": "The customer item ID",
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "customers"
        ],
        "description": "Update a customer charge item",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerItemUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/leads/get/page/{page_number}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "page_number",
          "required": true,
          "description": "The Page number to get, defaults to 1",
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "leads"
        ],
        "description": "Get a list of paginated leads ( 20 per page )",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LeadsListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/leads/filter/get/page/{page_number}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "page_number",
          "schema": {
            "type": "integer"
          },
          "description": "the page you wish to return",
          "required": true
        }
      ],
      "post": {
        "tags": [
          "leads"
        ],
        "requestBody": {
          "description": "All properties are optional, only included properties will be filtered.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LeadsFilterOption"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LeadsListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/leads/get/{lid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "lid",
          "required": true,
          "description": "The Lead Id",
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "leads"
        ],
        "description": "Get a lead",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LeadsGetResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/leads/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "leads"
        ],
        "description": "Create a lead",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LeadItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiCreateItemBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/leads/{lid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "lid",
          "description": "Lead ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "leads"
        ],
        "description": "Update a lead",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LeadItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiCreateItemBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/products/category/{catid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "catid",
          "description": "Category ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "products"
        ],
        "description": "Get a list of products for a cateogry",
        "responses": {
          "200": {
            "description": "Request received succesfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductListPage"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/products/category/{catid}/page/{page_number}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "catid",
          "description": "Category ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        },
        {
          "in": "path",
          "name": "page_number",
          "schema": {
            "type": "integer"
          },
          "description": "the page you wish to return",
          "required": true
        }
      ],
      "get": {
        "tags": [
          "products"
        ],
        "description": "Get a list of products for a cateogry",
        "responses": {
          "200": {
            "description": "Request received succesfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductListPage"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/products/get/{pid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "pid",
          "description": "Product ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "products"
        ],
        "description": "Get a produc",
        "responses": {
          "200": {
            "description": "Request received succesfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductItem"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/serviceType/get/page/{page_number}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "page_number",
          "schema": {
            "type": "integer"
          },
          "description": "The page number to return",
          "required": true
        },
        {
          "in": "query",
          "name": "include_inactive",
          "schema": {
            "type": "boolean"
          },
          "description": "Inactive (retired) service types are excluded by default; pass 1 to include them",
          "required": false
        }
      ],
      "get": {
        "tags": [
          "service_types"
        ],
        "description": "Retrieve a paginated list of service types and basic information. Only active service types are returned unless include_inactive is set.",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceTypeListPage"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/serviceType/get/{esid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "esid",
          "description": "Service Type ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "service_types"
        ],
        "description": "Get detailed information about a specific service type",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceTypeGetResponse"
                }
              }
            }
          },
          "404": {
            "description": "Service type not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "description": {
                      "type": "string",
                      "example": "serviceType not found"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/serviceType/filter/get/page/{page_number}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "page_number",
          "schema": {
            "type": "integer"
          },
          "description": "the page you wish to return",
          "required": true
        }
      ],
      "post": {
        "tags": [
          "service_types"
        ],
        "requestBody": {
          "description": "All properties are optional, only included properties will be filtered.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceTypeFilterOption"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceTypeListPage"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/serviceType/filter/get": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "service_types"
        ],
        "description": "Retrieve filtered service types without pagination",
        "requestBody": {
          "description": "All properties are optional, only included properties will be filtered.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceTypeFilterOption"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceTypeListPage"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/serviceType/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "service_types"
        ],
        "description": "Create a new service type",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceTypeCreateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Service type created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "esid": {
                      "type": "integer",
                      "description": "ID of the newly created service type",
                      "example": 123
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request - missing required fields or invalid data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/serviceType/update/{esid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "esid",
          "description": "Service Type ID to update",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "service_types"
        ],
        "description": "Update an existing service type",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceTypeUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Service type updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "description": {
                      "type": "string",
                      "example": "serviceType updated successfully"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Service type not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/serviceType/delete/{esid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "esid",
          "description": "Service Type ID to delete",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "delete": {
        "tags": [
          "service_types"
        ],
        "description": "Delete a service type. Will fail if there are active services associated with this service type.",
        "responses": {
          "200": {
            "description": "Service type deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "description": {
                      "type": "string",
                      "example": "serviceType deleted successfully"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Cannot delete - active services exist",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "description": {
                      "type": "string",
                      "example": "Cannot delete serviceType: there are active services associated with this service type"
                    },
                    "active_services_count": {
                      "type": "integer",
                      "description": "Number of active services using this service type",
                      "example": 5
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Service type not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/invoice/get": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "invoices"
        ],
        "description": "Retrieve all invoices for the department",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "invoices"
        ],
        "description": "Retrieve all invoices ordered by a specific field",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "order_by": {
                    "type": "string",
                    "description": "Field to order by",
                    "enum": [
                      "iid",
                      "cid",
                      "date",
                      "company",
                      "duedate",
                      "balance"
                    ],
                    "example": "iid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/invoice/get/{iid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "iid",
          "description": "Invoice ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "invoices"
        ],
        "description": "Retrieve a specific invoice by ID",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceGetResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/invoice/get/customer/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "invoices"
        ],
        "description": "Retrieve all invoices for a specific customer",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/invoice/get/customer/{cid}/filter/{filter}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        },
        {
          "in": "path",
          "name": "filter",
          "description": "Filter string (e.g., 'paid=1', 'balance>100', 'date>=2024-01-01'). Supported filters: bad_debt, paid, date_modified, date, duedate, balance, draft, void",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "invoices"
        ],
        "description": "Retrieve filtered invoices for a specific customer",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/invoice/get/filter/{filter}/page/{page_number}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "filter",
          "description": "Filter string (e.g., 'paid=1', 'balance>100', 'date_modified>=2024-01-01'). Supported filters: bad_debt, paid, date_modified, date, duedate, balance, draft, void",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "page_number",
          "description": "Page number (20 results per page)",
          "required": true,
          "schema": {
            "type": "integer",
            "default": 1
          }
        }
      ],
      "get": {
        "tags": [
          "invoices"
        ],
        "description": "Retrieve filtered and paginated invoices",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoicePaginatedResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/invoice/get/pdf/{iid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "iid",
          "description": "Invoice ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "invoices"
        ],
        "description": "Download invoice as PDF file",
        "responses": {
          "200": {
            "description": "PDF file",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/invoice/get/csv/{iid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "iid",
          "description": "Invoice ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "invoices"
        ],
        "description": "Download invoice as CSV file. Site-grouped invoices carry a trailing Site Name column (empty when the row has no engineering site). An invalid API key or missing iid returns a JSON error instead.",
        "responses": {
          "200": {
            "description": "CSV file",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/invoice/get/csv/usage/{iid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "iid",
          "description": "Invoice ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "invoices"
        ],
        "description": "Download invoice usage (call/CDR detail) as CSV file. Each row carries a trailing Site Name column (empty when the charged service has no engineering site). An invalid API key or missing iid returns a JSON error instead.",
        "responses": {
          "200": {
            "description": "CSV file",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/invoice/get/statement/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "invoices"
        ],
        "description": "Download customer statement as PDF file",
        "responses": {
          "200": {
            "description": "PDF file",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/invoice/{iid}/void": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "iid",
          "description": "Invoice ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "invoices"
        ],
        "description": "Void an invoice",
        "responses": {
          "200": {
            "description": "Invoice voided successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/invoice/{iid}/bad_debt": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "iid",
          "description": "Invoice ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "invoices"
        ],
        "description": "Mark an invoice as bad debt",
        "responses": {
          "200": {
            "description": "Invoice marked as bad debt successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/{cid}/contacts": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID (can be cid, account_id, or crm_id)",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customer_contacts"
        ],
        "description": "Retrieve all contacts for a customer",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "customer_contacts"
        ],
        "description": "Create a new contact for a customer",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contact created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactSingleResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/{cid}/contact/{contact_id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID (can be cid, account_id, or crm_id)",
          "required": true,
          "schema": {
            "type": "integer"
          }
        },
        {
          "in": "path",
          "name": "contact_id",
          "description": "Contact ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customer_contacts"
        ],
        "description": "Retrieve a specific contact",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactSingleResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "customer_contacts"
        ],
        "description": "Update a contact",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contact updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactSingleResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/{cid}/contact/{contact_id}/delete": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID (can be cid, account_id, or crm_id)",
          "required": true,
          "schema": {
            "type": "integer"
          }
        },
        {
          "in": "path",
          "name": "contact_id",
          "description": "Contact ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customer_contacts"
        ],
        "description": "Delete a contact",
        "responses": {
          "200": {
            "description": "Contact deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/{cid}/paymentMethods": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID (can be cid, account_id, or crm_id)",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "payment_methods"
        ],
        "summary": "List payment methods",
        "description": "Retrieve all payment methods for a customer (both active and inactive)",
        "responses": {
          "200": {
            "description": "Payment methods retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentMethodListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "payment_methods"
        ],
        "summary": "Filter payment methods",
        "description": "Retrieve payment methods with optional filters for active status, type (bank/card), primary/backup method, and payment gateway",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PaymentMethodFilterRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment methods retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentMethodListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/{cid}/paymentMethods/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID (can be cid, account_id, or crm_id)",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "payment_methods"
        ],
        "summary": "Add payment method",
        "description": "Add a new payment method to a customer. Can be a credit card (via token or full card details) or bank account. Supply `gateway` to nominate a gateway configured for the department, otherwise the gateway is automatically selected based on the data provided.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PaymentMethodAddRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment method added successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentMethodAddResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/paymentMethods/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Payment Method ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "payment_methods"
        ],
        "summary": "Get payment method",
        "description": "Retrieve details for a specific payment method",
        "responses": {
          "200": {
            "description": "Payment method retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentMethodSingleResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/paymentMethods/{id}/status": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Payment Method ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "payment_methods"
        ],
        "summary": "Set payment method status",
        "description": "Update the status of a payment method. Valid statuses: primary, backup, inactive. Setting a method to primary or backup will also set it as active. Setting to inactive deactivates the method.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PaymentMethodStatusRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Status updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/paymentMethods/{id}/nickname": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Payment Method ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "payment_methods"
        ],
        "summary": "Set payment method nickname",
        "description": "Update the nickname/display name of a payment method",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PaymentMethodNicknameRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Nickname updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/getCreditManagementStatus/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customers"
        ],
        "description": "Get credit management status for a customer. Credit management prevents automatic late fees and card charges.",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditManagementResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/setCreditManagementStatus/{cid}/{status}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        },
        {
          "in": "path",
          "name": "status",
          "description": "Credit management status (0 or 1)",
          "required": true,
          "schema": {
            "type": "integer",
            "enum": [
              0,
              1
            ]
          }
        }
      ],
      "get": {
        "tags": [
          "customers"
        ],
        "description": "Set credit management status for a customer",
        "responses": {
          "200": {
            "description": "Status updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/cdr/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token (must have cdr_source variable configured)",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "cdr"
        ],
        "description": "Add a single CDR (Call Detail Record) for billing. Important: API Key must have cdr_source variable set.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CDRItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "CDR added successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CDRAddResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/cdr/multiple/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token (must have cdr_source variable configured)",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "cdr"
        ],
        "description": "Add multiple CDRs (Call Detail Records) for billing in a single request. Important: API Key must have cdr_source variable set.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CDRItem"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "CDRs processed (may contain mixed success/failure results)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CDRAddResponse"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/cdr/getPrice/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token (must have cdr_source variable configured)",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "CDR orig_id",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "cdr"
        ],
        "description": "Retrieve rating information for a specific CDR",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CDRPriceResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/cdr/getMultiplePrice": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token (must have cdr_source variable configured)",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "cdr"
        ],
        "description": "Retrieve rating information for multiple CDRs",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "string",
                  "description": "CDR orig_id"
                },
                "example": [
                  "CU4Y5KKRJCXGVO4ITUBTRWR5VVGW6F3Q",
                  "CCWSSUWTVFLJSDQF4BEI2WQ2ROFNHHDI"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CDRMultiplePriceResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/cdr/status": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "cdr"
        ],
        "description": "Get CDR processing status",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/cdr/exports": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "cdr"
        ],
        "description": "List customers that have a CDR export configured (cdr_export_frequency and cdr_export_format both set), reporting the last export run, the computed next run, and the export path and format. By default only customers whose next run is still pending are returned, for export-run monitoring/alerting.",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CdrExportsResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/cdr/exports/{include_inactive}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "include_inactive",
          "description": "Pass the literal string \"include_inactive\" to also return exports whose next run is not yet pending (i.e. every configured customer, not just those currently due).",
          "required": true,
          "schema": {
            "type": "string",
            "enum": [
              "include_inactive"
            ]
          }
        }
      ],
      "get": {
        "tags": [
          "cdr"
        ],
        "description": "As GET /{api_key}/cdr/exports, but includes customers whose next export run is not yet pending.",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CdrExportsResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/report": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "reporting"
        ],
        "description": "Run a specific report. Report name and options vary by report type. Common reports: agedReceivables, invoiceListing, revenueSummary, customerBillingSummary, etc.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Report generated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/timeline/{module}/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "module",
          "description": "Module name (e.g., customer, orders, helpdesk)",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Record ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "timeline"
        ],
        "description": "Get timeline entries (notes, events) for a specific record",
        "responses": {
          "200": {
            "description": "Timeline entries retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/TimelineItem"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "timeline"
        ],
        "description": "Add a timeline entry (note or event) to a record",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TimelineCreateItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Timeline entry created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiCreateItemBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/get/servicePricing/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customers"
        ],
        "description": "Get service type pricing for a customer (includes price book adjustments if customer has a price book assigned)",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerServicePricingResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/get/servicePricing/{cid}/{esid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        },
        {
          "in": "path",
          "name": "esid",
          "description": "Service Type ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customers"
        ],
        "description": "Get specific service type pricing for a customer",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerServicePricingSingleResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/priceBooks/get/page/{page_number}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "page_number",
          "description": "Page number (20 results per page)",
          "required": true,
          "schema": {
            "type": "integer",
            "default": 1
          }
        }
      ],
      "get": {
        "tags": [
          "price_books"
        ],
        "description": "Get paginated list of price books",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PriceBooksListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/priceBooks/get/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Price Book ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "price_books"
        ],
        "description": "Get detailed price book information including all items",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PriceBookGetResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/priceBooks/post": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "price_books"
        ],
        "description": "Create or update a price book",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PriceBookSaveItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Price book saved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiCreateItemBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/engineering/get/{enid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "enid",
          "description": "Service/Engineering ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "services"
        ],
        "description": "Get a specific service record by ID",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceGetResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/engineering/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "services"
        ],
        "description": "Create a new service record",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceCreateItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Service created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiCreateItemBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/engineering/update/{enid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "enid",
          "description": "Service/Engineering ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "services"
        ],
        "description": "Update an existing service record",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceCreateItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Service updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/engineering/search": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "services"
        ],
        "description": "Search for services with flexible criteria. The request body is a JSON **array** of criterion objects. Each criterion has a `field`, a `value`, and an optional `operator` (defaults to `like`). Multiple criteria are combined with AND. Results are automatically scoped to the API token's department.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceSearchCriteria"
              },
              "examples": {
                "byServiceNumber": {
                  "summary": "Exact match on a service number",
                  "value": [
                    {
                      "field": "service_num",
                      "value": "456789098",
                      "operator": "="
                    }
                  ]
                },
                "partialBillingName": {
                  "summary": "Partial (LIKE) match on billing name",
                  "value": [
                    {
                      "field": "billing_name",
                      "value": "Smith"
                    }
                  ]
                },
                "activeServicesForCustomer": {
                  "summary": "Active services for a customer (active_services takes no value)",
                  "value": [
                    {
                      "field": "cid",
                      "value": 12345,
                      "operator": "="
                    },
                    {
                      "field": "active_services"
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Search completed successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceSearchResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/{cid}/service-sites": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "services"
        ],
        "description": "List a customer's non-deleted service sites (the engineering_sites records shown in the UI as \"Service Sites\"). Constrained to the token's department via the customer.",
        "responses": {
          "200": {
            "description": "Service sites for the customer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceSiteListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/services/sites/customer/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "services"
        ],
        "description": "Alias of /{api_key}/customer/{cid}/service-sites — list a customer's non-deleted service sites.",
        "responses": {
          "200": {
            "description": "Service sites for the customer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceSiteListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/service-sites/get/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Service site ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "services"
        ],
        "description": "Fetch a single service site. Fails when the site does not exist, is deleted, or belongs to a customer outside the token's department.",
        "responses": {
          "200": {
            "description": "The service site",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceSiteGetResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/service-sites/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "services"
        ],
        "description": "Create a service site. cid must be a customer in the token's department; name must not be blank.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceSiteCreateItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Service site created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiCreateItemBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/service-sites/update/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Service site ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "services"
        ],
        "description": "Update a service site (name/sid/domain_name, and optionally cid to another customer in the same department). Fails for a nonexistent/deleted/cross-department site or a blank name.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceSiteCreateItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Service site updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/service-sites/delete/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Service site ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "services"
        ],
        "description": "Soft-delete a service site (deleted = 1; never a hard delete). Fails for a nonexistent/deleted/cross-department site.",
        "responses": {
          "200": {
            "description": "Service site deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiBasicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/engineering/{enid}/calculateETF": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "enid",
          "description": "Service/Engineering ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "services"
        ],
        "description": "Calculate Early Termination Fee (ETF) for a service",
        "responses": {
          "200": {
            "description": "ETF calculated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ETFCalculationResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/engineering/{enid}/doETF": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "enid",
          "description": "Service/Engineering ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "services"
        ],
        "description": "Execute Early Termination Fee (ETF) - creates invoice item for ETF charge",
        "responses": {
          "200": {
            "description": "ETF processed successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ETFExecutionResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/serviceBundles/get/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Service Bundle ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "service_bundles"
        ],
        "description": "Get detailed service bundle information including related services",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceBundleGetResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/serviceBundles/getByCustomer/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "service_bundles"
        ],
        "description": "Get all service bundles for a specific customer",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceBundleListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/externalsales/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "sales"
        ],
        "description": "Process external sales from e-commerce platforms (creates customer, invoice, items, and payments)",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExternalSaleItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sale processed successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalSaleResponse"
                }
              }
            }
          }
        }
      }
    },
    "/get-key/{user}/{pass}": {
      "parameters": [
        {
          "in": "path",
          "name": "user",
          "description": "Username",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "pass",
          "description": "Password",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "authentication"
        ],
        "description": "Authenticate user and retrieve API key",
        "responses": {
          "200": {
            "description": "Authentication result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetApiKeyResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/callType/get/page/{page_number}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "page_number",
          "description": "Page number (20 results per page)",
          "required": false,
          "schema": {
            "type": "integer",
            "default": 1
          }
        }
      ],
      "get": {
        "tags": [
          "cdr"
        ],
        "description": "Get paginated list of call types",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallTypesListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/callType/get/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Call Type ID (ctid)",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "cdr"
        ],
        "description": "Get detailed call type information including default rates",
        "responses": {
          "200": {
            "description": "Request received successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallTypeGetResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/services/get/monthlyCostByServiceNumber/{date}/{service_num}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "date",
          "description": "The date to calculate monthly cost for (YYYY-MM-DD format)",
          "required": true,
          "schema": {
            "type": "string",
            "format": "date"
          }
        },
        {
          "in": "path",
          "name": "service_num",
          "description": "The service number to get monthly cost for",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "services"
        ],
        "description": "Get the actual monthly cost charged for a service on a specific date (based on invoice data)",
        "responses": {
          "200": {
            "description": "Monthly cost retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MonthlyCostResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/services/get/monthlyCostByServiceNumber/proRata/{date}/{service_num}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "date",
          "description": "The start date to calculate pro-rata cost from (YYYY-MM-DD format)",
          "required": true,
          "schema": {
            "type": "string",
            "format": "date"
          }
        },
        {
          "in": "path",
          "name": "service_num",
          "description": "The service number to get pro-rata cost for",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "services"
        ],
        "description": "Calculate pro-rata monthly cost for a service starting on a specific date (calculated from monthlyfee)",
        "responses": {
          "200": {
            "description": "Pro-rata monthly cost calculated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MonthlyProRataCostResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/services/get/monthlyCostByServiceNumber/daily/{service_num}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "service_num",
          "description": "The service number to get daily cost for",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "services"
        ],
        "description": "Calculate daily cost for an active service (monthlyfee divided by days in current month)",
        "responses": {
          "200": {
            "description": "Daily cost calculated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DailyCostResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/engineering/item/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "services"
        ],
        "description": "Add a one-time charge item to a service (for additional fees, equipment, installation charges, etc.)",
        "requestBody": {
          "description": "Service item details. Product ID (pid) is required.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceItemCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Service item created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceItemCreateResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/engineering/item/update/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "The service item ID to update",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "services"
        ],
        "description": "Update a one-time charge item on a service",
        "requestBody": {
          "description": "Service item fields to update. All fields are optional.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceItemUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Service item updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/call_pack/get": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "call_management"
        ],
        "description": "Get all call packs for the department",
        "responses": {
          "200": {
            "description": "Call packs retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallPacksListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/call_pack/get/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Call pack ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "call_management"
        ],
        "description": "Get a specific call pack by ID",
        "responses": {
          "200": {
            "description": "Call pack retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallPackResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/call_pack/customer/get/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "call_management"
        ],
        "description": "Get all call packs for a specific customer",
        "responses": {
          "200": {
            "description": "Customer call packs retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallPacksListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/call_pack/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "call_management"
        ],
        "description": "Create a new call pack subscription for a customer",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CallPackCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Call pack created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/call_pack/upgrade/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Call pack ID to upgrade",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "call_management"
        ],
        "description": "Upgrade a call pack (ends current pack today, creates new pack from 1st of current month)",
        "responses": {
          "200": {
            "description": "Call pack upgraded successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/call_pack/downgrade/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Call pack ID to downgrade",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "call_management"
        ],
        "description": "Downgrade a call pack (ends current pack today, creates new pack from 1st of next month)",
        "responses": {
          "200": {
            "description": "Call pack downgraded successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/call_pack/cancel/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Call pack ID to cancel",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "call_management"
        ],
        "description": "Cancel a call pack (sets end date, minimum 30 days from now)",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "date_ended": {
                    "type": "string",
                    "format": "date",
                    "description": "Requested end date (must be at least 30 days from today)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Call pack cancelled successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/call_pack_type/get": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "call_management"
        ],
        "description": "Get all call pack types (templates) for the department",
        "responses": {
          "200": {
            "description": "Call pack types retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallPackTypesListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/call_pack_type/get/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Call pack type ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "call_management"
        ],
        "description": "Get a specific call pack type by ID",
        "responses": {
          "200": {
            "description": "Call pack type retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallPackTypeResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/call_pack_type/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "call_management"
        ],
        "description": "Create a new call pack type (template)",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CallPackTypeCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Call pack type created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/call_pack_type/update/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Call pack type ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "call_management"
        ],
        "description": "Update a call pack type",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CallPackTypeUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Call pack type updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/callRates/get/page/{page_number}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "page_number",
          "description": "Page number (default: 1)",
          "required": false,
          "schema": {
            "type": "integer",
            "default": 1
          }
        }
      ],
      "get": {
        "tags": [
          "call_management"
        ],
        "description": "Get paginated list of call rate groups (tariff groups)",
        "responses": {
          "200": {
            "description": "Call rates retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallRatesListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/callRates/get/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Call rate group ID (ctgid)",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "call_management"
        ],
        "description": "Get a specific call rate group with all associated call type rates",
        "responses": {
          "200": {
            "description": "Call rate group retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallRateGroupResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/callRates/post": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "call_management"
        ],
        "description": "Create or update a call rate group with call type rates",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CallRateGroupSave"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Call rate group saved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "ctgid": {
                      "type": "integer",
                      "description": "The call rate group ID"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/tickets": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "helpdesk"
        ],
        "description": "Get paginated list of helpdesk tickets with filtering",
        "parameters": [
          {
            "in": "query",
            "name": "status",
            "description": "Filter by status (0=open, 1=closed, 2=void)",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "cid",
            "description": "Filter by customer ID",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "uid",
            "description": "Filter by assigned user ID",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "priority",
            "description": "Filter by priority (1=low, 2=medium, 3=high)",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "search",
            "description": "Search in subject and company",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "description": "Records per page (default: 20)",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tickets retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HelpdeskTicketsListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/tickets/page/{page_number}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "page_number",
          "description": "Page number",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "helpdesk"
        ],
        "description": "Get paginated list of helpdesk tickets",
        "responses": {
          "200": {
            "description": "Tickets retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HelpdeskTicketsListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/tickets/outstanding": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "helpdesk"
        ],
        "description": "Get all outstanding (open) tickets",
        "responses": {
          "200": {
            "description": "Outstanding tickets retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HelpdeskTicketsListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/tickets/outstanding/{uid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "uid",
          "description": "User ID to filter by",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "helpdesk"
        ],
        "description": "Get outstanding tickets for a specific user",
        "responses": {
          "200": {
            "description": "Outstanding tickets retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HelpdeskTicketsListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/tickets/search": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "helpdesk"
        ],
        "description": "Search helpdesk tickets",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HelpdeskSearchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Search results retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HelpdeskTicketsListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/ticket/create": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "helpdesk"
        ],
        "description": "Create a new helpdesk ticket",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HelpdeskTicketCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ticket created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HelpdeskTicketCreateResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/ticket/{htid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "htid",
          "description": "Helpdesk ticket ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "helpdesk"
        ],
        "description": "Get a specific helpdesk ticket with full details",
        "responses": {
          "200": {
            "description": "Ticket retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HelpdeskTicketResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/ticket/{htid}/attachment/{rdid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "htid",
          "description": "Helpdesk ticket ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        },
        {
          "in": "path",
          "name": "rdid",
          "description": "Attachment record ID (attacheddoclist.rdid) as returned by the ticket detail response",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "helpdesk"
        ],
        "description": "Download a single attachment belonging to a helpdesk ticket. The file content is base64 encoded in the JSON response. Files larger than 10MB are not served.",
        "responses": {
          "200": {
            "description": "Attachment retrieved successfully, or a JSON error describing why it could not be served",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HelpdeskAttachmentDownloadResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/ticket/{htid}/update": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "htid",
          "description": "Helpdesk ticket ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "helpdesk"
        ],
        "description": "Update a helpdesk ticket",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HelpdeskTicketUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ticket updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HelpdeskTicketResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/ticket/{htid}/assign/{uid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "htid",
          "description": "Helpdesk ticket ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        },
        {
          "in": "path",
          "name": "uid",
          "description": "User ID to assign to (0 for unassigned)",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "helpdesk"
        ],
        "description": "Assign a ticket to a user",
        "responses": {
          "200": {
            "description": "Ticket assigned successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/ticket/{htid}/close": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "htid",
          "description": "Helpdesk ticket ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "helpdesk"
        ],
        "description": "Close a helpdesk ticket",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "note": {
                    "type": "string",
                    "description": "Closing note"
                  },
                  "uid": {
                    "type": "integer",
                    "description": "User closing the ticket"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ticket closed successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/ticket/{htid}/reopen": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "htid",
          "description": "Helpdesk ticket ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "helpdesk"
        ],
        "description": "Reopen a closed helpdesk ticket",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "note": {
                    "type": "string",
                    "description": "Reopening note"
                  },
                  "uid": {
                    "type": "integer",
                    "description": "User reopening the ticket"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ticket reopened successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/ticket/{htid}/void": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "htid",
          "description": "Helpdesk ticket ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "helpdesk"
        ],
        "description": "Void a helpdesk ticket",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "note": {
                    "type": "string",
                    "description": "Void reason"
                  },
                  "uid": {
                    "type": "integer",
                    "description": "User voiding the ticket"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ticket voided successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/ticket/{htid}/priority/{priority}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "htid",
          "description": "Helpdesk ticket ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        },
        {
          "in": "path",
          "name": "priority",
          "description": "Priority level (1=low, 2=medium, 3=high)",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "helpdesk"
        ],
        "description": "Set ticket priority",
        "responses": {
          "200": {
            "description": "Priority updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/ticket/{htid}/notes": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "htid",
          "description": "Helpdesk ticket ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "helpdesk"
        ],
        "description": "Get all notes for a ticket",
        "responses": {
          "200": {
            "description": "Notes retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HelpdeskNotesResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/ticket/{htid}/note/add": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "htid",
          "description": "Helpdesk ticket ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "helpdesk"
        ],
        "description": "Add a note to a ticket",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HelpdeskNoteCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Note added successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HelpdeskNoteResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/note/{noteid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "noteid",
          "description": "Note ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "helpdesk"
        ],
        "description": "Get a specific note",
        "responses": {
          "200": {
            "description": "Note retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HelpdeskNoteResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/note/{noteid}/update": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "noteid",
          "description": "Note ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "helpdesk"
        ],
        "description": "Update a note",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HelpdeskNoteUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Note updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HelpdeskNoteResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/note/{noteid}/delete": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "noteid",
          "description": "Note ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "helpdesk"
        ],
        "description": "Delete a note",
        "responses": {
          "200": {
            "description": "Note deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/helpdesk/customer/{cid}/tickets": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "helpdesk"
        ],
        "description": "Get all tickets for a customer",
        "parameters": [
          {
            "in": "query",
            "name": "status",
            "description": "Filter by status",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "description": "Limit results",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer tickets retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HelpdeskCustomerTicketsResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/orders/get": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "orders"
        ],
        "description": "Get paginated list of orders",
        "responses": {
          "200": {
            "description": "Orders retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrdersListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/orders/get/page/{page_number}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "page_number",
          "description": "Page number (default: 1)",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "orders"
        ],
        "description": "Get paginated list of orders",
        "responses": {
          "200": {
            "description": "Orders retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrdersListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/orders/get/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Order ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "orders"
        ],
        "description": "Get a specific order with full details",
        "responses": {
          "200": {
            "description": "Order retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/orders/update/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Order ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "orders"
        ],
        "description": "Update an existing order",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Order updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/orders/updateData/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Order ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "orders"
        ],
        "description": "Update order workflow data",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderDataUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Order data updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/products/getAll": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "products"
        ],
        "description": "Get all products (no pagination)",
        "responses": {
          "200": {
            "description": "All products retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductsAllResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/getAll": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "customers"
        ],
        "description": "Get all active customers (no pagination)",
        "responses": {
          "200": {
            "description": "All customers retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomersAllResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/get/page/{page_number}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "page_number",
          "description": "Page number (default: 1)",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customers"
        ],
        "description": "Get paginated list of customers",
        "responses": {
          "200": {
            "description": "Customers retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomersListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/get/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customers"
        ],
        "description": "Get a specific customer with full details",
        "responses": {
          "200": {
            "description": "Customer retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/search/{field}/{value}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "field",
          "description": "Field to search (e.g., 'role', 'email', 'company')",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "value",
          "description": "Search value (minimum 3 characters)",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "customers"
        ],
        "description": "Search customers by field",
        "responses": {
          "200": {
            "description": "Search results retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomersSearchResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/get/services/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customers"
        ],
        "description": "Get all services assigned to a customer",
        "responses": {
          "200": {
            "description": "Customer services retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerServicesResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/get/statement/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        },
        {
          "in": "query",
          "name": "format",
          "description": "Output format. Omitted or 'pdf' returns the inline PDF (default); 'json' returns the statement rows as structured JSON.",
          "required": false,
          "schema": {
            "type": "string",
            "enum": [
              "pdf",
              "json"
            ],
            "default": "pdf"
          }
        },
        {
          "in": "query",
          "name": "date_to",
          "description": "Optional window end (YYYY-MM-DD). Defaults to today when omitted.",
          "required": false,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "customers"
        ],
        "description": "Get customer statement as an inline PDF (default), or as structured JSON when format=json is passed.",
        "responses": {
          "200": {
            "description": "Inline PDF statement, or the JSON statement when format=json (JSON errors also return 200 with success=false).",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerStatementResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/get/statement/{cid}/{date_from}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        },
        {
          "in": "path",
          "name": "date_from",
          "description": "Start date for statement (YYYY-MM-DD)",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "query",
          "name": "format",
          "description": "Output format. Omitted or 'pdf' returns the inline PDF (default); 'json' returns the statement rows as structured JSON.",
          "required": false,
          "schema": {
            "type": "string",
            "enum": [
              "pdf",
              "json"
            ],
            "default": "pdf"
          }
        },
        {
          "in": "query",
          "name": "date_to",
          "description": "Optional window end (YYYY-MM-DD). Defaults to today when omitted.",
          "required": false,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "customers"
        ],
        "description": "Get customer statement from a specific date as an inline PDF (default), or as structured JSON when format=json is passed.",
        "responses": {
          "200": {
            "description": "Inline PDF statement, or the JSON statement when format=json (JSON errors also return 200 with success=false).",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerStatementResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/getManagementStatus/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customers"
        ],
        "description": "Get customer management status",
        "responses": {
          "200": {
            "description": "Management status retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerManagementStatusResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/setManagementStatus/{cid}/{status}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        },
        {
          "in": "path",
          "name": "status",
          "description": "Management status to set",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "customers"
        ],
        "description": "Set customer management status",
        "responses": {
          "200": {
            "description": "Management status updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/authenticate/": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "customers"
        ],
        "description": "Authenticate a customer",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "password"
                ],
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Authentication result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerAuthResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/contact/add/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "customer_contacts"
        ],
        "description": "Add a contact to a customer",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contact added successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/contact/get/{cid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "cid",
          "description": "Customer ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customer_contacts"
        ],
        "description": "Get all contacts for a customer",
        "responses": {
          "200": {
            "description": "Contacts retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactsListResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/calendar/getCalendar/{uid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "uid",
          "description": "User ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "calendar"
        ],
        "description": "Get calendar HTML for a user",
        "responses": {
          "200": {
            "description": "HTML calendar",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/calendar/getEvents/{uid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "uid",
          "description": "User ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "calendar"
        ],
        "description": "Get calendar events as JSON",
        "responses": {
          "200": {
            "description": "Calendar events retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CalendarEventsResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/calendar/getEventsUrl/{uid}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "uid",
          "description": "User ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "calendar"
        ],
        "description": "Get calendar events as iCalendar (.ics) file",
        "responses": {
          "200": {
            "description": "iCalendar file",
            "content": {
              "text/calendar": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/billruns": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "query",
          "name": "billrun_template_id",
          "description": "Only return bill runs for this bill run template",
          "required": false,
          "schema": {
            "type": "integer"
          }
        },
        {
          "in": "query",
          "name": "complete",
          "description": "Filter on the completed flag (0 or 1)",
          "required": false,
          "schema": {
            "type": "integer",
            "example": 1
          }
        },
        {
          "in": "query",
          "name": "approved",
          "description": "Filter on the approved flag (0 or 1)",
          "required": false,
          "schema": {
            "type": "integer",
            "example": 0
          }
        },
        {
          "in": "query",
          "name": "page",
          "description": "1-based page number (default 1)",
          "required": false,
          "schema": {
            "type": "integer",
            "example": 1
          }
        },
        {
          "in": "query",
          "name": "limit",
          "description": "Records per page (default 20, maximum 200)",
          "required": false,
          "schema": {
            "type": "integer",
            "example": 20
          }
        }
      ],
      "get": {
        "tags": [
          "billruns"
        ],
        "description": "List bill runs. Only non-deleted bill runs belonging to the API token's department are returned. Results are ordered by start date, newest first.",
        "responses": {
          "200": {
            "description": "A page of bill runs",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillRunListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "billruns"
        ],
        "description": "Create a bill run. Only the whitelisted fields are accepted; `deptid` is taken from the API token and `approved` cannot be set here — use `POST /{api_key}/billruns/{id}/approve`. `start_date` defaults to now.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillRunWritableItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created bill run",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillRunCreateResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/billruns/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Bill run ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "billruns"
        ],
        "description": "Fetch a single bill run. Fails when the bill run does not exist, is deleted, or belongs to another department.",
        "responses": {
          "200": {
            "description": "The bill run",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillRunGetResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "billruns"
        ],
        "description": "Update a bill run. Only the whitelisted fields are accepted; supplying `approved` is rejected — use `POST /{api_key}/billruns/{id}/approve`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillRunWritableItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated bill run",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillRunUpdateResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "billruns"
        ],
        "description": "Identical to the POST form of this endpoint.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillRunWritableItem"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated bill run",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillRunUpdateResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/billruns/{id}/delete": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Bill run ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "billruns"
        ],
        "description": "Soft-delete a bill run (sets `deleted = 1`). The row is never physically removed and the bill run disappears from the list and get endpoints.",
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillRunDeleteResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "billruns"
        ],
        "description": "Identical to the POST form of this endpoint.",
        "responses": {
          "200": {
            "description": "Deletion result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillRunDeleteResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/billruns/{id}/approve": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Bill run ID",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "billruns"
        ],
        "description": "Approve a bill run. Marks the run approved, authorises its pending invoices (applying the run's `update_invoice_date_on_approval` date shift), dispatches the invoice emails, runs the un-emailed invoice audit and the approval postflight — identical behaviour to the `cli_approve_billrun.php` CLI. A bill run that is already approved is rejected (`already_approved: true`) so nothing is authorised or emailed twice; pass `{\"resend\": true}` to re-email an approved run without re-authorising it or shifting invoice dates.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillRunApproveRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Approval summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillRunApproveResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/bulk-email/filters": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "customer_bulk_email"
        ],
        "description": "List the whitelisted recipient filter fields and the joins that may combine them. These are the only fields accepted by the preview and create endpoints. Failures use the standard envelope with a stable `error_code`. Possible values: `invalid_key` (unknown or malformed API key), `capability_denied` (the key does not have `\"bulk_email\": true` in `api_keys.data`), `deptid_not_allowed` (the request supplied a department; the key department is authoritative), `invalid_request` (the body was not JSON), `attachments_not_supported` (attachments are not implemented in v1), `missing_subject`, `missing_content`, `invalid_schedule` (unparseable, impossible, or more than 90 days ahead), `no_recipients` (the selection resolved to nobody), `recipient_count_changed` (`confirm_count` no longer matches the resolved count), `too_many_recipients` (above `bulk_email_max_recipients`, default 5000), `daily_campaign_limit_reached` (above `bulk_email_max_daily_campaigns`, default 10), `duplicate_campaign` (same department and subject within 60 seconds), `create_failed` (the queue row could not be written), `not_found` (no such campaign in the key department), `campaign_completed` / `already_cancelled` (the campaign can no longer be cancelled).",
        "responses": {
          "200": {
            "description": "Filter metadata",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkEmailFiltersResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/bulk-email/preview": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "customer_bulk_email"
        ],
        "description": "Resolve the recipient set for a filter selection without queueing anything. Returns the full recipient count plus a capped sample (default 25, maximum 1000), and - when both subject and content are supplied - a first-recipient merge-field render identical to what the sender will produce. Recipients are always restricted to active customers with a valid email in the API key department; `customer_ids` only narrows that set. Request and response bodies are deliberately not written to api_logs. Failures use the standard envelope with a stable `error_code`. Possible values: `invalid_key` (unknown or malformed API key), `capability_denied` (the key does not have `\"bulk_email\": true` in `api_keys.data`), `deptid_not_allowed` (the request supplied a department; the key department is authoritative), `invalid_request` (the body was not JSON), `attachments_not_supported` (attachments are not implemented in v1), `missing_subject`, `missing_content`, `invalid_schedule` (unparseable, impossible, or more than 90 days ahead), `no_recipients` (the selection resolved to nobody), `recipient_count_changed` (`confirm_count` no longer matches the resolved count), `too_many_recipients` (above `bulk_email_max_recipients`, default 5000), `daily_campaign_limit_reached` (above `bulk_email_max_daily_campaigns`, default 10), `duplicate_campaign` (same department and subject within 60 seconds), `create_failed` (the queue row could not be written), `not_found` (no such campaign in the key department), `campaign_completed` / `already_cancelled` (the campaign can no longer be cancelled).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkEmailPreviewRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Recipient preview",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkEmailPreviewResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/bulk-email": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "customer_bulk_email"
        ],
        "description": "Queue a bulk email campaign. Recipients are re-resolved server-side from the supplied filters, so the caller never provides addresses. Creates one `bulk_emails` row and one `bulk_emails_contacts` row per recipient and returns immediately - no mail is sent during the request; delivery is performed by the scheduled sender (modules/customer/cli_send_emails.php). Request bodies are deliberately not written to api_logs. Failures use the standard envelope with a stable `error_code`. Possible values: `invalid_key` (unknown or malformed API key), `capability_denied` (the key does not have `\"bulk_email\": true` in `api_keys.data`), `deptid_not_allowed` (the request supplied a department; the key department is authoritative), `invalid_request` (the body was not JSON), `attachments_not_supported` (attachments are not implemented in v1), `missing_subject`, `missing_content`, `invalid_schedule` (unparseable, impossible, or more than 90 days ahead), `no_recipients` (the selection resolved to nobody), `recipient_count_changed` (`confirm_count` no longer matches the resolved count), `too_many_recipients` (above `bulk_email_max_recipients`, default 5000), `daily_campaign_limit_reached` (above `bulk_email_max_daily_campaigns`, default 10), `duplicate_campaign` (same department and subject within 60 seconds), `create_failed` (the queue row could not be written), `not_found` (no such campaign in the key department), `campaign_completed` / `already_cancelled` (the campaign can no longer be cancelled).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkEmailCreateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campaign queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkEmailCreateResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/bulk-email/page/{pageNumber}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "pageNumber",
          "description": "Page of campaign history, 20 per page, newest first",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customer_bulk_email"
        ],
        "description": "Campaign history for the API key department, 20 per page, newest first, each with its derived status and progress counts. Failures use the standard envelope with a stable `error_code`. Possible values: `invalid_key` (unknown or malformed API key), `capability_denied` (the key does not have `\"bulk_email\": true` in `api_keys.data`), `deptid_not_allowed` (the request supplied a department; the key department is authoritative), `invalid_request` (the body was not JSON), `attachments_not_supported` (attachments are not implemented in v1), `missing_subject`, `missing_content`, `invalid_schedule` (unparseable, impossible, or more than 90 days ahead), `no_recipients` (the selection resolved to nobody), `recipient_count_changed` (`confirm_count` no longer matches the resolved count), `too_many_recipients` (above `bulk_email_max_recipients`, default 5000), `daily_campaign_limit_reached` (above `bulk_email_max_daily_campaigns`, default 10), `duplicate_campaign` (same department and subject within 60 seconds), `create_failed` (the queue row could not be written), `not_found` (no such campaign in the key department), `campaign_completed` / `already_cancelled` (the campaign can no longer be cancelled).",
        "responses": {
          "200": {
            "description": "Campaign history page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkEmailHistoryResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/bulk-email/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Bulk email campaign id",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "customer_bulk_email"
        ],
        "description": "Status and progress for one campaign. Scoped to the API key department: another department's campaign is reported as `not_found`. Failures use the standard envelope with a stable `error_code`. Possible values: `invalid_key` (unknown or malformed API key), `capability_denied` (the key does not have `\"bulk_email\": true` in `api_keys.data`), `deptid_not_allowed` (the request supplied a department; the key department is authoritative), `invalid_request` (the body was not JSON), `attachments_not_supported` (attachments are not implemented in v1), `missing_subject`, `missing_content`, `invalid_schedule` (unparseable, impossible, or more than 90 days ahead), `no_recipients` (the selection resolved to nobody), `recipient_count_changed` (`confirm_count` no longer matches the resolved count), `too_many_recipients` (above `bulk_email_max_recipients`, default 5000), `daily_campaign_limit_reached` (above `bulk_email_max_daily_campaigns`, default 10), `duplicate_campaign` (same department and subject within 60 seconds), `create_failed` (the queue row could not be written), `not_found` (no such campaign in the key department), `campaign_completed` / `already_cancelled` (the campaign can no longer be cancelled).",
        "responses": {
          "200": {
            "description": "Campaign status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkEmailStatusResponse"
                }
              }
            }
          }
        }
      }
    },
    "/{api_key}/customer/bulk-email/{id}/cancel": {
      "parameters": [
        {
          "in": "path",
          "name": "api_key",
          "description": "The API Token",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "in": "path",
          "name": "id",
          "description": "Bulk email campaign id",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "post": {
        "tags": [
          "customer_bulk_email"
        ],
        "description": "Prevent any further delivery for a campaign: unsent recipients are withdrawn (soft-deleted) and the campaign is ended. Cancellation is not a recall - messages already sent cannot be retrieved, and a message the sender was transmitting when the request arrived may still be delivered. A campaign that has already completed or been cancelled is rejected. Failures use the standard envelope with a stable `error_code`. Possible values: `invalid_key` (unknown or malformed API key), `capability_denied` (the key does not have `\"bulk_email\": true` in `api_keys.data`), `deptid_not_allowed` (the request supplied a department; the key department is authoritative), `invalid_request` (the body was not JSON), `attachments_not_supported` (attachments are not implemented in v1), `missing_subject`, `missing_content`, `invalid_schedule` (unparseable, impossible, or more than 90 days ahead), `no_recipients` (the selection resolved to nobody), `recipient_count_changed` (`confirm_count` no longer matches the resolved count), `too_many_recipients` (above `bulk_email_max_recipients`, default 5000), `daily_campaign_limit_reached` (above `bulk_email_max_daily_campaigns`, default 10), `duplicate_campaign` (same department and subject within 60 seconds), `create_failed` (the queue row could not be written), `not_found` (no such campaign in the key department), `campaign_completed` / `already_cancelled` (the campaign can no longer be cancelled).",
        "responses": {
          "200": {
            "description": "Campaign cancelled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkEmailCancelResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "QualificationItem": {
        "type": "object",
        "required": [
          "service_type_id",
          "list_price"
        ],
        "properties": {
          "location": {
            "type": "string",
            "example": "LOC000000000001"
          },
          "ndf": {
            "type": "boolean",
            "description": "Is a new Development Fee Required"
          },
          "fibre_upgrade": {
            "type": "boolean",
            "description": "Is there the ability to upgrade to a fibre connection"
          },
          "technology": {
            "type": "string",
            "example": "FIBRE",
            "description": "the technology used to deliver the service"
          },
          "zone": {
            "type": "string",
            "example": "Urban",
            "description": "the Zone for billing"
          },
          "address": {
            "type": "string",
            "example": "72 York Street, South Melbourne, VIC",
            "description": "The address matched for qualitfication, returned from the upstream provider"
          },
          "avc_match": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the AVC ID matches the address. Only returned when avcid parameter is provided."
          },
          "avc_target": {
            "type": "string",
            "nullable": true,
            "description": "The matching CopperPairID or PortID. Only returned when avcid parameter is provided and avc_match is true."
          },
          "avc_current_epid": {
            "type": "string",
            "nullable": true,
            "description": "The current provider's EPID code. Only returned when avcid parameter is provided and avc_match is true."
          },
          "primary_technology": {
            "type": "string",
            "nullable": true,
            "description": "The primary NBN technology at this address (e.g. FTTP, HFC, FTTC)"
          },
          "original_technology": {
            "type": "string",
            "nullable": true,
            "description": "The original NBN technology at this address, before any upgrades"
          },
          "carrier_response": {
            "type": "object",
            "description": "The Reponse from the upstream carrier, varies based on carrier"
          },
          "service_types": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "service_type_id": {
                  "type": "integer",
                  "example": 55,
                  "description": "The id of the service type"
                },
                "name": {
                  "type": "string",
                  "example": "NBN 50/20",
                  "description": "The Name of the service type"
                },
                "list_price": {
                  "type": "number",
                  "example": 60
                },
                "is_business": {
                  "type": "boolean",
                  "description": "If the service is set to Service Grade Business or Enterprise"
                },
                "requires_upgrade": {
                  "type": "boolean",
                  "description": "Will only be available on a fibre_upgrade qualification, and indicates if the speed is only available on an upgrade"
                },
                "available": {
                  "type": "boolean",
                  "description": "Is this service type available for this location.  By default this is only ever false on a wireless service, the service types are not returned for the other technologies"
                },
                "appointment_required": {
                  "type": "boolean",
                  "description": "Will only be available on Wireless services, it will be set to true if an upgrade is required and a NBN appointment is required"
                }
              }
            }
          }
        }
      },
      "AVCCheckResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the API call was successful"
          },
          "result": {
            "type": "string",
            "enum": [
              "PASS",
              "REJECTED",
              "REJECTED-CVC",
              "MANUAL"
            ],
            "description": "The qualification result from the carrier"
          },
          "avc_match": {
            "type": "boolean",
            "description": "Whether the AVC ID matches the location"
          },
          "avc_target": {
            "type": "string",
            "nullable": true,
            "description": "The matching CopperPairID or PortID when avc_match is true",
            "example": "CPI300010022999"
          },
          "current_epid": {
            "type": "string",
            "nullable": true,
            "description": "The current provider's EPID code. List available at commsalliance.com.au",
            "example": "05S62"
          },
          "primary_technology": {
            "type": "string",
            "nullable": true,
            "description": "The primary NBN technology at this address",
            "example": "FTTC"
          },
          "original_technology": {
            "type": "string",
            "nullable": true,
            "description": "The original NBN technology at this address",
            "example": "FTTC"
          }
        }
      },
      "OrderItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "cid": {
            "type": "integer"
          },
          "company": {
            "type": "string"
          },
          "order_type": {
            "type": "string"
          },
          "service_type": {
            "type": "string"
          },
          "date_ordered": {
            "type": "string",
            "format": "date"
          },
          "date_expected": {
            "type": "string",
            "format": "date"
          },
          "status": {
            "type": "string"
          }
        }
      },
      "PaymentItem": {
        "type": "object",
        "required": [
          "amount"
        ],
        "properties": {
          "amount": {
            "type": "number",
            "format": "decimal",
            "example": 50,
            "description": "the decimal number of the amount to charge, if you are storing a card details only, you can leave this empty, null or 0"
          },
          "bank_on_file": {
            "type": "boolean",
            "description": "force use of the bank details on file ( rqeuires department to have a default direct deposit gateway set )"
          },
          "card_on_file": {
            "type": "boolean",
            "description": "force use of the card details on file ( requires department to have a default credit card gateway set )"
          },
          "payment_token": {
            "type": "string",
            "description": "a payment/card token to perform the transaction against"
          },
          "cc_name": {
            "type": "string",
            "description": "the card holders name"
          },
          "cc_number": {
            "type": "number",
            "description": "the card number"
          },
          "cc_expmonth": {
            "type": "number",
            "description": "the 2 digit of the expiry month"
          },
          "cc_expyear": {
            "type": "number",
            "description": "the 2 digit expiry of the year"
          },
          "cc_ccv": {
            "type": "number",
            "description": "the card's ccv"
          },
          "store_card": {
            "type": "boolean",
            "description": "Store this card on file for the customer"
          }
        }
      },
      "ApiBasicResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "whether the request was able to process successfully or not"
          },
          "description": {
            "type": "string",
            "description": "The message from the request ( Success for a good transaction )",
            "example": "success"
          }
        }
      },
      "ApiCreateItemBasicResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "whether the request was able to process successfully or not"
          },
          "description": {
            "type": "string",
            "description": "The message from the request ( Success for a good transaction )",
            "example": "success"
          },
          "id": {
            "type": "integer",
            "description": "ID of the record just created",
            "example": 787873
          }
        }
      },
      "LeadsGetResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "whether the request was able to process successfully or not"
          },
          "lead": {
            "$ref": "#/components/schemas/LeadItem"
          }
        }
      },
      "LeadsListResponse": {
        "type": "object",
        "properties": {
          "page_number": {
            "type": "integer",
            "description": "the page number returned"
          },
          "total_pages": {
            "type": "integer",
            "description": "the total number of pages"
          },
          "results": {
            "type": "object",
            "properties": {
              "lid": {
                "type": "integer",
                "description": "the id of the lead"
              },
              "Company": {
                "type": "string",
                "description": "The Company Name"
              },
              "Name": {
                "type": "string",
                "description": "The Lead Name"
              },
              "Phone": {
                "type": "string",
                "description": "the phone number for the lead"
              },
              "Address": {
                "type": "string",
                "description": "The address if available, if not No Adddress is shown"
              },
              "Status": {
                "type": "string",
                "description": "Current Lead Status"
              }
            }
          }
        }
      },
      "LeadItem": {
        "type": "object",
        "properties": {
          "lid": {
            "type": "integer",
            "description": "Lead id",
            "example": 456
          },
          "Status": {
            "type": "string",
            "description": "Current Lead Status",
            "example": "Hot Leads"
          },
          "Company": {
            "type": "string",
            "description": "Company Name",
            "example": "Pracbill"
          },
          "Title": {
            "type": "string",
            "description": "Leads Title",
            "example": "Mr"
          },
          "Name": {
            "type": "string",
            "description": "First Name",
            "example": "John"
          },
          "Middle Name": {
            "type": "string",
            "description": "Middle Name",
            "example": "Joe"
          },
          "Surname": {
            "type": "string",
            "description": "Last Name",
            "example": "Citizen"
          },
          "Sex": {
            "type": "string",
            "description": "Gender",
            "example": "Male"
          },
          "Date Of Birth": {
            "type": "string",
            "description": "Date Of Birth",
            "example": "1990-05-05T00:00:00.000Z"
          },
          "Logo": {
            "type": "string",
            "description": "URL For Logo",
            "example": "https://billing.pracbill.com.au/images/lead_logo.png"
          },
          "Phone": {
            "type": "string",
            "description": "Phone number for Lead",
            "example": 1300927598
          },
          "Mobile": {
            "type": "string",
            "description": "Mobile Contact number",
            "example": 411222333
          },
          "Fax": {
            "type": "string",
            "description": "Fax Number",
            "example": 399998888
          },
          "Email": {
            "type": "string",
            "description": "Email Address",
            "example": "joe@citizen.com"
          },
          "Website": {
            "type": "string",
            "description": "Company Website",
            "example": "http://citizen.com"
          },
          "Billing Address": {
            "type": "string",
            "description": "Billing Address",
            "example": "123 Main Street, Big City"
          },
          "Comments": {
            "type": "string",
            "description": "Any Comments about the lead",
            "example": "VIP Lead, ensure they get everything"
          },
          "Security Question": {
            "type": "string",
            "description": "A security question for validate Lead",
            "example": "Mothers maiden name"
          },
          "Security Answer": {
            "type": "string",
            "description": "Security Question Answer",
            "example": "Eve"
          },
          "Lead Type": {
            "type": "string",
            "description": "Type of lead, this is controlled by a Lookup Table in pracbill \"Lead Types\" any non matching value may not render",
            "example": "Business"
          },
          "Lead Source": {
            "type": "string",
            "description": "Where the lead came from, this is controlled by a Lookup Table in pracbill \"Lead Sources\" any non matching value may not render",
            "example": "Google"
          },
          "Security": {
            "type": "string",
            "description": "Security Method to apply"
          },
          "date_created": {
            "type": "string",
            "description": "Date Created",
            "example": "2024-01-10 10:19:19"
          },
          "date_modified": {
            "type": "string",
            "description": "Date Last Modified",
            "example": "2025-01-20 20:29:04"
          }
        }
      },
      "LeadsFilterOption": {
        "type": "object",
        "description": "All Items are optional, only use the items required",
        "properties": {
          "company": {
            "type": "string",
            "description": "company name"
          },
          "email": {
            "type": "string",
            "description": "email address"
          },
          "phone": {
            "type": "string",
            "description": "Phone number"
          },
          "type": {
            "type": "string",
            "description": "The type of lead"
          },
          "source": {
            "type": "string",
            "description": "lead source, where did this lead come from?"
          },
          "ntoes": {
            "type": "string",
            "description": "any internal notes about the lead"
          },
          "status": {
            "type": "string",
            "description": "Current status the lead is in"
          }
        }
      },
      "CustomerUpdateItem": {
        "type": "object",
        "properties": {
          "company": {
            "type": "string",
            "description": "Company Name"
          },
          "name": {
            "type": "string",
            "description": "first name",
            "example": "John"
          },
          "surname": {
            "type": "string",
            "description": "last name",
            "example": "Citizen"
          },
          "email": {
            "type": "string",
            "description": "customer email address",
            "example": "sales@pracbill.com.au"
          },
          "mobile": {
            "type": "string",
            "description": "mobile phone contact number",
            "example": 411222333
          },
          "phone": {
            "type": "string",
            "description": "primary contact number",
            "example": 411222333
          },
          "full_address": {
            "type": "string",
            "description": "full address string ( Address will be looked up using Google )",
            "example": "72 York Street, South Melbourne, VIC, 3002"
          },
          "web_password": {
            "type": "string",
            "description": "plain text password for customer portal access"
          },
          "dob": {
            "type": "string",
            "format": "date",
            "description": "customer date of birth"
          },
          "abn": {
            "type": "number",
            "description": "abn for business"
          },
          "paymethod": {
            "type": "string",
            "description": "the payment method to use ( Invoice, Credit Card, Direct Debit )"
          },
          "ctgid": {
            "type": "integer",
            "description": "call rates id for this customer, only need if custom rates are required for this customer"
          },
          "price_book_id": {
            "type": "integer",
            "description": "price book id for this customer. only need if custom prices are required for this customer"
          },
          "expected_revenue": {
            "type": "integer",
            "description": "monthly expected revenue"
          },
          "minimum_spend": {
            "type": "integer",
            "description": "minimum spend requirements"
          },
          "credit_limit": {
            "type": "number",
            "format": "decimal",
            "description": "the total credit limit we should apply to this customer"
          },
          "terms": {
            "type": "integer",
            "description": "the number of days before an invoice is due"
          },
          "billinggroup": {
            "type": "string",
            "description": "the billing group"
          },
          "reseller_cid": {
            "type": "integer",
            "description": "the reseller ( customer id ) that referred this customer"
          },
          "trading_name": {
            "type": "string",
            "description": "Company Trading Name"
          },
          "agreement_start": {
            "type": "string",
            "format": "date",
            "description": "When does the current agreement start"
          },
          "agreement_end": {
            "type": "string",
            "format": "date",
            "description": "When does the current agreement end"
          },
          "currency": {
            "type": "string",
            "description": "The Specific currency to use for this customer, not required if they are using the department default"
          },
          "do_not_send_invoice": {
            "type": "boolean",
            "description": "set to true to not email invoices to customer"
          },
          "bank_name": {
            "type": "string",
            "description": "the name on the bank account"
          },
          "bank_number": {
            "type": "number",
            "description": "the account number on the bank account"
          },
          "bank_bsb": {
            "type": "number",
            "description": "the 6 digit bsb on the bank account"
          }
        }
      },
      "CustomerItemAdd": {
        "type": "object",
        "required": [
          "cid",
          "pid"
        ],
        "properties": {
          "charge_date": {
            "type": "string",
            "format": "date",
            "description": "Date of the charge (YYYY-MM-DD or DD/MM/YYYY format). Defaults to today if not provided",
            "example": "2025-12-21"
          },
          "cid": {
            "type": "integer",
            "description": "Customer ID (required)",
            "example": 123
          },
          "quantity": {
            "type": "number",
            "format": "decimal",
            "description": "Quantity of items. Defaults to 1 if not provided",
            "example": 1
          },
          "pid": {
            "type": "integer",
            "description": "Product ID (required)",
            "example": 456
          },
          "taxrate_id": {
            "type": "integer",
            "description": "Tax rate ID. Auto-populated from product if not provided"
          },
          "inc_tax_amount": {
            "type": "number",
            "format": "decimal",
            "description": "Amount including tax. Auto-populated from product if not provided",
            "example": 110.0
          },
          "description": {
            "type": "string",
            "description": "Description of the charge. Auto-populated from product if not provided",
            "example": "Custom service charge"
          },
          "source": {
            "type": "string",
            "description": "Source of the charge",
            "example": "API"
          }
        }
      },
      "CustomerItemUpdate": {
        "type": "object",
        "properties": {
          "charge_date": {
            "type": "string",
            "format": "date",
            "description": "Date of the charge (YYYY-MM-DD or DD/MM/YYYY format)",
            "example": "2025-12-21"
          },
          "cid": {
            "type": "integer",
            "description": "Customer ID",
            "example": 123
          },
          "quantity": {
            "type": "number",
            "format": "decimal",
            "description": "Quantity of items",
            "example": 1
          },
          "pid": {
            "type": "integer",
            "description": "Product ID. If changed, tax rates will be recalculated",
            "example": 456
          },
          "taxrate_id": {
            "type": "integer",
            "description": "Tax rate ID"
          },
          "inc_tax_amount": {
            "type": "number",
            "format": "decimal",
            "description": "Amount including tax",
            "example": 120.0
          },
          "description": {
            "type": "string",
            "description": "Description of the charge",
            "example": "Updated charge description"
          },
          "source": {
            "type": "string",
            "description": "Source of the charge"
          }
        }
      },
      "CustomerPaymentDetails": {
        "type": "object",
        "properties": {
          "cid": {
            "type": "integer",
            "description": "Customer ID"
          },
          "paymethod": {
            "type": "string",
            "description": "Customer's payment method one of - Invoice,Credit Card,Direct Debit - Direct Debit or Credit Card indicate the customer is on automated payments"
          },
          "balance": {
            "type": "number",
            "description": "Current Balance"
          },
          "cc_number": {
            "type": "string",
            "description": "Masked Card Number ( If Available )"
          },
          "cc_name": {
            "type": "string",
            "description": "Name on the card ( If Available )"
          },
          "cc_expmonth": {
            "type": "string",
            "description": "2 digit expiry month ( If Available )"
          },
          "cc_expyear": {
            "type": "number",
            "description": "2 digit year expiry ( If Available )"
          },
          "bank_name": {
            "type": "string",
            "description": "Bank Account Name ( If Available )"
          },
          "bank_bsb": {
            "type": "string",
            "description": "Bank 6 digit BSB code ( If Available )"
          },
          "bank_number": {
            "type": "number",
            "description": "Bank Account Number ( If Available )"
          }
        }
      },
      "CustomerPaymentDetailsResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "customer": {
            "$ref": "#/components/schemas/CustomerPaymentDetails"
          }
        }
      },
      "CustomerBalanceResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "cid": {
            "type": "number",
            "description": "Customer ID"
          },
          "balance": {
            "type": "number",
            "description": "Current Balance"
          }
        }
      },
      "ProductListPage": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProductListItem"
            }
          },
          "page_number": {
            "type": "integer",
            "description": "the current page number we are displaying",
            "example": 1
          },
          "total_pages": {
            "type": "integer",
            "description": "the total number of pages available",
            "example": 2
          }
        }
      },
      "ProductListItem": {
        "type": "object",
        "properties": {
          "pid": {
            "type": "integer",
            "example": 1234,
            "description": "The product ID"
          },
          "title": {
            "type": "string",
            "description": "the short description/title for the product",
            "example": "Super Cool Thing"
          },
          "partnumber": {
            "type": "string",
            "description": "The Part Number of the product , like an internal id or code",
            "example": "SUPERCOOL"
          },
          "ex_tax_amount": {
            "type": "number",
            "description": "the decimal value of the item",
            "example": 100
          },
          "category_name": {
            "type": "string",
            "description": "the product category name",
            "example": "Cool Products"
          }
        }
      },
      "ProductItem": {
        "type": "object",
        "properties": {
          "pid": {
            "type": "integer"
          },
          "partnumber": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "ex_tax_amount": {
            "type": "number"
          },
          "inc_tax_amount": {
            "type": "number"
          },
          "cost": {
            "type": "number"
          },
          "vid": {
            "type": "integer"
          },
          "vpartnumber": {
            "type": "string"
          },
          "taxrate": {
            "type": "number"
          },
          "catid": {
            "type": "integer"
          },
          "manufacturer": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "title": {
            "type": "string"
          }
        }
      },
      "ServiceTypeFilterOption": {
        "type": "object",
        "description": "All Items are optional, only use the items required. By default only active service types are returned; filter on `active` explicitly or set `include_inactive` to true to get inactive records as well.",
        "properties": {
          "helpdesk_display": {
            "type": "boolean",
            "description": "whether this service type displays in the helpdesk module"
          },
          "invoice_type": {
            "type": "string",
            "description": "The invoice type that the service type is displaye don"
          },
          "calls_service": {
            "type": "boolean",
            "description": "If this is a call based service"
          },
          "sms_postpaid": {
            "type": "boolean",
            "description": "If this is a sms postpaid service"
          },
          "data_service": {
            "type": "boolean",
            "description": "If this is a data service"
          },
          "data_unlimited": {
            "type": "boolean",
            "description": "Unlimited Data included?"
          },
          "data_included_mb": {
            "type": "integer",
            "description": "Number of MB included in the service, for the filter, this is an exact match and has no ability for > or < or any wilcards"
          },
          "vid": {
            "type": "integer",
            "description": "Vendor or Supplier ID"
          },
          "vendor_product_id": {
            "type": "string",
            "description": "Vendor's Product ID"
          },
          "ratecode": {
            "type": "string",
            "description": "The rate code for types"
          },
          "data_service_technology": {
            "type": "string",
            "description": "What type of data technologies"
          },
          "data_service_type": {
            "type": "string",
            "description": "what data service types are available"
          },
          "allow_order": {
            "type": "boolean",
            "description": "If the service is allowed to be ordered through the orders module"
          },
          "active": {
            "type": "boolean",
            "description": "Filter by active state. Defaults to true (active only) when neither this nor include_inactive is supplied"
          },
          "include_inactive": {
            "type": "boolean",
            "description": "Set to true to return both active and inactive service types (ignored when `active` is supplied)"
          },
          "typeofservice": {
            "type": "string",
            "description": "A wildcard search for type of service"
          }
        }
      },
      "ServiceTypeListPage": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceTypeListItem"
            }
          },
          "page_number": {
            "type": "integer",
            "description": "the current page number we are displaying",
            "example": 1
          },
          "total_pages": {
            "type": "integer",
            "description": "the total number of pages available",
            "example": 2
          }
        }
      },
      "ServiceTypeListItem": {
        "type": "object",
        "properties": {
          "esid": {
            "type": "integer",
            "description": "id of the service type"
          },
          "typeofservice": {
            "type": "string",
            "description": "name of the service type"
          },
          "calls_service": {
            "type": "boolean",
            "description": "if call related service"
          },
          "list_price": {
            "type": "number",
            "description": "ex tax list price",
            "example": 90
          },
          "wholesale_price": {
            "type": "number",
            "description": "ex tax list wholesale price",
            "example": 85
          },
          "reseller_price": {
            "type": "number",
            "description": "ex tax list reseller price",
            "example": 88
          },
          "reporting_category": {
            "type": "string",
            "description": "group or category service belongs to",
            "example": "Business Phone"
          },
          "ratecode": {
            "type": "string",
            "description": "internal rate code",
            "example": "BUSPHONE-STANDARD"
          },
          "cost_price": {
            "type": "number",
            "description": "ex tax cost price",
            "example": 50
          }
        }
      },
      "ServiceType": {
        "type": "object",
        "description": "Detailed service type information",
        "properties": {
          "esid": {
            "type": "integer",
            "description": "ID of service type",
            "example": 123
          },
          "typeofservice": {
            "type": "string",
            "description": "Name of service type",
            "example": "Cool Service"
          },
          "active": {
            "type": "boolean",
            "description": "Whether the service type is active (inactive types are hidden from lists and selectors but remain valid on existing services)",
            "example": true
          },
          "accounting_account": {
            "type": "string",
            "description": "Accounting account number"
          },
          "calls_service": {
            "type": "integer",
            "description": "Whether to include call charges (0 or 1)",
            "enum": [
              0,
              1
            ]
          },
          "usage_script": {
            "type": "integer",
            "description": "Whether to use an inbuilt usage script to define monthly charges"
          },
          "data_service": {
            "type": "integer",
            "description": "Is this a data service (0 or 1)",
            "enum": [
              0,
              1
            ]
          },
          "sms_postpaid": {
            "type": "integer",
            "description": "Is this a sms postpaid service (0 or 1)",
            "enum": [
              0,
              1
            ]
          },
          "invoice_type": {
            "type": "string",
            "description": "The invoice type that this is to be billed on",
            "example": "Phone"
          },
          "helpdesk_display": {
            "type": "integer",
            "description": "Does this record display in the helpdesk module (0 or 1)",
            "enum": [
              0,
              1
            ]
          },
          "list_price": {
            "type": "number",
            "description": "Default ex tax price",
            "example": 150.0
          },
          "wholesale_price": {
            "type": "number",
            "description": "Default wholesale price for this service",
            "example": 10.0
          },
          "reseller_price": {
            "type": "number",
            "description": "Default reseller price",
            "example": 12.5
          },
          "config_generator_script": {
            "type": "string",
            "description": "Location of a config generation script for integration with devices and third party solutions",
            "example": "none"
          },
          "call_types": {
            "type": "string",
            "description": "List of potential call types that this service can bill"
          },
          "source_locations": {
            "type": "string",
            "description": "Only rate calls from these CDR sources"
          },
          "invoice_generation_script": {
            "type": "string",
            "description": "Custom invoice generation script"
          },
          "additional_fields": {
            "type": "string",
            "description": "Additional custom fields in JSON format",
            "example": "[]"
          },
          "additional_fields_type": {
            "type": "string",
            "description": "Type of additional fields",
            "example": "structuredjson"
          },
          "date_created": {
            "type": "string",
            "format": "date-time",
            "description": "Date created",
            "example": "2020-01-08 01:22:00"
          },
          "date_modified": {
            "type": "string",
            "format": "date-time",
            "description": "Date modified",
            "example": "2020-09-07 03:38:57"
          },
          "user_created": {
            "type": "integer",
            "description": "User ID who created this record"
          },
          "user_modified": {
            "type": "integer",
            "description": "User ID who last modified this record"
          },
          "reporting_category": {
            "type": "string",
            "description": "Type of services to group this with for reporting purposes"
          },
          "ctgid": {
            "type": "integer",
            "description": "Default call rate to use for this service (0 for no match)",
            "example": 0
          },
          "ratecode": {
            "type": "string",
            "description": "An internal rate code to use",
            "nullable": true
          },
          "default_call_types": {
            "type": "array",
            "description": "List of common call types that this service can bill",
            "items": {
              "type": "integer"
            }
          },
          "cost_price": {
            "type": "number",
            "description": "What this service's default cost price is",
            "example": 5.0
          }
        }
      },
      "ServiceTypeGetResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the request was successful"
          },
          "serviceType": {
            "$ref": "#/components/schemas/ServiceType"
          }
        }
      },
      "ServiceTypeCreateRequest": {
        "type": "object",
        "required": [
          "typeofservice"
        ],
        "description": "Request body for creating a new service type",
        "properties": {
          "typeofservice": {
            "type": "string",
            "description": "Name of the service type (required)",
            "example": "Business Phone Line"
          },
          "active": {
            "type": "boolean",
            "description": "Whether the service type is active and offered in lists/selectors (defaults to true)",
            "example": true
          },
          "ratecode": {
            "type": "string",
            "description": "Internal rate code",
            "example": "BUS-PHONE-STD"
          },
          "list_price": {
            "type": "number",
            "description": "Default ex-tax list price",
            "example": 49.95
          },
          "cost_price": {
            "type": "number",
            "description": "Ex-tax cost price",
            "example": 25.0
          },
          "wholesale_price": {
            "type": "number",
            "description": "Wholesale price for resellers",
            "example": 35.0
          },
          "reseller_price": {
            "type": "number",
            "description": "Reseller price",
            "example": 40.0
          },
          "invoice_type": {
            "type": "string",
            "description": "Invoice type this service belongs to",
            "example": "Phone"
          },
          "calls_service": {
            "type": "integer",
            "description": "Whether this is a call-based service (0 or 1)",
            "enum": [
              0,
              1
            ],
            "example": 1
          },
          "data_service": {
            "type": "integer",
            "description": "Whether this is a data service (0 or 1)",
            "enum": [
              0,
              1
            ],
            "example": 0
          },
          "data_unlimited": {
            "type": "integer",
            "description": "Whether data is unlimited (0 or 1)",
            "enum": [
              0,
              1
            ],
            "example": 0
          },
          "data_included_mb": {
            "type": "integer",
            "description": "Included data in MB",
            "example": 50000
          },
          "helpdesk_display": {
            "type": "integer",
            "description": "Display in helpdesk module (0 or 1)",
            "enum": [
              0,
              1
            ],
            "example": 1
          },
          "reporting_category": {
            "type": "string",
            "description": "Category for reporting purposes",
            "example": "Business Services"
          },
          "vid": {
            "type": "integer",
            "description": "Vendor/Supplier ID",
            "example": 5
          },
          "vendor_product_id": {
            "type": "string",
            "description": "Vendor's product identifier",
            "example": "VENDOR-PROD-001"
          },
          "allow_order": {
            "type": "integer",
            "description": "Allow ordering through Orders module (0 or 1)",
            "enum": [
              0,
              1
            ],
            "example": 1
          },
          "call_types": {
            "type": "array",
            "description": "Array of call type IDs allowed for this service",
            "items": {
              "type": "integer"
            }
          },
          "default_call_types": {
            "type": "array",
            "description": "Array of default call type IDs for billing",
            "items": {
              "type": "integer"
            }
          }
        }
      },
      "ServiceTypeUpdateRequest": {
        "type": "object",
        "description": "Request body for updating a service type. All fields are optional.",
        "properties": {
          "typeofservice": {
            "type": "string",
            "description": "Name of the service type",
            "example": "Business Phone Line"
          },
          "active": {
            "type": "boolean",
            "description": "Whether the service type is active and offered in lists/selectors",
            "example": true
          },
          "ratecode": {
            "type": "string",
            "description": "Internal rate code",
            "example": "BUS-PHONE-STD"
          },
          "list_price": {
            "type": "number",
            "description": "Default ex-tax list price",
            "example": 49.95
          },
          "cost_price": {
            "type": "number",
            "description": "Ex-tax cost price",
            "example": 25.0
          },
          "wholesale_price": {
            "type": "number",
            "description": "Wholesale price for resellers",
            "example": 35.0
          },
          "reseller_price": {
            "type": "number",
            "description": "Reseller price",
            "example": 40.0
          },
          "invoice_type": {
            "type": "string",
            "description": "Invoice type this service belongs to",
            "example": "Phone"
          },
          "calls_service": {
            "type": "integer",
            "description": "Whether this is a call-based service (0 or 1)",
            "enum": [
              0,
              1
            ]
          },
          "data_service": {
            "type": "integer",
            "description": "Whether this is a data service (0 or 1)",
            "enum": [
              0,
              1
            ]
          },
          "data_unlimited": {
            "type": "integer",
            "description": "Whether data is unlimited (0 or 1)",
            "enum": [
              0,
              1
            ]
          },
          "data_included_mb": {
            "type": "integer",
            "description": "Included data in MB"
          },
          "helpdesk_display": {
            "type": "integer",
            "description": "Display in helpdesk module (0 or 1)",
            "enum": [
              0,
              1
            ]
          },
          "reporting_category": {
            "type": "string",
            "description": "Category for reporting purposes"
          },
          "vid": {
            "type": "integer",
            "description": "Vendor/Supplier ID"
          },
          "vendor_product_id": {
            "type": "string",
            "description": "Vendor's product identifier"
          },
          "allow_order": {
            "type": "integer",
            "description": "Allow ordering through Orders module (0 or 1)",
            "enum": [
              0,
              1
            ]
          },
          "call_types": {
            "type": "array",
            "description": "Array of call type IDs allowed for this service",
            "items": {
              "type": "integer"
            }
          },
          "default_call_types": {
            "type": "array",
            "description": "Array of default call type IDs for billing",
            "items": {
              "type": "integer"
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": false
          },
          "description": {
            "type": "string",
            "description": "Error message describing what went wrong",
            "example": "An error occurred"
          }
        }
      },
      "InvoiceListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the request was successful"
          },
          "invoices": {
            "type": "object",
            "description": "Invoice list keyed by invoice ID",
            "additionalProperties": {
              "$ref": "#/components/schemas/Invoice"
            }
          }
        }
      },
      "InvoiceGetResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "invoice": {
            "$ref": "#/components/schemas/Invoice"
          }
        }
      },
      "InvoicePaginatedResponse": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "Type": {
                  "type": "string"
                },
                "Company": {
                  "type": "string"
                },
                "Date": {
                  "type": "string"
                },
                "Due Date": {
                  "type": "string"
                },
                "Status": {
                  "type": "string"
                },
                "Reconciled": {
                  "type": "string"
                },
                "Amount": {
                  "type": "string"
                }
              }
            }
          },
          "page_number": {
            "type": "integer"
          },
          "total_pages": {
            "type": "integer"
          }
        }
      },
      "Invoice": {
        "type": "object",
        "properties": {
          "iid": {
            "type": "string",
            "description": "Invoice ID"
          },
          "uid": {
            "type": "string",
            "description": "User ID"
          },
          "cid": {
            "type": "string",
            "description": "Customer ID"
          },
          "company": {
            "type": "string",
            "description": "Company name"
          },
          "terms": {
            "type": "string",
            "description": "Payment terms (days)"
          },
          "date": {
            "type": "string",
            "format": "date-time",
            "description": "Invoice date"
          },
          "duedate": {
            "type": "string",
            "format": "date",
            "description": "Due date"
          },
          "invoice_type": {
            "type": "string",
            "description": "Type of invoice"
          },
          "total": {
            "type": "string",
            "description": "Ex-tax total"
          },
          "tax_total": {
            "type": "string",
            "description": "Tax amount"
          },
          "balance": {
            "type": "string",
            "description": "Outstanding balance"
          },
          "paid": {
            "type": "string",
            "description": "Paid status (0 or 1)"
          },
          "void": {
            "type": "string",
            "description": "Void status (0 or 1)"
          },
          "bad_debt": {
            "type": "string",
            "description": "Bad debt date (if applicable)"
          },
          "payments": {
            "type": "array",
            "description": "Payment transactions",
            "items": {
              "type": "object",
              "properties": {
                "payid": {
                  "type": "integer"
                },
                "date": {
                  "type": "string"
                },
                "amount": {
                  "type": "string"
                },
                "type": {
                  "type": "string"
                },
                "full_total": {
                  "type": "string"
                }
              }
            }
          },
          "items": {
            "type": "array",
            "description": "Invoice line items",
            "items": {
              "type": "object"
            }
          },
          "engineering_items": {
            "type": "array",
            "description": "Engineering/service items",
            "items": {
              "type": "object"
            }
          }
        }
      },
      "ContactListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "contacts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContactItem"
            }
          }
        }
      },
      "ContactSingleResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "contact": {
            "$ref": "#/components/schemas/ContactItem"
          }
        }
      },
      "ContactItem": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "integer"
          },
          "cid": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "surname": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "mobile": {
            "type": "string"
          },
          "position": {
            "type": "string"
          },
          "people_type": {
            "type": "string",
            "description": "Contact type from people_related.people_type. Known values: technical, accounts, site, authorised. Multiple values may be stored together using the legacy '^,^' delimiter (e.g. 'technical^,^accounts'). On create/update this field is optional; when provided it is persisted on the customer/contact relationship.",
            "example": "accounts"
          }
        }
      },
      "CreditManagementResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "cid": {
            "type": "integer",
            "description": "Customer ID"
          },
          "credit_management": {
            "type": "integer",
            "description": "Credit management status (0 or 1)",
            "enum": [
              0,
              1
            ]
          }
        }
      },
      "CDRItem": {
        "type": "object",
        "required": [
          "orig_id",
          "startdate",
          "callerid",
          "destination",
          "direction"
        ],
        "properties": {
          "orig_id": {
            "type": "string",
            "description": "Unique ID from your platform/provider",
            "example": "abc1234"
          },
          "startdate": {
            "type": "string",
            "format": "date-time",
            "description": "Call start time",
            "example": "2020-01-12 01:34:34"
          },
          "enddate": {
            "type": "string",
            "format": "date-time",
            "description": "Call end time",
            "example": "2020-01-12 01:34:54"
          },
          "accountcode": {
            "type": "string",
            "description": "Billing account identifier",
            "example": "6113000111222"
          },
          "callerid": {
            "type": "string",
            "description": "Caller ID / A Party",
            "example": "61399997777"
          },
          "did": {
            "type": "string",
            "description": "Inbound phone number (for inbound calls)",
            "example": "611300111222"
          },
          "direction": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound"
            ],
            "description": "Call direction",
            "example": "inbound"
          },
          "destination": {
            "type": "string",
            "description": "Destination number / B Party",
            "example": "61411222333"
          },
          "destination_info": {
            "type": "string",
            "description": "Description of destination",
            "example": "mobile"
          },
          "application": {
            "type": "string",
            "description": "Internal application (Voicemail, IVR, Queue, etc.)",
            "example": "bridge"
          },
          "duration": {
            "type": "integer",
            "description": "Total call duration in seconds",
            "example": 20
          },
          "billsec": {
            "type": "integer",
            "description": "Billable seconds",
            "example": 20
          },
          "cost": {
            "type": "number",
            "format": "float",
            "description": "Cost of the call",
            "example": 0.01
          },
          "disposition": {
            "type": "string",
            "description": "Call status (ANSWERED, NO_ANSWER, BUSY, etc.)",
            "example": "ANSWERED"
          },
          "privacy_flag": {
            "type": "integer",
            "description": "Hide A Party from screens/outputs (0 or 1)",
            "enum": [
              0,
              1
            ]
          }
        }
      },
      "CDRAddResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "yourid": {
            "type": "string",
            "description": "Your orig_id"
          },
          "id": {
            "type": "integer",
            "description": "Internal CDR ID (on success)"
          },
          "description": {
            "type": "string",
            "description": "Error description (on failure)"
          }
        }
      },
      "CDRPriceResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "CDR orig_id"
              },
              "ratecode": {
                "type": "string",
                "description": "Rate code applied"
              },
              "rate_name": {
                "type": "string",
                "description": "Rate name"
              },
              "price": {
                "type": "string",
                "description": "Price charged"
              }
            }
          }
        }
      },
      "CDRMultiplePriceResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "description": "Successfully priced CDRs",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "ratecode": {
                  "type": "string"
                },
                "rate_name": {
                  "type": "string"
                },
                "price": {
                  "type": "string"
                }
              }
            }
          },
          "failures": {
            "type": "array",
            "description": "CDR IDs that could not be priced",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "ReportRequest": {
        "type": "object",
        "required": [
          "report"
        ],
        "properties": {
          "report": {
            "type": "string",
            "description": "Report name (e.g., agedReceivables, invoiceListing, revenueSummary, customerBillingSummary, billedMinutes, newCustomerDetails, endedCustomerDetails, etc.)",
            "example": "agedReceivables"
          },
          "report_options": {
            "type": "object",
            "description": "Report-specific options (varies by report type)",
            "additionalProperties": true,
            "example": {
              "date": "2020-03-29"
            }
          }
        }
      },
      "ReportResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "description": "Report data (structure varies by report type)",
            "items": {
              "type": "object"
            }
          }
        }
      },
      "TimelineItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Timeline entry ID"
          },
          "date": {
            "type": "string",
            "format": "date-time",
            "description": "Entry date/time"
          },
          "title": {
            "type": "string",
            "description": "Entry title"
          },
          "description": {
            "type": "string",
            "description": "Entry description/content"
          },
          "category": {
            "type": "string",
            "description": "Entry category (note, event, etc.)",
            "enum": [
              "note",
              "event"
            ]
          },
          "editable": {
            "type": "boolean",
            "description": "Whether the entry can be edited"
          },
          "table": {
            "type": "string",
            "description": "Source database table"
          }
        }
      },
      "TimelineCreateItem": {
        "type": "object",
        "required": [
          "category",
          "description"
        ],
        "properties": {
          "title": {
            "type": "string",
            "description": "Entry title"
          },
          "category": {
            "type": "string",
            "description": "Entry type",
            "enum": [
              "note",
              "event"
            ]
          },
          "description": {
            "type": "string",
            "description": "Entry content/description"
          },
          "event_date": {
            "type": "string",
            "format": "date-time",
            "description": "Event date (required if category is 'event')"
          },
          "event_type": {
            "type": "string",
            "description": "Event type (required if category is 'event')"
          },
          "id": {
            "type": "integer",
            "description": "Entry ID (for updates)"
          }
        }
      },
      "CustomerServicePricingResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "prices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceTypePriceItem"
            }
          }
        }
      },
      "CustomerServicePricingSingleResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "price": {
            "$ref": "#/components/schemas/ServiceTypePriceItem"
          }
        }
      },
      "ServiceTypePriceItem": {
        "type": "object",
        "properties": {
          "esid": {
            "type": "integer",
            "description": "Service type ID"
          },
          "typeofservice": {
            "type": "string",
            "description": "Service type name"
          },
          "list_price": {
            "type": "number",
            "description": "Price (may be adjusted by price book)"
          },
          "default_price": {
            "type": "boolean",
            "description": "True if using default pricing, false if price book adjusted"
          },
          "ratecode": {
            "type": "string",
            "description": "Rate code"
          }
        }
      },
      "PriceBooksListResponse": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer",
                  "description": "Price book ID"
                },
                "name": {
                  "type": "string",
                  "description": "Price book name"
                }
              }
            }
          },
          "page_number": {
            "type": "integer",
            "description": "Current page number"
          },
          "total_pages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "PriceBookGetResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "priceBook": {
            "$ref": "#/components/schemas/PriceBookItem"
          }
        }
      },
      "PriceBookItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Price book ID"
          },
          "name": {
            "type": "string",
            "description": "Price book name"
          },
          "items": {
            "type": "array",
            "description": "Price book items (services and products)",
            "items": {
              "type": "object",
              "properties": {
                "related_id": {
                  "type": "integer",
                  "description": "ID of the service or product"
                },
                "related_type": {
                  "type": "string",
                  "enum": [
                    "service",
                    "product"
                  ],
                  "description": "Type of item"
                },
                "name": {
                  "type": "string",
                  "description": "Item name"
                },
                "list_price": {
                  "type": "number",
                  "description": "Default/list price"
                },
                "adjustment": {
                  "type": "number",
                  "description": "Adjusted price for this price book"
                },
                "override": {
                  "type": "boolean",
                  "description": "Whether price is overridden"
                }
              }
            }
          }
        }
      },
      "PriceBookSaveItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Price book ID (for updates)"
          },
          "name": {
            "type": "string",
            "description": "Price book name"
          },
          "items": {
            "type": "array",
            "description": "Price book items to add/update",
            "items": {
              "type": "object",
              "required": [
                "related_id",
                "related_type",
                "adjustment"
              ],
              "properties": {
                "related_id": {
                  "type": "integer",
                  "description": "ID of service (esid) or product (pid)"
                },
                "related_type": {
                  "type": "string",
                  "enum": [
                    "service",
                    "product"
                  ],
                  "description": "Type of item"
                },
                "adjustment": {
                  "type": "number",
                  "description": "Price for this item in the price book"
                },
                "override": {
                  "type": "boolean",
                  "description": "Whether to override default price"
                }
              }
            }
          }
        }
      },
      "ServiceGetResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "record": {
            "$ref": "#/components/schemas/ServiceRecord"
          }
        }
      },
      "ServiceRecord": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Service ID (enid)"
          },
          "cid": {
            "type": "integer",
            "description": "Customer ID"
          },
          "service_num": {
            "type": "string",
            "description": "Service number (e.g., phone number, account number)"
          },
          "start_date": {
            "type": "string",
            "format": "date",
            "description": "Service activation date"
          },
          "servicetype": {
            "type": "integer",
            "description": "Service type ID (esid)"
          },
          "monthlyfee": {
            "type": "number",
            "description": "Monthly recurring charge"
          },
          "date_ended": {
            "type": "string",
            "format": "date",
            "description": "Service end/cancellation date"
          },
          "billing_cycle": {
            "type": "string",
            "description": "Billing cycle",
            "enum": [
              "monthly",
              "quarterly",
              "yearly"
            ]
          },
          "contractterm": {
            "type": "integer",
            "description": "Contract term in months"
          },
          "billing_name": {
            "type": "string",
            "description": "Billing name to display on invoices"
          },
          "call_rates_id": {
            "type": "integer",
            "description": "Call rates group ID (ctgid)"
          },
          "bundle_id": {
            "type": "integer",
            "description": "Service bundle ID"
          },
          "cost": {
            "type": "number",
            "description": "Cost price"
          },
          "quantity": {
            "type": "integer",
            "description": "Quantity"
          },
          "parent_id": {
            "type": "integer",
            "description": "Parent service ID (for related services)"
          },
          "nbn_avc": {
            "type": "string",
            "description": "NBN AVC identifier"
          },
          "locid": {
            "type": "string",
            "description": "NBN Location ID (the engineering record's `nbn_loc_id`). Empty if not set."
          },
          "primaryAddress": {
            "type": "string",
            "description": "The service's primary (\"Service\") address as a single full-address string. Empty if no address is set. Set/update it via the full_address field on add/update."
          },
          "site_id": {
            "type": "integer",
            "description": "Service site this service belongs to (engineering.engineering_site_id). Empty/0 if none. See the Service Sites API."
          }
        }
      },
      "ServiceSiteRecord": {
        "type": "object",
        "description": "A customer service site (engineering_sites row).",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Service site ID"
          },
          "cid": {
            "type": "integer",
            "description": "Customer ID"
          },
          "name": {
            "type": "string",
            "description": "Site name"
          },
          "sid": {
            "type": "string",
            "description": "Site reference (DB field sitesid)"
          },
          "domain_name": {
            "type": "string",
            "description": "Site domain (DB field domainname)"
          }
        }
      },
      "ServiceSiteCreateItem": {
        "type": "object",
        "required": [
          "cid",
          "name"
        ],
        "properties": {
          "cid": {
            "type": "integer",
            "description": "Customer ID (must be in the token's department)"
          },
          "name": {
            "type": "string",
            "description": "Site name (must not be blank)"
          },
          "sid": {
            "type": "string",
            "description": "Site reference (DB field sitesid)"
          },
          "domain_name": {
            "type": "string",
            "description": "Site domain (DB field domainname)"
          }
        }
      },
      "ServiceSiteGetResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "record": {
            "$ref": "#/components/schemas/ServiceSiteRecord"
          }
        }
      },
      "ServiceSiteListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "records": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceSiteRecord"
            }
          }
        }
      },
      "ServiceCreateItem": {
        "type": "object",
        "required": [
          "cid",
          "servicetype"
        ],
        "properties": {
          "cid": {
            "type": "integer",
            "description": "Customer ID"
          },
          "service_num": {
            "type": "string",
            "description": "Service number/identifier"
          },
          "start_date": {
            "type": "string",
            "format": "date",
            "description": "Service start date"
          },
          "servicetype": {
            "type": "integer",
            "description": "Service type ID (esid)"
          },
          "monthlyfee": {
            "type": "number",
            "description": "Monthly fee (auto-calculated from price book if not provided)"
          },
          "date_ended": {
            "type": "string",
            "format": "date",
            "description": "Service end date"
          },
          "billing_cycle": {
            "type": "string",
            "description": "Billing cycle"
          },
          "contractterm": {
            "type": "integer",
            "description": "Contract term in months"
          },
          "billing_name": {
            "type": "string",
            "description": "Billing name"
          },
          "call_rates_id": {
            "type": "integer",
            "description": "Call rates ID"
          },
          "bundle_id": {
            "type": "integer",
            "description": "Service bundle ID"
          },
          "cost": {
            "type": "number",
            "description": "Cost price"
          },
          "quantity": {
            "type": "integer",
            "description": "Quantity",
            "default": 1
          },
          "service_information_data": {
            "type": "object",
            "description": "Additional service information (JSON)"
          },
          "nbn_avc": {
            "type": "string",
            "description": "NBN AVC identifier"
          },
          "full_address": {
            "type": "string",
            "description": "The service's primary (\"Service\") address. Provided as a full-address string which is geocoded against Australian addresses and stored. Omit to leave the address unchanged."
          },
          "site_id": {
            "type": "integer",
            "description": "Service site to link this service to. Validated to be a live site of the same customer in the token's department; rejected otherwise. Omit to leave unchanged."
          }
        }
      },
      "ServiceSearchCriteria": {
        "type": "array",
        "description": "A list of search criteria. Each element is a single field/value condition; all conditions are combined with AND. At least one valid criterion is required.",
        "minItems": 1,
        "items": {
          "$ref": "#/components/schemas/ServiceSearchCriterion"
        }
      },
      "ServiceSearchCriterion": {
        "type": "object",
        "description": "A single search condition. Use `field` + `value` (+ optional `operator`) for a normal condition, or the special `active_services` field on its own to restrict results to currently-active services.",
        "required": [
          "field"
        ],
        "properties": {
          "field": {
            "type": "string",
            "description": "The field to filter on. `active_services` is a special flag that takes no value/operator and limits results to services that have not ended (date_ended unset or in the future). Unrecognised fields are silently ignored.",
            "enum": [
              "id",
              "cid",
              "service_num",
              "servicetype",
              "start_date",
              "monthlyfee",
              "date_ended",
              "billing_name",
              "call_rates_id",
              "username",
              "parent_id",
              "quantity",
              "nbn_avc",
              "locid",
              "site_id",
              "ip_ipadd",
              "date_created",
              "date_modified",
              "active_services"
            ]
          },
          "value": {
            "description": "The value to compare against. Required for every field except `active_services`. May be a string or number depending on the field.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "number"
              }
            ]
          },
          "operator": {
            "type": "string",
            "description": "Comparison operator. Defaults to `like` (substring match — the value is wrapped in % wildcards) when omitted. Ignored for `active_services`.",
            "default": "like",
            "enum": [
              "=",
              "like",
              "<",
              ">",
              "<=",
              ">=",
              "!="
            ]
          }
        }
      },
      "ServiceSearchResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "records": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceRecord"
            }
          }
        }
      },
      "ETFCalculationResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "etf_amount": {
            "type": "number",
            "description": "Calculated ETF amount"
          },
          "months_remaining": {
            "type": "integer",
            "description": "Months remaining in contract"
          },
          "monthly_fee": {
            "type": "number",
            "description": "Monthly recurring fee"
          }
        }
      },
      "ETFExecutionResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "description": {
            "type": "string",
            "description": "Result description"
          },
          "etf_amount": {
            "type": "number",
            "description": "ETF amount charged"
          },
          "invoice_item_id": {
            "type": "integer",
            "description": "Created invoice item ID"
          }
        }
      },
      "ServiceBundleGetResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "serviceBundle": {
            "$ref": "#/components/schemas/ServiceBundleItem"
          }
        }
      },
      "ServiceBundleListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "serviceBundles": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceBundleItem"
            }
          }
        }
      },
      "ServiceBundleItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Bundle ID"
          },
          "cid": {
            "type": "integer",
            "description": "Customer ID"
          },
          "name": {
            "type": "string",
            "description": "Bundle name"
          },
          "description": {
            "type": "string",
            "description": "Bundle description"
          },
          "monthly_fee": {
            "type": "number",
            "description": "Total bundle monthly fee"
          },
          "call_types": {
            "type": "array",
            "description": "Included call types",
            "items": {
              "type": "string"
            }
          },
          "charges": {
            "type": "array",
            "description": "Bundle charges/components",
            "items": {
              "type": "object"
            }
          },
          "services": {
            "type": "array",
            "description": "Services included in this bundle",
            "items": {
              "type": "object",
              "properties": {
                "enid": {
                  "type": "integer",
                  "description": "Service ID"
                },
                "service_num": {
                  "type": "string",
                  "description": "Service number"
                },
                "servicetype": {
                  "type": "integer",
                  "description": "Service type ID"
                },
                "billing_name": {
                  "type": "string",
                  "description": "Billing name"
                },
                "date_started": {
                  "type": "string",
                  "format": "date",
                  "description": "Service start date"
                },
                "date_ended": {
                  "type": "string",
                  "format": "date",
                  "description": "Service end date"
                }
              }
            }
          }
        }
      },
      "ExternalSaleItem": {
        "type": "object",
        "description": "External sale data from e-commerce platforms (can be single object or array)",
        "properties": {
          "id": {
            "type": "string",
            "description": "External system sale/order ID"
          },
          "order_number": {
            "type": "string",
            "description": "Order number"
          },
          "cid": {
            "type": "integer",
            "description": "Existing customer ID (if known)"
          },
          "company": {
            "type": "string",
            "description": "Company name (for customer matching/creation)"
          },
          "name": {
            "type": "string",
            "description": "Customer first name"
          },
          "surname": {
            "type": "string",
            "description": "Customer last name"
          },
          "email": {
            "type": "string",
            "description": "Customer email"
          },
          "phone": {
            "type": "string",
            "description": "Customer phone"
          },
          "timestamp": {
            "type": "integer",
            "description": "Unix timestamp of sale"
          },
          "date": {
            "type": "string",
            "format": "date-time",
            "description": "Sale date/time"
          },
          "shipping_address": {
            "type": "object",
            "description": "Shipping address details"
          },
          "billing_address": {
            "type": "object",
            "description": "Billing address details"
          },
          "inc_tax_shipping": {
            "type": "number",
            "description": "Shipping amount including tax"
          },
          "ex_tax_shipping": {
            "type": "number",
            "description": "Shipping amount excluding tax"
          },
          "discount": {
            "type": "number",
            "description": "Discount percentage"
          },
          "products": {
            "type": "array",
            "description": "Array of products/items sold",
            "items": {
              "type": "object",
              "properties": {
                "pid": {
                  "type": "integer",
                  "description": "Product ID"
                },
                "partnumber": {
                  "type": "string",
                  "description": "Product part number"
                },
                "barcode": {
                  "type": "string",
                  "description": "Product barcode"
                },
                "quantity": {
                  "type": "number",
                  "description": "Quantity sold"
                },
                "price": {
                  "type": "number",
                  "description": "Unit price (inc tax)"
                },
                "ex_tax_amount": {
                  "type": "number",
                  "description": "Unit price (ex tax)"
                },
                "name": {
                  "type": "string",
                  "description": "Product name/description"
                }
              }
            }
          },
          "payments": {
            "type": "object",
            "description": "Payment details keyed by payment method",
            "additionalProperties": {
              "type": "number"
            }
          },
          "vouchers": {
            "type": "array",
            "description": "Vouchers applied to sale",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer",
                  "description": "Voucher ID"
                },
                "amount": {
                  "type": "number",
                  "description": "Voucher amount"
                }
              }
            }
          },
          "void": {
            "type": "boolean",
            "description": "Whether sale is void"
          }
        }
      },
      "ExternalSaleResponse": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "description": "Results for each sale processed",
            "items": {
              "type": "object",
              "properties": {
                "success": {
                  "type": "boolean",
                  "description": "Whether sale was processed successfully"
                },
                "cid": {
                  "type": "integer",
                  "description": "Customer ID"
                },
                "iid": {
                  "type": "integer",
                  "description": "Invoice ID created/updated"
                },
                "message": {
                  "type": "string",
                  "description": "Result message"
                },
                "error": {
                  "type": "string",
                  "description": "Error message if failed"
                },
                "paymentResult": {
                  "type": "object",
                  "description": "Payment processing result"
                }
              }
            }
          },
          "processed": {
            "type": "boolean",
            "description": "Whether all sales were processed"
          }
        }
      },
      "GetApiKeyResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether authentication was successful"
          },
          "key": {
            "type": "string",
            "description": "API key (if successful)"
          }
        }
      },
      "CallTypesListResponse": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "ctid": {
                  "type": "integer",
                  "description": "Call type ID"
                },
                "name": {
                  "type": "string",
                  "description": "Call type name"
                },
                "internal_code": {
                  "type": "string",
                  "description": "Internal code/identifier"
                },
                "direction": {
                  "type": "string",
                  "description": "Call direction (inbound/outbound)"
                },
                "priority": {
                  "type": "integer",
                  "description": "Priority level"
                },
                "application": {
                  "type": "string",
                  "description": "Application type"
                }
              }
            }
          },
          "page_number": {
            "type": "integer",
            "description": "Current page number"
          },
          "total_pages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "CallTypeGetResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "callType": {
            "$ref": "#/components/schemas/CallTypeItem"
          }
        }
      },
      "CallTypeItem": {
        "type": "object",
        "properties": {
          "ctid": {
            "type": "integer",
            "description": "Call type ID"
          },
          "name": {
            "type": "string",
            "description": "Call type name"
          },
          "internal_code": {
            "type": "string",
            "description": "Internal code"
          },
          "direction": {
            "type": "string",
            "description": "Call direction"
          },
          "priority": {
            "type": "integer",
            "description": "Priority level"
          },
          "application": {
            "type": "string",
            "description": "Application type"
          },
          "rating_increments": {
            "type": "integer",
            "description": "Rating time increments (seconds)"
          },
          "minimum_call_length": {
            "type": "integer",
            "description": "Minimum billable call length (seconds)"
          },
          "default_rate": {
            "type": "object",
            "description": "Default rate information from default tariff group",
            "properties": {
              "rate": {
                "type": "number",
                "description": "Rate per unit"
              },
              "connection_fee": {
                "type": "number",
                "description": "Connection/flagfall fee"
              }
            }
          }
        }
      },
      "MonthlyCostResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "enid": {
                "type": "integer",
                "description": "Service ID"
              },
              "service_num": {
                "type": "string",
                "description": "Service number"
              },
              "monthlyfee": {
                "type": "number",
                "description": "The actual monthly fee charged on the invoice for this service"
              },
              "ratecode": {
                "type": "string",
                "description": "Service type rate code"
              },
              "service_type": {
                "type": "string",
                "description": "Service type name"
              }
            }
          },
          "description": {
            "type": "string",
            "description": "Error description (only present when success is false)"
          }
        }
      },
      "MonthlyProRataCostResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "enid": {
                "type": "integer",
                "description": "Service ID"
              },
              "service_num": {
                "type": "string",
                "description": "Service number"
              },
              "monthly_prorata_fee": {
                "type": "number",
                "description": "Pro-rata monthly fee calculated from start date to end of month"
              },
              "ratecode": {
                "type": "string",
                "description": "Service type rate code"
              },
              "service_type": {
                "type": "string",
                "description": "Service type name"
              }
            }
          },
          "description": {
            "type": "string",
            "description": "Error description (only present when success is false)"
          }
        }
      },
      "DailyCostResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "properties": {
              "enid": {
                "type": "integer",
                "description": "Service ID"
              },
              "service_num": {
                "type": "string",
                "description": "Service number"
              },
              "dailyfee": {
                "type": "number",
                "description": "Daily fee calculated from monthly fee divided by days in current month"
              },
              "ratecode": {
                "type": "string",
                "description": "Service type rate code"
              },
              "service_type": {
                "type": "string",
                "description": "Service type name"
              }
            }
          },
          "description": {
            "type": "string",
            "description": "Error description (only present when success is false)"
          }
        }
      },
      "ServiceItemCreate": {
        "type": "object",
        "required": [
          "pid"
        ],
        "properties": {
          "pid": {
            "type": "integer",
            "description": "Product ID (required) - references inventory table"
          },
          "enid": {
            "type": "integer",
            "description": "Service ID to associate the item with"
          },
          "charge_date": {
            "type": "string",
            "format": "date",
            "description": "Date the charge should be applied (YYYY-MM-DD)"
          },
          "inc_tax_amount": {
            "type": "number",
            "description": "Amount including tax (if not provided, uses product's default price)"
          },
          "taxrate": {
            "type": "number",
            "description": "Tax rate percentage (if not provided, uses product's tax rate)"
          },
          "description": {
            "type": "string",
            "description": "Charge description (if not provided, uses product's description)"
          }
        }
      },
      "ServiceItemUpdate": {
        "type": "object",
        "properties": {
          "pid": {
            "type": "integer",
            "description": "Product ID - if changed, will recalculate pricing and tax"
          },
          "charge_date": {
            "type": "string",
            "format": "date",
            "description": "Date the charge should be applied (YYYY-MM-DD)"
          },
          "inc_tax_amount": {
            "type": "number",
            "description": "Amount including tax"
          },
          "taxrate": {
            "type": "number",
            "description": "Tax rate percentage"
          },
          "description": {
            "type": "string",
            "description": "Charge description"
          }
        }
      },
      "ServiceItemCreateResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "id": {
            "type": "integer",
            "description": "The created service item ID"
          },
          "description": {
            "type": "string",
            "description": "Error description (only present when success is false)"
          }
        }
      },
      "CallPacksListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "call_packs": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/CallPackItem"
            }
          },
          "description": {
            "type": "string"
          }
        }
      },
      "CallPackItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "cid": {
            "type": "integer"
          },
          "subscription_discount_type_id": {
            "type": "integer"
          },
          "date_started": {
            "type": "string",
            "format": "date"
          },
          "date_ended": {
            "type": "string",
            "format": "date"
          },
          "customer_cost": {
            "type": "number"
          },
          "customer_value": {
            "type": "number"
          }
        }
      },
      "CallPackResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "call_pack_type": {
            "$ref": "#/components/schemas/CallPackItem"
          },
          "description": {
            "type": "string"
          }
        }
      },
      "CallPackCreate": {
        "type": "object",
        "required": [
          "cid",
          "subscription_discount_type_id"
        ],
        "properties": {
          "cid": {
            "type": "integer",
            "description": "Customer ID"
          },
          "subscription_discount_type_id": {
            "type": "integer",
            "description": "Call pack type ID"
          },
          "date_started": {
            "type": "string",
            "format": "date",
            "description": "Start date (defaults to today)"
          },
          "date_ended": {
            "type": "string",
            "format": "date",
            "description": "End date (optional)"
          }
        }
      },
      "CallPackTypesListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "call_pack_types": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/CallPackTypeItem"
            }
          },
          "description": {
            "type": "string"
          }
        }
      },
      "CallPackTypeItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "customer_cost": {
            "type": "number",
            "description": "Monthly cost to customer"
          },
          "customer_value": {
            "type": "number",
            "description": "Value of calls included"
          },
          "rate_id": {
            "type": "integer",
            "description": "Associated rate/tariff group ID"
          }
        }
      },
      "CallPackTypeResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "call_pack_type": {
            "$ref": "#/components/schemas/CallPackTypeItem"
          },
          "description": {
            "type": "string"
          }
        }
      },
      "CallPackTypeCreate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "customer_cost": {
            "type": "number"
          },
          "customer_value": {
            "type": "number"
          },
          "rate_id": {
            "type": "integer"
          }
        }
      },
      "CallPackTypeUpdate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "customer_cost": {
            "type": "number"
          },
          "customer_value": {
            "type": "number"
          },
          "rate_id": {
            "type": "integer"
          }
        }
      },
      "CallRatesListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CallRateGroupItem"
            }
          },
          "total_count": {
            "type": "integer"
          },
          "page_number": {
            "type": "integer"
          },
          "total_pages": {
            "type": "integer"
          }
        }
      },
      "CallRateGroupItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "ctgid": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "billing_increment": {
            "type": "integer",
            "description": "Billing increment in seconds"
          }
        }
      },
      "CallRateGroupResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "callRates": {
            "$ref": "#/components/schemas/CallRateGroupFull"
          }
        }
      },
      "CallRateGroupFull": {
        "type": "object",
        "properties": {
          "ctgid": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "billing_increment": {
            "type": "integer"
          },
          "active": {
            "type": "integer"
          },
          "tags": {
            "type": "string"
          },
          "international_markup_percent": {
            "type": "number"
          },
          "callTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CallTypeRate"
            }
          }
        }
      },
      "CallTypeRate": {
        "type": "object",
        "properties": {
          "ctid": {
            "type": "integer"
          },
          "internal_code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "direction": {
            "type": "string"
          },
          "fixedrate": {
            "type": "number"
          },
          "ratepermin": {
            "type": "number"
          },
          "flagfall": {
            "type": "number"
          },
          "min_cost": {
            "type": "number"
          },
          "max_cost": {
            "type": "number"
          },
          "freeseconds": {
            "type": "integer"
          },
          "min_callpackusage": {
            "type": "number"
          },
          "max_callpackusage": {
            "type": "number"
          }
        }
      },
      "CallRateGroupSave": {
        "type": "object",
        "properties": {
          "ctgid": {
            "type": "integer",
            "description": "Call rate group ID (omit for create)"
          },
          "name": {
            "type": "string"
          },
          "active": {
            "type": "integer"
          },
          "billing_increment": {
            "type": "integer"
          },
          "tags": {
            "type": "string"
          },
          "international_markup_percent": {
            "type": "number"
          },
          "callTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CallTypeRate"
            }
          }
        }
      },
      "HelpdeskTicketsListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HelpdeskTicketItem"
            }
          },
          "total_count": {
            "type": "integer"
          },
          "page_number": {
            "type": "integer"
          },
          "total_pages": {
            "type": "integer"
          }
        }
      },
      "HelpdeskTicketItem": {
        "type": "object",
        "properties": {
          "htid": {
            "type": "integer"
          },
          "cid": {
            "type": "integer"
          },
          "uid": {
            "type": "integer"
          },
          "subject": {
            "type": "string"
          },
          "company": {
            "type": "string"
          },
          "priority": {
            "type": "integer",
            "description": "1=low, 2=medium, 3=high"
          },
          "status": {
            "type": "integer",
            "description": "0=open, 1=closed, 2=void"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "lastupdate": {
            "type": "string",
            "format": "date-time"
          },
          "phone": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "note_count": {
            "type": "integer"
          }
        }
      },
      "HelpdeskSearchRequest": {
        "type": "object",
        "required": [
          "query"
        ],
        "properties": {
          "query": {
            "type": "string",
            "description": "Search term"
          },
          "status": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          }
        }
      },
      "HelpdeskTicketCreate": {
        "type": "object",
        "required": [
          "cid",
          "subject"
        ],
        "properties": {
          "cid": {
            "type": "integer"
          },
          "subject": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "uid": {
            "type": "integer",
            "description": "Assigned user ID"
          },
          "priority": {
            "type": "integer",
            "description": "1=low, 2=medium, 3=high"
          },
          "ostype": {
            "type": "string"
          },
          "internal": {
            "type": "integer",
            "description": "Internal note flag (0 or 1)"
          },
          "contacts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "email": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "HelpdeskTicketCreateResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "description": {
            "type": "string"
          },
          "htid": {
            "type": "integer"
          },
          "ticket": {
            "$ref": "#/components/schemas/HelpdeskTicketFull"
          }
        }
      },
      "HelpdeskTicketResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "ticket": {
            "$ref": "#/components/schemas/HelpdeskTicketFull"
          },
          "customer": {
            "$ref": "#/components/schemas/CustomerBasic"
          },
          "assigned_user": {
            "$ref": "#/components/schemas/UserBasic"
          },
          "notes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HelpdeskNoteItem"
            }
          },
          "attachments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AttachmentItem"
            }
          },
          "contacts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContactBasic"
            }
          }
        }
      },
      "HelpdeskTicketFull": {
        "type": "object",
        "properties": {
          "htid": {
            "type": "integer"
          },
          "cid": {
            "type": "integer"
          },
          "uid": {
            "type": "integer"
          },
          "subject": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "priority": {
            "type": "integer"
          },
          "status": {
            "type": "integer"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "time": {
            "type": "string"
          },
          "company": {
            "type": "string"
          }
        }
      },
      "HelpdeskTicketUpdate": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "string"
          },
          "uid": {
            "type": "integer"
          },
          "priority": {
            "type": "integer"
          },
          "status": {
            "type": "integer"
          },
          "ostype": {
            "type": "string"
          },
          "cid": {
            "type": "integer"
          }
        }
      },
      "HelpdeskNotesResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "htid": {
            "type": "integer"
          },
          "notes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HelpdeskNoteItem"
            }
          }
        }
      },
      "HelpdeskNoteItem": {
        "type": "object",
        "properties": {
          "noteid": {
            "type": "integer"
          },
          "note": {
            "type": "string"
          },
          "notetime": {
            "type": "string",
            "format": "date-time"
          },
          "internal": {
            "type": "integer"
          },
          "user": {
            "$ref": "#/components/schemas/UserBasic"
          }
        }
      },
      "HelpdeskNoteCreate": {
        "type": "object",
        "required": [
          "note"
        ],
        "properties": {
          "note": {
            "type": "string"
          },
          "uid": {
            "type": "integer"
          },
          "internal": {
            "type": "integer",
            "description": "0=customer visible, 1=internal only"
          },
          "ignore_response": {
            "type": "boolean"
          }
        }
      },
      "HelpdeskNoteUpdate": {
        "type": "object",
        "properties": {
          "note": {
            "type": "string"
          },
          "internal": {
            "type": "integer"
          },
          "ignore_response": {
            "type": "boolean"
          }
        }
      },
      "HelpdeskNoteResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "noteid": {
            "type": "integer"
          },
          "note": {
            "$ref": "#/components/schemas/HelpdeskNoteItem"
          }
        }
      },
      "HelpdeskCustomerTicketsResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "customer": {
            "$ref": "#/components/schemas/CustomerBasic"
          },
          "tickets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HelpdeskTicketItem"
            }
          },
          "ticket_count": {
            "type": "integer"
          }
        }
      },
      "OrdersListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrderItem"
            }
          },
          "total_count": {
            "type": "integer"
          },
          "page_number": {
            "type": "integer"
          },
          "total_pages": {
            "type": "integer"
          }
        }
      },
      "OrderResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "order": {
            "$ref": "#/components/schemas/OrderFull"
          }
        }
      },
      "OrderFull": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "cid": {
            "type": "integer"
          },
          "uid": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "vid": {
            "type": "integer"
          },
          "order_type": {
            "type": "string"
          },
          "service_type": {
            "type": "string"
          },
          "date_ordered": {
            "type": "string",
            "format": "date"
          },
          "date_expected": {
            "type": "string",
            "format": "date"
          },
          "notes": {
            "type": "string"
          },
          "workflow_id": {
            "type": "integer"
          },
          "order_data": {
            "type": "object"
          }
        }
      },
      "OrderUpdate": {
        "type": "object",
        "properties": {
          "cid": {
            "type": "integer"
          },
          "uid": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "vid": {
            "type": "integer"
          },
          "order_type": {
            "type": "string"
          },
          "service_type": {
            "type": "string"
          },
          "date_ordered": {
            "type": "string",
            "format": "date"
          },
          "date_expected": {
            "type": "string",
            "format": "date"
          },
          "notes": {
            "type": "string"
          },
          "workflow_id": {
            "type": "integer"
          },
          "order_data": {
            "type": "object"
          }
        }
      },
      "OrderDataUpdate": {
        "type": "object",
        "properties": {
          "workflow_action": {
            "type": "object"
          },
          "order_data": {
            "type": "object"
          }
        }
      },
      "ProductsAllResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "products": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/ProductItem"
            }
          }
        }
      },
      "CustomersAllResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "records": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "cid": {
                  "type": "integer"
                },
                "company": {
                  "type": "string"
                },
                "trading_name": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "surname": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "CustomersListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerBasic"
            }
          },
          "total_count": {
            "type": "integer"
          },
          "page_number": {
            "type": "integer"
          },
          "total_pages": {
            "type": "integer"
          }
        }
      },
      "CustomerResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "customer": {
            "$ref": "#/components/schemas/CustomerFull"
          }
        }
      },
      "CustomerFull": {
        "type": "object",
        "properties": {
          "cid": {
            "type": "integer"
          },
          "deptid": {
            "type": "integer"
          },
          "company": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "surname": {
            "type": "string"
          },
          "dob": {
            "type": "string",
            "format": "date"
          },
          "phone": {
            "type": "string"
          },
          "fax": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "abn": {
            "type": "string"
          },
          "balance": {
            "type": "number"
          },
          "ctgid": {
            "type": "integer"
          },
          "credit_management": {
            "type": "integer"
          },
          "state": {
            "type": "string"
          },
          "primaryAddress": {
            "$ref": "#/components/schemas/AddressObject"
          },
          "billingAddress": {
            "$ref": "#/components/schemas/AddressObject"
          },
          "expected_revenue": {
            "type": "number"
          },
          "minimum_spend": {
            "type": "number"
          },
          "credit_limit": {
            "type": "number"
          },
          "terms": {
            "type": "integer"
          },
          "billinggroup": {
            "type": "string"
          },
          "reseller_cid": {
            "type": "integer"
          },
          "trading_name": {
            "type": "string"
          },
          "agreement_start": {
            "type": "string",
            "format": "date"
          },
          "agreement_end": {
            "type": "string",
            "format": "date"
          },
          "currency": {
            "type": "string"
          },
          "do_not_send_invoice": {
            "type": "integer"
          },
          "comments": {
            "type": "string"
          }
        }
      },
      "CustomerBasic": {
        "type": "object",
        "properties": {
          "cid": {
            "type": "integer"
          },
          "company": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "surname": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          }
        }
      },
      "CustomersSearchResponse": {
        "description": "On success the endpoint returns a bare array of matching customer records. On failure (invalid key, or a search value shorter than 3 characters) it returns an error object instead.",
        "oneOf": [
          {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerSearchRecord"
            }
          },
          {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              },
              "description": {
                "type": "string"
              }
            }
          }
        ]
      },
      "CustomerSearchRecord": {
        "type": "object",
        "properties": {
          "cid": {
            "type": "integer"
          },
          "company": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "surname": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "mobile": {
            "type": "string"
          },
          "credit_management": {
            "type": "integer"
          },
          "dob": {
            "type": "string"
          },
          "abn": {
            "type": "string"
          },
          "ctgid": {
            "type": "integer"
          },
          "paymethod": {
            "type": "string"
          }
        }
      },
      "CustomerServicesResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "services": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceRecord"
            }
          }
        }
      },
      "CustomerStatementResponse": {
        "type": "object",
        "description": "JSON customer statement (returned when format=json). On error, success is false and a description is returned instead of the statement.",
        "properties": {
          "success": {
            "type": "boolean",
            "example": true
          },
          "description": {
            "type": "string",
            "description": "Error message when success is false (e.g. 'invalid key', 'must include cid', 'invalid customer')."
          },
          "cid": {
            "type": "integer"
          },
          "date_from": {
            "type": "string",
            "description": "Resolved window start (defaults applied when omitted).",
            "example": "2024-01-01 00:00"
          },
          "date_to": {
            "type": "string",
            "description": "Resolved window end (defaults applied when omitted).",
            "example": "2024-12-31 23:59"
          },
          "statement": {
            "type": "array",
            "description": "Statement rows in the same chronological/balance order as the PDF.",
            "items": {
              "$ref": "#/components/schemas/CustomerStatementRow"
            }
          }
        }
      },
      "CustomerStatementRow": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Row type: 'Invoice', a payment type (e.g. the gateway public name), or empty for the opening-balance row.",
            "example": "Invoice"
          },
          "iid": {
            "type": "integer",
            "description": "Related invoice id (empty for the opening-balance row)."
          },
          "notes": {
            "type": "string",
            "description": "Line description. May contain presentation HTML (e.g. <br>) — escape before rendering into a web page."
          },
          "amount": {
            "type": "number",
            "description": "Row amount; payments are negative."
          },
          "balance": {
            "type": "number",
            "description": "Running balance after this row."
          },
          "date": {
            "type": "string",
            "example": "2024-03-15 00:00"
          },
          "date_text": {
            "type": "string",
            "example": "15 Mar 2024"
          }
        }
      },
      "CustomerManagementStatusResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "status": {
            "type": "string"
          }
        }
      },
      "CustomerAuthResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "cid": {
            "type": "integer"
          },
          "customer": {
            "$ref": "#/components/schemas/CustomerBasic"
          }
        }
      },
      "ContactCreate": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "surname": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "mobile": {
            "type": "string"
          },
          "position": {
            "type": "string"
          },
          "people_type": {
            "type": "string",
            "description": "Optional contact type to store on the customer/contact relationship (people_related.people_type). Known values: technical, accounts, site, authorised. Multiple values may be supplied using the legacy '^,^' delimiter (e.g. 'technical^,^accounts').",
            "example": "accounts"
          }
        }
      },
      "ContactResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "contact_id": {
            "type": "integer"
          },
          "contact": {
            "$ref": "#/components/schemas/ContactItem"
          }
        }
      },
      "ContactsListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "contacts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContactItem"
            }
          }
        }
      },
      "ContactBasic": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          }
        }
      },
      "CalendarEventsResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CalendarEvent"
            }
          }
        }
      },
      "CalendarEvent": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "start": {
            "type": "string",
            "format": "date-time"
          },
          "end": {
            "type": "string",
            "format": "date-time"
          },
          "address": {
            "type": "string"
          },
          "url": {
            "type": "string"
          }
        }
      },
      "UserBasic": {
        "type": "object",
        "properties": {
          "uid": {
            "type": "integer"
          },
          "username": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "surname": {
            "type": "string"
          },
          "email": {
            "type": "string"
          }
        }
      },
      "AttachmentItem": {
        "type": "object",
        "properties": {
          "rdid": {
            "type": "integer",
            "description": "attacheddoclist record id - the identifier used by the attachment download endpoint"
          },
          "name": {
            "type": "string"
          },
          "filename": {
            "type": "string"
          },
          "dateadded": {
            "type": "string",
            "format": "date-time"
          },
          "download_url": {
            "type": "string",
            "description": "Absolute URL of the attachment download endpoint for this record"
          }
        }
      },
      "HelpdeskAttachmentDownloadResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "htid": {
            "type": "integer"
          },
          "rdid": {
            "type": "integer"
          },
          "name": {
            "type": "string",
            "description": "Original name the file was uploaded under"
          },
          "filename": {
            "type": "string",
            "description": "Stored filename"
          },
          "content_type": {
            "type": "string"
          },
          "size": {
            "type": "integer",
            "description": "Byte length of the decoded file"
          },
          "encoding": {
            "type": "string",
            "example": "base64"
          },
          "content": {
            "type": "string",
            "description": "Base64 encoded file content"
          },
          "description": {
            "type": "string",
            "description": "Error description when success is false"
          }
        }
      },
      "AddressObject": {
        "type": "object",
        "properties": {
          "street": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "postcode": {
            "type": "string"
          },
          "country": {
            "type": "string"
          }
        }
      },
      "IdResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "id": {
            "type": "integer"
          },
          "description": {
            "type": "string"
          }
        }
      },
      "PaymentMethodItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Payment method ID"
          },
          "cid": {
            "type": "integer",
            "description": "Customer ID"
          },
          "payment_gateway": {
            "type": "string",
            "description": "Payment gateway name (e.g., stripe, ezidebit)"
          },
          "type": {
            "type": "string",
            "enum": [
              "bank",
              "card"
            ],
            "description": "Type of payment method"
          },
          "active": {
            "type": "boolean",
            "description": "Whether the payment method is active"
          },
          "primary_method": {
            "type": "boolean",
            "description": "Whether this is the primary payment method"
          },
          "backup_method": {
            "type": "boolean",
            "description": "Whether this is the backup payment method"
          },
          "status": {
            "type": "string",
            "description": "Card status (e.g., Active, Expired)"
          },
          "nick_name": {
            "type": "string",
            "description": "User-defined nickname for the payment method"
          },
          "details": {
            "type": "string",
            "description": "Formatted payment method details"
          },
          "date_created": {
            "type": "string",
            "description": "Date the payment method was created"
          },
          "cc_type": {
            "type": "string",
            "nullable": true,
            "description": "Credit card type (Visa, Mastercard, etc.)"
          },
          "cc_last_four": {
            "type": "string",
            "nullable": true,
            "description": "Last 4 digits of credit card number"
          },
          "cc_name": {
            "type": "string",
            "nullable": true,
            "description": "Name on the credit card"
          },
          "cc_expiry": {
            "type": "string",
            "nullable": true,
            "description": "Credit card expiry (MM/YYYY)"
          },
          "bank_name": {
            "type": "string",
            "nullable": true,
            "description": "Bank name for bank accounts"
          },
          "bank_bsb": {
            "type": "string",
            "nullable": true,
            "description": "BSB number for bank accounts"
          },
          "bank_account_number": {
            "type": "string",
            "nullable": true,
            "description": "Account number for bank accounts"
          }
        }
      },
      "PaymentMethodListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "payment_methods": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentMethodItem"
            }
          },
          "count": {
            "type": "integer",
            "description": "Number of payment methods returned"
          }
        }
      },
      "PaymentMethodSingleResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "payment_method": {
            "$ref": "#/components/schemas/PaymentMethodItem"
          }
        }
      },
      "PaymentMethodFilterRequest": {
        "type": "object",
        "properties": {
          "active": {
            "type": "boolean",
            "description": "Filter by active status"
          },
          "primary_method": {
            "type": "boolean",
            "description": "Filter to only primary payment methods"
          },
          "backup_method": {
            "type": "boolean",
            "description": "Filter to only backup payment methods"
          },
          "type": {
            "type": "string",
            "enum": [
              "bank",
              "card"
            ],
            "description": "Filter by payment method type"
          },
          "payment_gateway": {
            "type": "string",
            "description": "Filter by payment gateway name"
          }
        }
      },
      "PaymentMethodAddRequest": {
        "type": "object",
        "description": "Request to add a new payment method. For credit cards, provide either a token OR full card details. For bank accounts, provide bank details.",
        "properties": {
          "gateway": {
            "type": "string",
            "description": "Optional payment gateway name (payment_gateways.gateway_name) to create and tokenise the payment method against, e.g. \"ezidebit\". Must be a gateway configured for the authenticated department; an unknown, deleted or other-department gateway is rejected. When omitted the department default credit card / direct debit gateway is used based on the payment details provided."
          },
          "payment_token": {
            "type": "string",
            "description": "Payment gateway token (for tokenized card storage)"
          },
          "cc_name": {
            "type": "string",
            "description": "Name on the credit card"
          },
          "cc_number": {
            "type": "string",
            "description": "Credit card number"
          },
          "cc_expiry_month": {
            "type": "string",
            "description": "Card expiry month (MM)"
          },
          "cc_expiry_year": {
            "type": "string",
            "description": "Card expiry year (YYYY)"
          },
          "cc_cvv": {
            "type": "string",
            "description": "Card CVV/security code"
          },
          "bank_account_name": {
            "type": "string",
            "description": "Account holder name"
          },
          "bank_name": {
            "type": "string",
            "description": "Bank name"
          },
          "bank_bsb": {
            "type": "string",
            "description": "BSB number (Australian banks)"
          },
          "bank_account_number": {
            "type": "string",
            "description": "Bank account number"
          },
          "set_primary": {
            "type": "boolean",
            "description": "Set this as the primary payment method"
          },
          "set_backup": {
            "type": "boolean",
            "description": "Set this as the backup payment method"
          },
          "nickname": {
            "type": "string",
            "description": "Nickname for the payment method"
          }
        }
      },
      "PaymentMethodAddResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "description": {
            "type": "string"
          },
          "payment_method_id": {
            "type": "integer",
            "description": "ID of the newly created payment method"
          }
        }
      },
      "PaymentMethodStatusRequest": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "primary",
              "backup",
              "inactive"
            ],
            "description": "New status for the payment method. 'primary' sets as primary and activates, 'backup' sets as backup and activates, 'inactive' deactivates the method."
          }
        }
      },
      "PaymentMethodNicknameRequest": {
        "type": "object",
        "required": [
          "nickname"
        ],
        "properties": {
          "nickname": {
            "type": "string",
            "description": "New nickname for the payment method"
          }
        }
      },
      "ExternalPaymentRequest": {
        "type": "object",
        "required": [
          "amount",
          "transaction_id"
        ],
        "properties": {
          "amount": {
            "type": "number",
            "format": "float",
            "description": "Payment amount (must be between 0.01 and 99,999,999.99)",
            "example": 100.0
          },
          "transaction_id": {
            "type": "string",
            "description": "External transaction reference ID (max 255 characters). Used for refund tracking and duplicate detection.",
            "example": "ch_abc123",
            "maxLength": 255
          },
          "gateway_name": {
            "type": "string",
            "description": "Gateway name for the payment type field (alphanumeric and underscores only). If not specified, uses the department's configured credit card gateway.",
            "example": "stripe"
          },
          "description": {
            "type": "string",
            "description": "Payment description (max 500 characters)",
            "default": "External Payment",
            "example": "Shopify order #1234",
            "maxLength": 500
          },
          "payment_date": {
            "type": "string",
            "format": "date-time",
            "description": "When the payment was processed. Defaults to current time.",
            "example": "2026-02-10 14:30:00"
          },
          "invoice_ids": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Specific invoice IDs to apply payment to. If omitted, payment is auto-distributed across unpaid invoices.",
            "example": [
              1234,
              5678
            ]
          },
          "gateway_data": {
            "type": "object",
            "additionalProperties": true,
            "description": "Flexible object for storing external gateway metadata. Reserved keys (processed, message, transaction_id, external) are stripped automatically.",
            "example": {
              "charge_id": "ch_abc123",
              "platform": "shopify",
              "order_ref": "ORD-9876"
            }
          }
        }
      },
      "ExternalPaymentResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the payment was logged successfully"
          },
          "payment_id": {
            "type": "integer",
            "description": "The ID of the created payment record"
          },
          "description": {
            "type": "string",
            "description": "Status message. Returns 'Payment already recorded (duplicate transaction_id)' if a payment with the same transaction_id already exists.",
            "example": "External payment logged successfully"
          }
        }
      },
      "CdrExportsResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the request was able to process successfully or not"
          },
          "data": {
            "type": "array",
            "description": "One entry per customer with a CDR export configured.",
            "items": {
              "type": "object",
              "properties": {
                "cid": {
                  "type": "integer",
                  "description": "Customer ID"
                },
                "company": {
                  "type": "string",
                  "description": "Customer company name"
                },
                "frequency": {
                  "type": "string",
                  "description": "Configured export frequency (customers.cdr_export_frequency), e.g. 'daily' or 'daily-dynamic'.",
                  "example": "daily"
                },
                "path": {
                  "type": "string",
                  "description": "Export destination directory (customers.cdr_export_dir)."
                },
                "format": {
                  "type": "string",
                  "description": "Configured export format (customers.cdr_export_format)."
                },
                "lastRun": {
                  "type": "string",
                  "nullable": true,
                  "description": "Timestamp of the most recent export run (cdr_exports.date_created), or null if the export has never run.",
                  "example": "2026-07-02 03:00:00"
                },
                "nextRun": {
                  "type": "string",
                  "nullable": true,
                  "description": "Computed timestamp of the next expected export run, or null when it cannot be computed (no prior run, no active services, or inactive customer).",
                  "example": "2026-07-03 03:00:00"
                }
              }
            }
          }
        }
      },
      "BillRunItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Bill run ID",
            "example": 412
          },
          "billrun_template_id": {
            "type": "integer",
            "description": "The bill run template this run belongs to",
            "example": 7
          },
          "start_date": {
            "type": "string",
            "description": "Start of the billing period",
            "example": "2026-03-01 00:00:00"
          },
          "end_date": {
            "type": "string",
            "description": "End of the billing period",
            "example": "2026-03-31 23:59:59"
          },
          "complete": {
            "type": "integer",
            "description": "Whether invoice generation for this run has finished (0 or 1)",
            "example": 1
          },
          "approved": {
            "type": "integer",
            "description": "Whether the run has been approved (0 or 1). Read-only — set via the approve endpoint.",
            "example": 0
          },
          "update_invoice_date_on_approval": {
            "type": "integer",
            "description": "Shift invoice date/due date forward on approval (0 or 1)",
            "example": 0
          },
          "auto_approve_draft_invoice_date": {
            "type": "string",
            "description": "Draft invoices in this run are auto-approved after this date/time. '0000-00-00 00:00:00' when unset.",
            "example": "2026-04-05 09:00:00"
          },
          "mode": {
            "type": "string",
            "description": "Bill run mode",
            "example": "live"
          },
          "date_created": {
            "type": "string",
            "example": "2026-03-01 02:00:11"
          },
          "date_modified": {
            "type": "string",
            "example": "2026-03-01 02:41:52"
          }
        }
      },
      "BillRunWritableItem": {
        "type": "object",
        "description": "The only bill run fields a client may set. Any other field in the body is ignored, except `approved`, which is rejected outright.",
        "properties": {
          "billrun_template_id": {
            "type": "integer",
            "description": "Bill run template ID — must belong to the token's department. Required on create.",
            "example": 7
          },
          "start_date": {
            "type": "string",
            "description": "Start of the billing period. Defaults to now on create.",
            "example": "2026-03-01 00:00:00"
          },
          "end_date": {
            "type": "string",
            "description": "End of the billing period",
            "example": "2026-03-31 23:59:59"
          },
          "complete": {
            "type": "integer",
            "description": "Completed flag (0 or 1)",
            "example": 0
          },
          "update_invoice_date_on_approval": {
            "type": "integer",
            "description": "Shift invoice date/due date forward on approval (0 or 1)",
            "example": 0
          },
          "auto_approve_draft_invoice_date": {
            "type": "string",
            "description": "Auto-approve draft invoices after this date/time. Send an empty string to clear.",
            "example": "2026-04-05 09:00:00"
          }
        }
      },
      "BillRunListResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": true
          },
          "description": {
            "type": "string",
            "description": "Only present on failure",
            "example": "invalid key"
          },
          "records": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillRunItem"
            }
          },
          "total": {
            "type": "integer",
            "description": "Total matching bill runs across all pages",
            "example": 43
          },
          "page": {
            "type": "integer",
            "example": 1
          },
          "limit": {
            "type": "integer",
            "example": 20
          },
          "total_pages": {
            "type": "integer",
            "example": 3
          }
        }
      },
      "BillRunGetResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": true
          },
          "description": {
            "type": "string",
            "description": "Only present on failure",
            "example": "bill run not found"
          },
          "record": {
            "$ref": "#/components/schemas/BillRunItem"
          }
        }
      },
      "BillRunCreateResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": true
          },
          "description": {
            "type": "string",
            "description": "Only present on failure",
            "example": "billrun_template_id is required"
          },
          "id": {
            "type": "integer",
            "description": "The new bill run ID",
            "example": 412
          },
          "record": {
            "$ref": "#/components/schemas/BillRunItem"
          }
        }
      },
      "BillRunUpdateResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": true
          },
          "description": {
            "type": "string",
            "example": "bill run updated"
          },
          "record": {
            "$ref": "#/components/schemas/BillRunItem"
          }
        }
      },
      "BillRunDeleteResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": true
          },
          "description": {
            "type": "string",
            "example": "bill run deleted"
          },
          "id": {
            "type": "integer",
            "description": "The soft-deleted bill run ID",
            "example": 412
          }
        }
      },
      "BillRunApproveRequest": {
        "type": "object",
        "properties": {
          "resend": {
            "type": "boolean",
            "description": "Re-email an already approved bill run without re-authorising its invoices or shifting invoice dates",
            "example": false
          }
        }
      },
      "BillRunApproveResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": true
          },
          "description": {
            "type": "string",
            "example": "bill run approved"
          },
          "billrun_id": {
            "type": "integer",
            "example": 412
          },
          "resend": {
            "type": "boolean",
            "description": "Whether this was a re-email run",
            "example": false
          },
          "already_approved": {
            "type": "boolean",
            "description": "True when the bill run was already approved and nothing was re-authorised",
            "example": false
          },
          "invoice_count": {
            "type": "integer",
            "description": "Non-zero-total invoices considered for authorisation/emailing",
            "example": 128
          },
          "emails_sent": {
            "type": "array",
            "description": "Invoice IDs whose invoice email was dispatched",
            "items": {
              "type": "integer"
            }
          },
          "emails_failed": {
            "type": "array",
            "description": "Invoice IDs that errored while being processed",
            "items": {
              "type": "integer"
            }
          },
          "emails_unsent_flagged": {
            "type": "integer",
            "description": "Authorised invoices with an active service that were not emailed (audit count). Null on a resend.",
            "example": 0
          }
        }
      },
      "BulkEmailFilterRow": {
        "type": "object",
        "properties": {
          "field": {
            "type": "string",
            "description": "Filter key from GET /bulk-email/filters. Unknown keys are ignored."
          },
          "value": {
            "type": "string",
            "description": "Value to match. Blank is ignored except for account_state, where blank means \"Normal\"."
          },
          "join": {
            "type": "string",
            "enum": [
              "AND",
              "OR"
            ],
            "default": "AND",
            "description": "How this row joins to the previous one."
          }
        }
      },
      "BulkEmailCounts": {
        "type": "object",
        "properties": {
          "recipients": {
            "type": "integer",
            "description": "Recipients the campaign was created with, including any later withdrawn by a cancel."
          },
          "sent": {
            "type": "integer"
          },
          "pending": {
            "type": "integer",
            "description": "Not yet attempted."
          },
          "failed": {
            "type": "integer",
            "description": "Attempted at least once and still unsent."
          },
          "cancelled": {
            "type": "integer",
            "description": "Unsent recipients withdrawn by a cancel."
          }
        }
      },
      "BulkEmailCampaignSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "subject": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "pending",
              "sending",
              "completed",
              "cancelled"
            ],
            "description": "queued = ready for the next sender run; pending = scheduled for the future; sending = the sender has started it; completed = the sender finished it; cancelled = ended early with unsent recipients withdrawn."
          },
          "scheduled_at": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "started_at": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "ended_at": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "counts": {
            "$ref": "#/components/schemas/BulkEmailCounts"
          }
        }
      },
      "BulkEmailErrorResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": false
          },
          "error_code": {
            "type": "string",
            "description": "Stable machine-readable failure code."
          },
          "description": {
            "type": "string"
          }
        }
      },
      "BulkEmailFiltersResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "description": {
            "type": "string"
          },
          "fields": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "select",
                    "number",
                    "text"
                  ]
                },
                "options": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "string"
                  },
                  "description": "value => label for select fields; empty object otherwise."
                }
              }
            }
          },
          "joins": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "AND",
                "OR"
              ]
            }
          }
        }
      },
      "BulkEmailPreviewRequest": {
        "type": "object",
        "properties": {
          "filters": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BulkEmailFilterRow"
            },
            "description": "Whitelisted recipient filters. Omit for every active, emailable customer in the key department."
          },
          "customer_ids": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Narrow the filtered set to these customers only. Never widens it: inactive customers, customers without a valid email, and customers in another department are still excluded. An empty array matches nobody."
          },
          "sample_limit": {
            "type": "integer",
            "default": 25,
            "maximum": 1000,
            "description": "Recipients to return in the sample. Clamped to 1000."
          },
          "subject": {
            "type": "string",
            "description": "Supply with content to receive a merge-field render."
          },
          "content": {
            "type": "string",
            "description": "HTML body. Merge fields use {{field}} placeholders, e.g. {{company}}."
          }
        }
      },
      "BulkEmailPreviewResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "description": {
            "type": "string"
          },
          "count": {
            "type": "integer",
            "description": "Full resolved recipient count, not the sample size."
          },
          "sample_limit": {
            "type": "integer"
          },
          "truncated": {
            "type": "boolean"
          },
          "recipients": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "cid": {
                  "type": "integer"
                },
                "company": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "surname": {
                  "type": "string"
                },
                "email": {
                  "type": "string"
                }
              }
            }
          },
          "preview": {
            "type": "object",
            "description": "Only present when both subject and content were supplied.",
            "properties": {
              "cid": {
                "type": "integer",
                "description": "The recipient the render was personalised for."
              },
              "subject": {
                "type": "string"
              },
              "content": {
                "type": "string"
              }
            }
          }
        }
      },
      "BulkEmailCreateRequest": {
        "type": "object",
        "required": [
          "subject",
          "content"
        ],
        "properties": {
          "filters": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BulkEmailFilterRow"
            },
            "description": "Whitelisted recipient filters. Omit for every active, emailable customer in the key department."
          },
          "customer_ids": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Narrow the filtered set to these customers only. Never widens it: inactive customers, customers without a valid email, and customers in another department are still excluded. An empty array matches nobody."
          },
          "subject": {
            "type": "string",
            "description": "Stored raw; the sender HTML-encodes it at delivery time."
          },
          "content": {
            "type": "string",
            "description": "HTML body. Merge fields use {{field}} placeholders."
          },
          "scheduled_at": {
            "type": "string",
            "nullable": true,
            "description": "Optional Australia/Melbourne local date/time (Y-m-d, Y-m-d H:i or Y-m-d H:i:s, with T accepted in place of the space). Defaults to now. May not be more than 90 days ahead."
          },
          "confirm_count": {
            "type": "integer",
            "description": "Optional guard: the recipient count a preview returned. Creation fails with recipient_count_changed if the freshly resolved count differs."
          }
        }
      },
      "BulkEmailCreateResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "description": {
            "type": "string"
          },
          "id": {
            "type": "integer",
            "description": "Campaign id, for the status and cancel endpoints."
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "pending"
            ]
          },
          "recipient_count": {
            "type": "integer"
          },
          "scheduled_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BulkEmailStatusResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "description": {
            "type": "string"
          },
          "id": {
            "type": "integer"
          },
          "subject": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "pending",
              "sending",
              "completed",
              "cancelled"
            ],
            "description": "queued = ready for the next sender run; pending = scheduled for the future; sending = the sender has started it; completed = the sender finished it; cancelled = ended early with unsent recipients withdrawn."
          },
          "scheduled_at": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "started_at": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "ended_at": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "counts": {
            "$ref": "#/components/schemas/BulkEmailCounts"
          }
        }
      },
      "BulkEmailHistoryResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "description": {
            "type": "string"
          },
          "page_number": {
            "type": "integer"
          },
          "page_size": {
            "type": "integer",
            "example": 20
          },
          "total": {
            "type": "integer",
            "description": "Total campaigns in the key department."
          },
          "records": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BulkEmailCampaignSummary"
            }
          }
        }
      },
      "BulkEmailCancelResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "description": {
            "type": "string"
          },
          "id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "example": "cancelled"
          },
          "sent_count": {
            "type": "integer",
            "description": "Recipients already delivered to; these cannot be recalled."
          },
          "cancelled_count": {
            "type": "integer",
            "description": "Unsent recipients withdrawn by this call."
          },
          "recipient_count": {
            "type": "integer"
          },
          "note": {
            "type": "string",
            "description": "Plain-language caveat about recall and the in-flight race."
          }
        }
      }
    }
  }
}
